ASoC: msm: add audio drivers for MSM targets
Add snapshot of audio drivers for MSM targets from msm-4.4 kernel
at the below commit level -
commit c03f0ace8a36 ("msm: ipa: enable suspend pipe for ODU")
(Kernel TIP as on 12-06-2016)
Change-Id: I7f3e057f9ec041ca8032a013a5e0c008536ec995
Signed-off-by: Banajit Goswami <bgoswami@codeaurora.org>
Signed-off-by: Xiaoyu Ye <benyxy@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 66ec9c5..c33b790 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -1,5 +1,66 @@
Qualcomm technologies inc audio devices for ALSA sound SoC
+* msm-pcm
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp"
+
+ - qcom,msm-pcm-dsp-id : device node id
+
+* msm-pcm-low-latency
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp"
+
+ - qcom,msm-pcm-dsp-id : device node id
+
+ Optional properties
+
+ - qcom,msm-pcm-low-latency : Flag indicating whether
+ the device node is of type low latency.
+
+ - qcom,latency-level : Flag indicating whether the device node
+ is of type regular low latency or ultra
+ low latency.
+ regular : regular low latency stream
+ ultra : ultra low latency stream
+ ull-pp : ultra low latency stream with post-processing capability
+
+* msm-pcm-dsp-noirq
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp-noirq";
+
+ Optional properties
+
+ - qcom,msm-pcm-low-latency : Flag indicating whether
+ the device node is of type low latency
+
+ - qcom,latency-level : Flag indicating whether the device node
+ is of type low latency or ultra low latency
+ ultra : ultra low latency stream
+ ull-pp : ultra low latency stream with post-processing capability
+* msm-pcm-routing
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-routing"
+
+* msm-pcm-lpa
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-lpa"
+
+* msm-compr-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-compr-dsp"
+
* msm-compress-dsp
Required properties:
@@ -14,8 +75,2271 @@
8909 purpose.If the ADSP version is anything other than this
we use new ADSP APIs.
+* msm-voip-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-voip-dsp"
+
+* msm-pcm-voice
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-voice"
+ - qcom,destroy-cvd : Flag indicating whether to destroy cvd at
+ the end of call for low memory targets
+ - qcom,vote-bms : Flag indicating whether to vote for BMS during
+ the call start and stop
+
+* msm-voice-host-pcm
+
+Required properties:
+
+ - compatible : "qcom,msm-voice-host-pcm"
+
+* msm-voice-svc
+
+Required properties:
+
+ - compatible : "qcom,msm-voice-svc"
+
+* msm-stub-codec
+
+Required properties:
+
+ - compatible : "qcom,msm-stub-codec"
+
+* msm-hdmi-dba-codec-rx
+
+Required properties:
+
+ - compatible : "qcom,msm-hdmi-dba-codec-rx"
+ - qcom,dba-bridge-chip: String info to indicate which bridge-chip
+ is used for HDMI using DBA.
+
+* msm-dai-fe
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-fe"
+
+* msm-pcm-afe
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-afe"
+
+* msm-pcm-dtmf
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dtmf"
+ - qcom,msm-pcm-dtmf : Enable DTMF driver in Audio. DTMF driver is
+ used for generation and detection of DTMF tones, when user is in
+ active voice call. APR commands are sent from DTMF driver to ADSP.
+
+* msm-dai-stub
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-stub"
+
+[Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-stub-dev"
+ - qcom,msm-dai-stub-dev-id : Stub dai port ID value is from 0 to 3.
+ This enables stub CPU dai in Audio. The stub dai is used when
+ there is no real backend in Audio.
+
+* msm-dai-q6-spdif
+
+Optional properties:
+
+ - compatible : "msm-dai-q6-spdif"
+
+* msm-dai-q6-hdmi
+
+Required properties:
+ - compatible : "msm-dai-q6-hdmi"
+ - qcom,msm-dai-q6-dev-id : The hdmi multi channel port ID.
+ It is passed onto the dsp from the apps to form an audio
+ path to the HDMI device. Currently the only supported value
+ is 8, which indicates the rx path used for audio playback
+ on HDMI device.
+
+* msm-lsm-client
+
+Required properties:
+
+ - compatible : "qcom,msm-lsm-client"
+
+* msm-pcm-loopback
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-loopback"
+
+* msm-dai-q6
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-q6"
+
+Optional properties:
+
+ - qcom,ext-spk-amp-supply : External speaker amplifier power supply.
+ - qcom,ext-spk-amp-gpio : External speaker amplifier enable signal.
+
+[Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-dev"
+ - qcom,msm-dai-q6-dev-id : The slimbus multi channel port ID
+ Value is from 16384 to 16397
+ BT SCO port ID value from 12288 to 12289
+ RT Proxy port ID values from 224 to 225 and 240 to
+ 241
+ FM Rx and TX port ID values from 12292 to 12293
+ incall record Rx and TX port ID values from 32771 to 32772
+ inCall Music Delivery port ID is 32773
+ incall Music 2 Delivery port ID is 32770
+
+* msm-auxpcm
+
+Required properties:
+
+ - compatible : "qcom,msm-auxpcm-dev"
+
+ - qcom,msm-cpudai-auxpcm-mode: mode information. The first value is
+ for 8khz mode, the second is for
+ 16khz
+ 0 - for PCM
+
+ - qcom,msm-cpudai-auxpcm-sync: sync information. The first value is
+ for 8khz mode, the second is for
+ 16khz
+
+ - qcom,msm-cpudai-auxpcm-frame: No.of bytes per frame. The first
+ value is for 8khz mode, the second
+ is for 16khz
+ 5 - 256BPF
+ 4 - 128BPF
+
+ - qcom,msm-cpudai-auxpcm-quant: Type of quantization. The first
+ value is for 8khz mode, the second
+ is for 16khz
+ 2 - Linear quantization
+
+ - qcom,msm-cpudai-auxpcm-num-slots: Number of slots per mode in the
+ msm-cpudai-auxpcm-slot-mapping
+ array.
+ The first value is for 8khz mode, the
+ second is for 16khz. Max number of
+ slots supported by DSP is 4, anything
+ above 4 will be truncated to 4 when
+ sent to DSP.
+
+ - qcom,msm-cpudai-auxpcm-slot-mapping: Array of slot numbers for multi
+ slot scenario. The first array
+ is for 8khz mode, the second is
+ for 16khz. The size of the array
+ is determined by the value in
+ qcom,msm-cpudai-auxpcm-num-slots
+
+ - qcom,msm-cpudai-auxpcm-data: Data field - 0. The first value is
+ for 8khz mode, the second is for
+ 16khz
+
+ - qcom,msm-cpudai-auxpcm-pcm-clk-rate: Clock rate for pcm - 2048000. The
+ first value is for 8khz mode, the
+ second is for 16KHz mode. When clock
+ rate is set to zero, then external
+ clock is assumed.
+
+ - qcom,msm-auxpcm-interface: name of AUXPCM interface "primary"
+ indicates primary AUXPCM interface
+ "secondary" indicates secondary
+ AUXPCM interface
+Optional properties:
+
+- pinctrl-names: Pinctrl state names for each pin
+ group configuration.
+- pinctrl-x: Defines pinctrl state for each pin
+ group
+- qcom,msm-cpudai-afe-clk-ver: Indicates version of AFE clock
+ interface to be used for enabling
+ PCM clock. If not defined, selects
+ default AFE clock interface.
+
+* msm-pcm-hostless
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-hostless"
+
+* msm-ocmem-audio
+
+Required properties:
+
+ - compatible : "qcom,msm-ocmem-audio"
+
+ - qcom,msm_bus,name: Client name
+
+ - qcom,msm_bus,num_cases: Total number of use cases
+
+ - qcom,msm_bus,active_only: Context flag for requests in active
+ or dual (active & sleep) contex
+
+ - qcom,msm_bus,num_paths: Total number of master-slave pairs
+
+ - qcom,msm_bus,vectors: Arrays of unsigned integers
+ representing:
+ master-id, slave-id, arbitrated
+ bandwidth,
+ instantaneous bandwidth
+* wcd9xxx_intc
+
+Required properties:
+
+ - compatible : "qcom,wcd9xxx-irq"
+
+ - interrupt-controller : Mark this device node as an
+ interrupt controller
+
+ - #interrupt-cells : Should be 1
+
+ - interrupt-parent : Parent interrupt controller
+
+ - qcom,gpio-connect Gpio that connects to parent
+ interrupt controller
+
+* audio-ext-clk
+
+Required properties:
+
+ - compatible : "qcom,audio-ref-clk"
+
+ - qcom,audio-ref-clk-gpio : PMIC or APQ gpio that will be
+ requested to enable reference
+ or external clock.
+
+Optional properties:
+
+ - qcom,node_has_rpm_clock: Boolean property used to indicate
+ whether ref. clock can be enabled
+ with a gpio toggle or Kernel clock
+ API call.
+
+ - clock-names: Name of the PMIC clock that needs
+ to be enabled for audio ref clock.
+ This clock is set as parent.
+
+ - clocks: phandle reference to the parent
+ clock.
+
+* audio_slimslave
+
+Required properties:
+
+ - compatible : "qcom,audio-slimslave"
+
+ - elemental-addr: slimbus slave enumeration address.
+
+* msm-cpe-lsm
+
+Required properties:
+
+ - compatible : "qcom,msm-cpe-lsm"
+ - qcom,msm-cpe-lsm-id : lsm afe port ID. CPE lsm driver uses
+ this property to find out the input afe port ID. Currently
+ only supported values are 1 and 3.
+
+* wcd_us_euro_gpio
+
+Required properties:
+
+ - compatible : "qcom,msm-cdc-pinctrl"
+
+* msm-dai-slim
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-slim"
+
+ - elemental-addr: slimbus slave enumeration address.
+
+* wcd_gpio_ctrl
+
+Required properties:
+
+ - compatible : "qcom,msm-cdc-pinctrl"
+
+ - qcom,cdc-rst-n-gpio : TLMM GPIO number
+
+ - pinctrl-names: Pinctrl state names for each pin
+ group configuration.
+ - pinctrl-x: Defines pinctrl state for each pin
+ group.
+* msm_cdc_pinctrl
+
+Required properties:
+
+ - compatible : "qcom,msm-cdc-pinctrl"
+
+ - pinctrl-names: Pinctrl state names for each pin
+ group configuration.
+ - pinctrl-x: Defines pinctrl state for each pin
+ group.
+
+* wcd_dsp_glink
+
+Required properties:
+
+ - compatible : "qcom,wcd-dsp-glink"
+
Example:
+ qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ };
+
+ qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ qcom,msm-pcm-lpa {
+ compatible = "qcom,msm-pcm-lpa";
+ };
+
+ qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
qcom,msm-compress-dsp {
compatible = "qcom,msm-compress-dsp";
};
+
+ qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,destroy-cvd;
+ };
+
+ qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,vote-bms;
+ };
+
+ qcom,msm-voice-host-pcm {
+ compatible = "qcom,msm-voice-host-pcm";
+ };
+
+ qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ qcom,msm-pcm-dtmf {
+ compatible = "qcom,msm-pcm-dtmf";
+ };
+
+ qcom,msm-dai-stub {
+ compatible = "qcom,msm-dai-stub";
+ };
+
+ qcom,msm-dai-q6-spdif {
+ compatible = "qcom,msm-dai-q6-spdif";
+ };
+
+ qcom,msm-dai-q6-hdmi {
+ compatible = "qcom,msm-dai-q6-hdmi";
+ qcom,msm-dai-q6-dev-id = <8>;
+ };
+
+ dai_dp: qcom,msm-dai-q6-dp {
+ compatible = "qcom,msm-dai-q6-hdmi";
+ qcom,msm-dai-q6-dev-id = <24608>;
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ qcom,msm-dai-q6-sb-0-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16384>;
+ };
+
+ qcom,msm-dai-q6-sb-0-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16385>;
+ };
+
+ qcom,msm-dai-q6-sb-1-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16386>;
+ };
+
+ qcom,msm-dai-q6-sb-1-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16387>;
+ };
+
+ qcom,msm-dai-q6-sb-3-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16390>;
+ };
+
+ qcom,msm-dai-q6-sb-3-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16391>;
+ };
+
+ qcom,msm-dai-q6-sb-4-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16392>;
+ };
+
+ qcom,msm-dai-q6-sb-4-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16393>;
+ };
+
+ qcom,msm-dai-q6-sb-5-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16395>;
+ };
+
+ qcom,msm-dai-q6-sb-6-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16396>;
+ };
+
+ qcom,msm-dai-q6-sb-6-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16397>;
+ };
+
+ qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+
+ qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
+
+ qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
+ };
+
+ qcom,msm-pri-auxpcm {
+ qcom,msm-cpudai-auxpcm-mode = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <4>, <4>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1 0 0 0>, <1 3 0 0>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ compatible = "qcom,msm-auxpcm-dev";
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&pri_aux_pcm_active &pri_aux_pcm_din_active>;
+ pinctrl-1 = <&pri_aux_pcm_sleep &pri_aux_pcm_din_sleep>;
+ };
+
+ qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ qcom,msm-ocmem-audio {
+ compatible = "qcom,msm-ocmem-audio";
+ qcom,msm_bus,name = "audio-ocmem";
+ qcom,msm_bus,num_cases = <2>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm_bus,vectors =
+ <11 604 0 0>,
+ <11 604 32505856 325058560>;
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <72 0>;
+ interrupt-names = "cdc-int";
+ };
+
+ clock_audio: audio_ext_clk {
+ compatible = "qcom,audio-ref-clk";
+ qcom,audio-ref-clk-gpios = <&pm8994_gpios 15 0>;
+ clock-names = "osr_clk";
+ clocks = <&clock_rpm clk_div_clk1>;
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ pinctrl-names = "sleep", "active";
+ pinctrl-0 = <&spkr_i2s_clk_sleep>;
+ pinctrl-1 = <&spkr_i2s_clk_active>;
+ };
+
+ audio_slimslave {
+ compatible = "qcom,audio-slimslave";
+ elemental-addr = [ff ff ff ff 17 02];
+ };
+
+ msm_dai_slim {
+ compatible = "qcom,msm_dai_slim";
+ elemental-addr = [ff ff ff fe 17 02];
+ };
+
+ wcd_gpio_ctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_reset_active>;
+ pinctrl-1 = <&cdc_reset_sleep>;
+ };
+
+ msm_cdc_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_reset_active>;
+ pinctrl-1 = <&cdc_reset_sleep>;
+ };
+
+ wcd_dsp_glink {
+ compatible = "qcom,wcd-dsp-glink";
+ };
+
+
+* MSM8916 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8x16-audio-codec"
+- qcom,model : The user-visible name of this sound card.
+- qcom,msm-snd-card-id : This id is used to recognize the sound card number
+- qcom,msm-codec-type : This property is used to recognize the codec type
+ internal or external.
+- qcom,msm-hs-micbias-type : This property is used to recognize the headset
+ micbias type, internal or external.
+- qcom,msm-ext-pa : This property is used to inform machine driver about
+ the connection of external PA over available MI2S interfaces,
+ following values can be given to this property.
+ primary -> Primary MI2S interface
+ secondary -> Secondary MI2S interface
+ tertiary -> Tertiary MI2S interface
+ quaternary -> Quaternary MI2S interface
+- qcom,msm-mclk-freq : This property is used to inform machine driver about
+mclk frequency needs to be configured for internal and external PA.
+- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL
+switch type on target typically the switch type will be normally open or
+normally close, value for this property 0 for normally close and 1 for
+normally open.
+- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND
+switch type on target typically the switch type will be normally open or
+normally close, value for this property 0 for normally close and 1 for
+normally open.
+- qcom,audio-routing : A list of the connections between audio components.
+- pinctrl-names : Pincntrl entries to configure the PDM gpio lines and
+ cross connection switch gpio accordingly
+- pinctrl-0 : This explains the active state of the PDM gpio lines
+- pinctrl-1 : This explains the suspend state of the PDM gpio lines
+- pinctrl-2 : This explains the active state of the cross connection
+ gpio lines
+- pinctrl-3 : This explains the suspend state of the cross connection
+ gpio lines
+- qcom,tapan-mclk-clk-freq : Tapan mclk Freq in Hz.
+- qcom,prim-auxpcm-gpio-clk : GPIO on which Primary AUXPCM clk signal is coming.
+- qcom,prim-auxpcm-gpio-sync : GPIO on which Primary AUXPCM SYNC signal is coming.
+- qcom,prim-auxpcm-gpio-din : GPIO on which Primary AUXPCM DIN signal is coming.
+- qcom,prim-auxpcm-gpio-dout : GPIO on which Primary AUXPCM DOUT signal is coming.
+- qcom,prim-auxpcm-gpio-set : set of GPIO lines used for Primary AUXPCM port
+- qcom,tapan-codec-9302: Indicates that this device node is for WCD9302 audio
+ codec.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+
+Optional Properties:
+- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+
+Example:
+
+ msm_dig_codec: qcom,msm-int-codec {
+ compatible = "qcom,msm_int_core_codec";
+ qcom,dig-cdc-base-addr = <0xc0f0000>;
+ };
+
+ sound {
+ compatible = "qcom,msm8x16-audio-codec";
+ qcom,model = "msm8x16-snd-card";
+ qcom,msm-snd-card-id = <0>;
+ qcom,msm-codec-type = "internal";
+ qcom,msm-ext-pa = <0>;
+ qcom,msm-mclk-freq = <12288000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "internal";
+ qcom,cdc-us-euro-gpios = <&msmgpio 120 0>;
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS Internal2",
+ "AMIC3", "MIC BIAS External";
+ pinctrl-names = "cdc_pdm_lines_act",
+ "cdc_pdm_lines_sus",
+ "cross_conn_det_act",
+ "cross_conn_det_sus";
+ pinctrl-0 = <&cdc_pdm_lines_act>;
+ pinctrl-1 = <&cdc_pdm_lines_sus>;
+ pinctrl-2 = <&cross_conn_det_act>;
+ pinctrl-3 = <&cross_conn_det_sus>;
+ qcom,tapan-mclk-clk-freq = <9600000>;
+ qcom,prim-auxpcm-gpio-clk = <&msm_gpio 63 0>;
+ qcom,prim-auxpcm-gpio-sync = <&msm_gpio 64 0>;
+ qcom,prim-auxpcm-gpio-din = <&msm_gpio 65 0>;
+ qcom,prim-auxpcm-gpio-dout = <&msm_gpio 66 0>;
+ qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+ qcom,tapan-codec-9302;
+ asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe",
+ "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa";
+ asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, <&dai_dp>,
+ <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+ <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-dp.24608",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
+ asoc-codec = <&stub>, <&pm8916_tombak_dig>;
+ asoc-codec-names = "msm-stub-codec.1", "tombak_codec";
+ };
+
+* MSM8974 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8974-audio-taiko"
+- qcom,model : The user-visible name of this sound card.
+- reg : Offset and length of the register region(s) for MI2S/PCM MUX
+- reg-names : Register region name(s) referenced in reg above
+ Required register resource entries are:
+ "lpaif_pri_mode_muxsel": Physical address of MUX to select between
+ Primary PCM and Primary MI2S
+ "lpaif_sec_mode_muxsel": Physical address of MUX to select between
+ Secondary PCM and Secondary MI2S
+ "lpaif_tert_mode_muxsel": Physical address of MUX to select between
+ Primary PCM and Tertiary MI2S
+ "lpaif_quat_mode_muxsel": Physical address of MUX to select between
+ Secondary PCM and Quarternary MI2S
+- qcom,audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source.
+- qcom,cdc-mclk-gpios : GPIO on which mclk signal is coming.
+- qcom,taiko-mclk-clk-freq : Taiko mclk Freq in Hz. currently only 9600000Hz
+ is supported.
+- qcom,prim-auxpcm-gpio-clk : GPIO on which Primary AUXPCM clk signal is coming.
+- qcom,prim-auxpcm-gpio-sync : GPIO on which Primary AUXPCM SYNC signal is coming.
+- qcom,prim-auxpcm-gpio-din : GPIO on which Primary AUXPCM DIN signal is coming.
+- qcom,prim-auxpcm-gpio-dout : GPIO on which Primary AUXPCM DOUT signal is coming.
+- qcom,prim-auxpcm-gpio-set : set of GPIO lines used for Primary AUXPCM port
+ Possible Values:
+ prim-gpio-prim : Primary AUXPCM shares GPIOs with Primary MI2S
+ prim-gpio-tert : Primary AUXPCM shares GPIOs with Tertiary MI2S
+- qcom,sec-auxpcm-gpio-clk : GPIO on which Secondary AUXPCM clk signal is coming.
+- qcom,sec-auxpcm-gpio-sync : GPIO on which Secondary AUXPCM SYNC signal is coming.
+- qcom,sec-auxpcm-gpio-din : GPIO on which Secondary AUXPCM DIN signal is coming.
+- qcom,sec-auxpcm-gpio-dout : GPIO on which Secondary AUXPCM DOUT signal is coming.
+- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
+- qcom,ext-ult-spk-amp-gpio : GPIO for enabling of speaker path amplifier.
+
+- qcom,ext-ult-lo-amp-gpio: GPIO to enable external ultrasound lineout
+ amplifier.
+
+- qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
+- qcom,tapan-codec-9302: Indicates that this device node is for WCD9302 audio
+ codec.
+- qcom,mbhc-bias-internal: Flag to indicate if internal micbias should be used
+ for headset detection.
+- qcom,dock-plug-det-irq: Interrupt line to detect Docking/Undocking of Liquid
+ device
+- qcom,ext-spk-rear-panel-irq: Interrupt line to detect rear panel speakers
+ jack for Dragon Board.
+- qcom,ext-spk-front-panel-irq: Interrupt line to detect front panel speakers
+ jack for Dragon Board.
+- qcom,ext-mic-front-panel-irq: Interrupt line to detect front panel microphone
+ jack for Dragon Board.
+- qcom,mbhc-audio-jack-type : String to indicate the jack type on the hardware.
+ Possible Values:
+ 4-pole-jack : Jack on the hardware is 4-pole.
+ 5-pole-jack : Jack on the hardware is 5-pole.
+ 6-pole-jack : Jack on the hardware is 6-pole.
+
+* APQ8074 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,apq8074-audio-taiko"
+
+Example:
+
+sound {
+ compatible = "qcom,msm8974-audio-taiko";
+ qcom,model = "msm8974-taiko-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "HEADPHONE", "LDO_H",
+ "Ext Spk Bottom Pos", "LINEOUT1",
+ "Ext Spk Bottom Neg", "LINEOUT3",
+ "Ext Spk Top Pos", "LINEOUT2",
+ "Ext Spk Top Neg", "LINEOUT4",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS3 Internal1",
+ "MIC BIAS3 Internal1", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS1 Internal2",
+ "MIC BIAS1 Internal2", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+
+ qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
+ qcom,taiko-mclk-clk-freq = <9600000>;
+ qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
+
+ qcom,hdmi-audio-rx;
+ qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>;
+
+ qcom,ext-mclk-gpio = <&msmgpio 47 0>;
+ qcom,dock-plug-det-irq = <&pm8841_mpps 2 0>;
+ qcom,prim-auxpcm-gpio-clk = <&msmgpio 65 0>;
+ qcom,prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
+ qcom,prim-auxpcm-gpio-din = <&msmgpio 67 0>;
+ qcom,prim-auxpcm-gpio-dout = <&msmgpio 68 0>;
+ qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+ qcom,sec-auxpcm-gpio-clk = <&msmgpio 79 0>;
+ qcom,sec-auxpcm-gpio-sync = <&msmgpio 80 0>;
+ qcom,sec-auxpcm-gpio-din = <&msmgpio 81 0>;
+ qcom,sec-auxpcm-gpio-dout = <&msmgpio 82 0>;
+ qcom,mbhc-audio-jack-type = "4-pole-jack";
+};
+
+* msm-dai-mi2s
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-mi2s"
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-mi2s"
+ - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to
+ transfer data to (WCD9XXX) codec.
+ If slimbus interface is used then "msm-dai-q6"
+ needs to be filled with correct data for
+ slimbus interface.
+ The sections "msm-dai-mi2s" is used by MDM or
+ MSM to use I2S interface with codec.
+ This section is used by CPU driver in ASOC MSM
+ to configure MI2S interface. MSM internally
+ has multiple MI2S namely Primary, Secondary,
+ Tertiary and Quaternary MI2S.
+ They are represented with id 0, 1, 2, 3
+ respectively.
+ The field "qcom,msm-dai-q6-mi2s-dev-id"
+ represents which of the MI2S block is used.
+ These MI2S are connected to I2S interface.
+
+ - qcom,msm-mi2s-rx-lines: Each MI2S interface in MSM has one or more SD
+ lines. These lines are used for data transfer
+ between codec and MSM.
+ This element in indicates which output RX lines
+ are used in the MI2S interface.
+
+ - qcom,msm-mi2s-tx-lines: Each MI2S interface in MSM has one or more SD
+ lines. These lines are used for data transfer
+ between codec and MSM.
+ This element in indicates which input TX lines
+ are used in the MI2S interface.
+
+Optional properties:
+
+- pinctrl-names: Pinctrl state names for each pin group
+ configuration.
+- pinctrl-x: Defines pinctrl state for each pin group
+
+Example:
+
+qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ qcom,msm-dai-q6-mi2s-prim {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <0>;
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&tert_mi2s_active &tert_mi2s_sd0_active>;
+ pinctrl-1 = <&tert_mi2s_sleep &tert_mi2s_sd0_sleep>;
+ };
+};
+
+* msm-adsp-loader
+
+Required properties:
+ - compatible : "qcom,adsp-loader"
+ - qcom,adsp-state:
+ It is possible that some MSM use PIL to load the ADSP image. While
+ other MSM may use SBL to load the ADSP image at boot. Audio APR needs
+ state of ADSP to register and enable APR to be used for sending commands
+ to ADSP. so adsp-state represents the state of ADSP to ADSP loader.
+ Value of 0 indicates ADSP loader needs to use PIL and value of 2 means
+ ADSP image is already loaded by SBL.
+
+Optional properties:
+ - qcom,proc-img-to-load;
+ This property can be used to override default ADSP
+ loading by PIL. Based on string input, different proc is
+ loaded. Right now we are adding option "modem"
+ for 8916 purpose. Default image will be "adsp" which
+ will load LPASS Q6 for other targets as expected.
+ "adsp" option need not be explicitly mentioned in
+ DTSI file, as it is default option.
+
+Example:
+
+qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <2>;
+ qcom,proc-img-to-load = "modem";
+};
+
+* msm-audio-ion
+
+Required properties:
+ - compatible : "qcom,msm-audio-ion"
+
+Optional properties:
+ - qcom,smmu-version:
+ version ID to provide info regarding smmu version
+ used in chipset. If ARM SMMU HW - use id value as 1,
+ If QSMMU HW - use id value as 2.
+
+ - qcom,smmu-enabled:
+ It is possible that some MSM have SMMU in ADSP. While other MSM use
+ no SMMU. Audio lib introduce wrapper for ION APIs. The wrapper needs
+ presence of SMMU in ADSP to handle ION APIs differently.
+ Presence of this property means ADSP has SMMU in it.
+ - iommus:
+ A phandle parsed by smmu driver. Number of entries will vary across
+ targets.
+
+Example:
+
+qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion;
+ qcom,smmu-enabled;
+};
+
+* msm-dai-tdm
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-tdm"
+ - qcom,msm-cpudai-tdm-group-id: ID of the group device. TDM interface
+ supports up to 8 groups:
+ Primary RX: 37120
+ Primary TX: 37121
+ Secondary RX: 37136
+ Secondary TX: 37137
+ Tertiary RX: 37152
+ Tertiary TX: 37153
+ Quaternary RX: 37168
+ Quaternary TX: 37169
+
+ - qcom,msm-cpudai-tdm-group-num-ports: Number of ports in
+ msm-cpudai-tdm-group-port-id array.
+ Max number of ports supported by DSP is 8.
+
+ - qcom,msm-cpudai-tdm-group-port-id: Array of TDM port IDs of the group.
+ The size of the array is determined by
+ the value in msm-cpudai-tdm-group-num-ports.
+ Each group supports up to 8 ports:
+ Primary RX: 36864, 36866, 36868, 36870,
+ 36872, 36874, 36876, 36878
+ Primary TX: 36865, 36867, 36869, 36871,
+ 36873, 36875, 36877, 36879
+ Secondary RX: 36880, 36882, 36884, 36886,
+ 36888, 36890, 36892, 36894
+ Secondary TX: 36881, 36883, 36885, 36887,
+ 36889, 36891, 36893, 36895
+ Tertiary RX: 36896, 36898, 36900, 36902,
+ 36904, 36906, 36908, 36910
+ Tertiary TX: 36897, 36899, 36901, 36903,
+ 36905, 36907, 36909, 36911
+ Quaternary RX: 36912, 36914, 36916, 36918,
+ 36920, 36922, 36924, 36926
+ Quaternary TX: 36913, 36915, 36917, 36919,
+ 36921, 36923, 36925, 36927
+
+ - qcom,msm-cpudai-tdm-clk-rate: Clock rate for tdm - 12288000.
+ When clock rate is set to zero,
+ then external clock is assumed.
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-tdm"
+ - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID.
+
+ - qcom,msm-cpudai-tdm-sync-mode: Synchronization setting.
+ 0 - Short sync bit mode
+ 1 - Long sync mode
+ 2 - Short sync slot mode
+
+ - qcom,msm-cpudai-tdm-sync-src: Synchronization source.
+ 0 - External source
+ 1 - Internal source
+
+ - qcom,msm-cpudai-tdm-data-out: Data out signal to drive with other masters.
+ 0 - Disable
+ 1 - Enable
+
+ - qcom,msm-cpudai-tdm-invert-sync: Invert the sync.
+ 0 - Normal
+ 1 - Invert
+
+ - qcom,msm-cpudai-tdm-data-delay: Number of bit clock to delay data
+ with respect to sync edge.
+ 0 - 0 bit clock cycle
+ 1 - 1 bit clock cycle
+ 2 - 2 bit clock cycle
+
+ - qcom,msm-cpudai-tdm-data-align: Indicate how data is packed
+ within the slot. For example, 32 slot width in case of
+ sample bit width is 24.
+ 0 - MSB
+ 1 - LSB
+
+Optional properties:
+
+ - qcom,msm-cpudai-tdm-header-start-offset: TDM Custom header start offset
+ in bytes from this sub-frame. The bytes is counted from 0.
+ 0 is mapped to the 1st byte in or out of
+ the digital serial data line this sub-frame belong to.
+ Supported value: 0, 4, 8.
+
+ - qcom,msm-cpudai-tdm-header-width: Header width per frame followed.
+ 2 bytes for MOST/TDM case.
+ Supported value: 2.
+
+ - qcom,msm-cpudai-tdm-header-num-frame-repeat: Number of header followed.
+ Supported value: 8.
+
+ - pinctrl-names: Pinctrl state names for each pin group
+ configuration.
+
+ - pinctrl-x: Defines pinctrl state for each pin group.
+
+Example:
+
+ qcom,msm-dai-tdm-quat-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37168>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36912>;
+ qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&quat_tdm_active &quat_tdm_dout_active>;
+ pinctrl-1 = <&quat_tdm_sleep &quat_tdm_dout_sleep>;
+ dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36912>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ qcom,msm-cpudai-tdm-header-start-offset = <0>;
+ qcom,msm-cpudai-tdm-header-width = <2>;
+ qcom,msm-cpudai-tdm-header-num-frame-repeat = <8>;
+ };
+ };
+
+* MSM8996 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8996-asoc-snd-tomtom" for tomtom codec and
+ node is "sound" and "qcom,msm8996-asoc-snd-tasha"
+ for tasha codec and node is "sound-9335"
+- qcom,model : The user-visible name of this sound card.
+- qcom,tomtom-mclk-clk-freq : MCLK frequency value for tomtom codec
+ and node is "sound"
+- qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec
+ and node is "sound-9335"
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,ext-ult-spk-amp-gpio : GPIO to enable ultrasound emitter amp.
+- qcom,mbhc-audio-jack-type : String to indicate the jack type on the hardware.
+ Possible Values:
+ 4-pole-jack : Jack on the hardware is 4-pole.
+ 5-pole-jack : Jack on the hardware is 5-pole.
+ 6-pole-jack : Jack on the hardware is 6-pole.
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- qcom,hph-en1-gpio : GPIO to enable HiFi amplifiers.
+- qcom,hph-en0-gpio : GPIO to enable HiFi audio route to headset.
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+
+Example:
+
+ sound {
+ compatible = "qcom,msm8996-asoc-snd";
+ qcom,model = "msm8996-tomtom-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AIF4 MAD", "MCLK",
+ "ultrasound amp", "LINEOUT1",
+ "ultrasound amp", "LINEOUT3",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+
+ clock-names = "osr_clk";
+ clocks = <&clock_rpm clk_div_clk1>;
+ qcom,mbhc-audio-jack-type = "6-pole-jack";
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, <&cpe3>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2",
+ "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe",
+ "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-cpe-lsm.3";
+ asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, <&dai_mi2s>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, <&afe_pcm_rx>,
+ <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music2_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.2",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
+ "SpkrRight", "SpkrLeft";
+ };
+
+* MSM8952 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8952-audio-codec"
+- qcom,model : The user-visible name of this sound card.
+- reg : Offset and length of the register region(s) for MI2S/PCM MUX
+- reg-names : Register region name(s) referenced in reg above
+ Required register resource entries are:
+ "csr_gp_io_mux_mic_ctl": Physical address of MUX that controls
+ controls LPA IF tertiary, quad, PCM0, Digital Codec
+ and Secondary TLMM mux setting for mic path operation.
+ "csr_gp_io_mux_spkr_ctl": Physical address of MUX that controls
+ IF primary, secondary, Digital Codec and Primary TLMM
+ setting for speaker path operation.
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel": Physical address of MUX
+ that controls the mux between LPA IF Quad and PCM0
+ path to secondary TLMM
+- qcom,msm-hs-micbias-type : This property is used to recognize the headset
+ micbias type, internal or external.
+- qcom,msm-ext-pa : This property is used to inform machine driver about
+ the connection of external PA over available MI2S interfaces,
+ following values can be given to this property.
+ primary -> Primary MI2S interface
+ secondary -> Secondary MI2S interface
+ tertiary -> Tertiary MI2S interface
+ quaternary -> Quaternary MI2S interface
+- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL
+switch type on target typically the switch type will be normally open or
+normally close, value for this property 0 for normally close and 1 for
+normally open.
+- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND
+switch type on target typically the switch type will be normally open or
+normally close, value for this property 0 for normally close and 1 for
+normally open.
+- qcom,audio-routing : A list of the connections between audio components.
+- qcom,msm-gpios : Lists down all the gpio sets that are supported.
+- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets
+mentioned in qcom,msm-gpios.
+- pinctrl-names : The combinations of gpio sets from above that are supported in
+the flavor.
+- pinctrl-# : Pinctrl states as mentioned in pinctrl-names.
+
+Optional properties:
+- qcom,prim-auxpcm-gpio-clk : GPIO on which Primary AUXPCM clk signal is coming.
+- qcom,prim-auxpcm-gpio-sync : GPIO on which Primary AUXPCM SYNC signal is coming.
+- qcom,prim-auxpcm-gpio-din : GPIO on which Primary AUXPCM DIN signal is coming.
+- qcom,prim-auxpcm-gpio-dout : GPIO on which Primary AUXPCM DOUT signal is coming.
+- qcom,prim-auxpcm-gpio-set : set of GPIO lines used for Primary AUXPCM port
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- qcom,msm-micbias1-ext-cap : Boolean. Enable micbias1 external
+capacitor mode.
+- qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external
+capacitor mode.
+- qcom,msm-spk-ext-pa : GPIO which enables external speaker pa.
+
+To Configure External Audio Switch
+- qcom,msm-ext-audio-switch : GPIO which controls external switch that switches
+ audio path between headset and speakers.
+- ext-switch-vdd-supply : Power supply that control external audio switch
+- qcom,ext-switch-vdd-voltage : Minimum and maximum voltage in uV to set for
+ power supply.
+- qcom,ext-switch-vdd-op-mode : Maxmum # of uA current the switch will draw
+ from the power supply.
+Example:
+ qcom,msm-ext-audio-switch = <&msm_gpio 2 0>; - gpio # and active_state
+ ext-switch-vdd-supply = <&pm8950_l13>; - Power Rail
+ qcom,ext-switch-vdd-voltage = <3075000 3075000>; - Min, Max uV voltage
+ qcom,ext-switch-vdd-op-mode = <5000>; - Operational current uA
+ Additional needs to add two additional qcom,audio-routings
+ "HEADPHONE", "VDD_EXT_AUDIO_SWITCH"
+ "SPK_OUT", "VDD_EXT_AUDIO_SWITCH"
+
+- qcom,msm-mclk-freq : This property is used to inform machine driver about
+mclk frequency needs to be configured for internal and external PA.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+- asoc-wsa-codec-names: This property contains list of wsa codec names. The names
+ should comply with the wsa nodes configurations.
+- asoc-wsa-codec-prefixes: This property contains list of wsa codec prefixes.
+- msm-vdd-wsa-switch-supply: WSA codec supply's regulator device tree node.
+- qcom,msm-vdd-wsa-switch-voltage: WSA codec supply's voltage level in mV.
+- qcom,msm-vdd-wsa-switch-current: WSA codec max current level in mA.
+
+Example:
+ sound {
+ compatible = "qcom,msm8952-audio-codec";
+ qcom,model = "msm8952-snd-card";
+ reg = <0xc051000 0x4>,
+ <0xc051004 0x4>,
+ <0xc055000 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel";
+ qcom,msm-ext-pa = "primary";
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "internal";
+ qcom,msm-micbias1-ext-cap;
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS Internal2",
+ "AMIC3", "MIC BIAS External";
+ qcom,msm-gpios =
+ "pri_i2s",
+ "us_eu_gpio";
+ qcom,pinctrl-names =
+ "all_off",
+ "pri_i2s_act",
+ "us_eu_gpio_act",
+ "pri_i2s_us_eu_gpio_act";
+ pinctrl-names =
+ "all_off",
+ "pri_i2s_act",
+ "us_eu_gpio_act",
+ "pri_i2s_us_eu_gpio_act";
+ pinctrl-0 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cross_conn_det_sus>;
+ pinctrl-1 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cross_conn_det_sus>;
+ pinctrl-2 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cross_conn_det_act>;
+ pinctrl-3 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cross_conn_det_act>;
+ qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>;
+ qcom,prim-auxpcm-gpio-clk = <&msm_gpio 63 0>;
+ qcom,prim-auxpcm-gpio-sync = <&msm_gpio 64 0>;
+ qcom,prim-auxpcm-gpio-din = <&msm_gpio 65 0>;
+ qcom,prim-auxpcm-gpio-dout = <&msm_gpio 66 0>;
+ qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+ qcom,tapan-codec-9302;
+ asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe",
+ "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa";
+ asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>,
+ <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+ <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
+ asoc-codec = <&stub>, <&pm8916_tombak_dig>;
+ asoc-codec-names = "msm-stub-codec.1", "tombak_codec";
+ asoc-wsa-codec-names = "wsa881x-i2c-codec.8-000f";
+ asoc-wsa-codec-prefixes = "SpkrMono";
+ };
+
+* MSMFALCON ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msmfalcon-asoc-snd"
+- qcom,model : The user-visible name of this sound card.
+- qcom,msm-hs-micbias-type : This property is used to recognize the headset
+ micbias type, internal or external.
+- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL
+switch type on target typically the switch type will be normally open or
+normally close, value for this property 0 for normally close and 1 for
+normally open.
+- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND
+switch type on target typically the switch type will be normally open or
+normally close, value for this property 0 for normally close and 1 for
+normally open.
+- qcom,audio-routing : A list of the connections between audio components.
+- qcom,msm-gpios : Lists down all the gpio sets that are supported.
+- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets
+mentioned in qcom,msm-gpios.
+- pinctrl-names : The combinations of gpio sets from above that are supported in
+the flavor.
+- pinctrl-# : Pinctrl states as mentioned in pinctrl-names.
+
+Optional properties:
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- qcom,msm-micbias1-ext-cap : Boolean. Enable micbias1 external
+capacitor mode.
+- qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external
+capacitor mode.
+- qcom,msm-spk-ext-pa : GPIO which enables external speaker pa.
+- qcom,msm-mclk-freq : This property is used to inform machine driver about
+mclk frequency needs to be configured for internal and external PA.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+
+Example:
+ sound {
+ compatible = "qcom,msmfalcon-asoc-snd";
+ qcom,model = "msmfalcon-snd-card";
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "internal";
+ qcom,msm-micbias1-ext-cap;
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS Internal2",
+ "AMIC3", "MIC BIAS External";
+ qcom,msm-gpios =
+ "int_pdm",
+ "us_eu_gpio";
+ qcom,pinctrl-names =
+ "all_off",
+ "int_pdm_act",
+ "us_eu_gpio_act",
+ "int_pdm_us_eu_gpio_act";
+ pinctrl-names =
+ "all_off",
+ "int_pdm_act",
+ "us_eu_gpio_act",
+ "int_pdm_us_eu_gpio_act";
+ pinctrl-0 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cross_conn_det_sus>;
+ pinctrl-1 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cross_conn_det_sus>;
+ pinctrl-2 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cross_conn_det_act>;
+ pinctrl-3 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cross_conn_det_act>;
+ qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe",
+ "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa";
+ asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>,
+ <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+ <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
+ "SpkrRight", "SpkrLeft";
+ };
+
+* MSM8952 Slimbus ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8952-audio-slimbus-codec"
+- qcom,model : The user-visible name of this sound card.
+- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets
+mentioned in qcom,msm-gpios. Say we have 2^N combinations for N GPIOs,
+this would list all the 2^N combinations.
+- pinctrl-names : The combinations of gpio sets from above that are supported in
+the flavor. This can be sometimes same as qcom, pinctrl-names i.e with 2^N
+combinations or will have less incase if some combination is not supported.
+- pinctrl-# : Pinctrl states as mentioned in pinctrl-names.
+- reg : Offset and length of the register region(s) for MI2S/PCM MUX
+- reg-names : Register region name(s) referenced in reg above
+ Required register resource entries are:
+ "csr_gp_io_mux_mic_ctl": Physical address of MUX that controls
+ controls LPA IF tertiary, quad, PCM0, Digital Codec
+ and Secondary TLMM mux setting for mic path operation.
+ "csr_gp_io_mux_spkr_ctl": Physical address of MUX that controls
+ IF primary, secondary, Digital Codec and Primary TLMM
+ setting for speaker path operation.
+- qcom,cdc-mclk-gpios : GPIO on which mclk signal is coming.
+- clock-names : clock name defined for external clock.
+- qcom,audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source.
+
+Optional Properties:
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- qcom,cdc-vdd-spkr-gpios : GPIO which controls PA for VDD speaker
+- qcom,headset-jack-type-NC: Set if the headset jack type is NC (Normally Closed)
+- qcom,tomtom-mclk-clk-freq : Tapan mclk Freq in Hz. currently only 9600000Hz
+ is supported.
+- qcom,msm-ext-pa : This property is used to inform machine driver about
+ the connection of external PA over available MI2S interfaces,
+ following values can be given to this property.
+ primary -> Primary MI2S interface
+ secondary -> Secondary MI2S interface
+ tertiary -> Tertiary MI2S interface
+ quaternary -> Quaternary MI2S interface
+- qcom,mi2s-audio-intf: This property is used to inform machine driver
+ if mi2s backend dailink has to be added as part of the sound card dai-links.
+- qcom,auxpcm-audio-intf: This property is used to inform machine driver
+ if auxpcm backend dailink has to be added as part of the sound card dai-links.
+- qcom,msm-mi2s-master: This property is used to inform machine driver
+ if MSM is the clock master of mi2s. 1 means master and 0 means slave. The
+ first entry is primary mi2s; the second entry is secondary mi2s, and so on.
+- reg: This property provides the AUX PCM/MI2S mux select register addresses
+ and size.
+- reg_names: This property provides the name of the AUX PCM/MI2S mux select
+ registers so the machine driver can retrieve the addresses. The order of the
+ names has to match the order of the registers in "reg" property.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+- asoc-wsa-codec-names: This property contains list of wsa codec names. The names
+ should comply with the wsa nodes configurations.
+- asoc-wsa-codec-prefixes: This property contains list of wsa codec prefixes.
+
+Example:
+ sound {
+ compatible = "qcom,msm8952-audio-slim-codec";
+ qcom,model = "msm8952-tomtom-snd-card";
+ reg = <0xc051000 0x4>,
+ <0xc051004 0x4>,
+ <0xc055000 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel";
+ qcom,msm-ext-pa = "primary";
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <0>, <1>, <1>;
+ reg = <0x1711a000 0x4>,
+ <0x1711b000 0x4>,
+ <0x1711c000 0x4>,
+ <0x1711d000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "internal";
+ qcom,msm-micbias1-ext-cap;
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS Internal2",
+ "AMIC3", "MIC BIAS External";
+ qcom,msm-gpios =
+ "slim",
+ "us_eu_gpio";
+ qcom,pinctrl-names =
+ "all_off",
+ "slim_act",
+ "us_eu_gpio_act",
+ "slim_us_eu_gpio_act";
+ pinctrl-names =
+ "all_off",
+ "slim_act",
+ "us_eu_gpio_act",
+ "slim_us_eu_gpio_act";
+ pinctrl-0 = <&cdc_slim_lines_sus &cross_conn_det_sus>;
+ pinctrl-1 = <&cdc_slim_lines_act &cross_conn_det_sus>;
+ pinctrl-2 = <&cdc_slim_lines_sus &cross_conn_det_act>;
+ pinctrl-3 = <&cdc_slim_lines_act &cross_conn_det_act>;
+ qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>;
+ qcom,headset-jack-type-NC;
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC5", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4";
+ asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe",
+ "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa";
+ asoc-cpu = <&dai_hdmi>, <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>, <&sb_0_rx>, <&sb_0_tx>,
+ <&sb_1_rx>, <&sb_1_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, <&bt_sco_rx>,
+ <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, <&afe_pcm_rx>,
+ <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>;
+ asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.0",
+ "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2",
+ "msm-dai-q6-mi2s.3", "msm-dai-q6-dev.16384",
+ "msm-dai-q6-dev.16385", "msm-dai-q6-dev.16386",
+ "msm-dai-q6-dev.16387", "msm-dai-q6-dev.16390",
+ "msm-dai-q6-dev.16391", "msm-dai-q6-dev.16392",
+ "msm-dai-q6-dev.16393", "msm-dai-q6-dev.16395",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ asoc-wsa-codec-names = "wsa881x.20170212";
+ asoc-wsa-codec-prefixes = "SpkrLeft";
+ };
+
+* MDM9607 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,mdm9607-audio-tomtom"
+- qcom,model : The user-visible name of this sound card.
+- qcom,audio-routing : A list of the connections between audio components.
+Each entry is a pair of strings, the first being the connection's sink,
+the second being the connection's source.
+- qcom,tomtom-mclk-clk-freq : Master clock value given to codec. Some WCD9XXX
+codec can run at different mclk values. Mclk value can be 9.6MHz or 12.288MHz.
+- pinctrl-names : pinctrl state names for each pin group configuration.
+- pinctrl-x : defines pinctrl state for each pin group
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+
+Example:
+
+sound {
+ compatible = "qcom,mdm9607-audio-tomtom";
+ qcom,model = "mdm9607-tomtom-i2s-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3";
+
+ qcom,tomtom-mclk-clk-freq = <12288000>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
+ <&loopback>, <&hostless>, <&afe>, <&routing>,
+ <&pcm_dtmf>, <&host_pcm>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-pcm-hostless", "msm-pcm-afe",
+ "msm-pcm-routing", "msm-pcm-dtmf", "msm-voice-host-pcm";
+ asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&dtmf_tx>,
+ <&rx_capture_tx>, <&rx_playback_rx>,
+ <&tx_capture_tx>, <&tx_playback_rx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0",
+ "msm-dai-stub-dev.4", "msm-dai-stub-dev.5",
+ "msm-dai-stub-dev.6", "msm-dai-stub-dev.7",
+ "msm-dai-stub-dev.8", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ };
+
+* MDMCALIFORNIUM ASoC Machine driver
+
+- compatible : "qcom,mdm-audio-tasha" for tasha codec and
+ node is "sound"
+- qcom,model : The user-visible name of this sound card.
+- qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec
+ and node is "sound-9335"
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- qcom,hph-en1-gpio : GPIO to enable HiFi amplifiers.
+- qcom,hph-en0-gpio : GPIO to enable HiFi audio route to headset.
+
+Example:
+
+ sound {
+ compatible = "qcom,mdm-audio-tasha";
+ qcom,model = "mdm-tasha-i2s-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AIF4 MAD", "MCLK",
+ "ultrasound amp", "LINEOUT1",
+ "ultrasound amp", "LINEOUT3",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+
+ qcom,tasha-mclk-clk-freq = <12288000>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
+ <&loopback>, <&hostless>, <&afe>, <&routing>,
+ <&pcm_dtmf>, <&host_pcm>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-pcm-hostless", "msm-pcm-afe",
+ "msm-pcm-routing", "msm-pcm-dtmf", "msm-voice-host-pcm";
+ asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&dtmf_tx>,
+ <&rx_capture_tx>, <&rx_playback_rx>,
+ <&tx_capture_tx>, <&tx_playback_rx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0",
+ "msm-dai-stub-dev.4", "msm-dai-stub-dev.5",
+ "msm-dai-stub-dev.6", "msm-dai-stub-dev.7",
+ "msm-dai-stub-dev.8", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,aux-codec = <&stub_codec>;
+ };
+
+* APQ8096 Automotive ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,apq8096-asoc-snd-auto" for auto codec and
+ node is "sound-auto",
+ "qcom,apq8096-asoc-snd-adp-agave" for adp agave codec and
+ node is "sound-adp-agave",
+ "qcom,apq8096-asoc-snd-adp-mmxf" for adp mmxf codec and
+ node is "sound-adp-mmxf".
+- qcom,model : The user-visible name of this sound card.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+
+Example:
+
+ sound-auto {
+ compatible = "qcom,apq8096-asoc-snd-auto";
+ qcom,model = "apq8096-auto-snd-card";
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&compr>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-compr-dsp";
+ asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
+ <&dai_mi2s>, <&dai_mi2s_quat>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>,
+ <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music2_rx>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>,
+ <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>,
+ <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>,
+ <&dai_tert_tdm_tx_2>, <&dai_tert_tdm_tx_3>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_rx_1>,
+ <&dai_quat_tdm_rx_2>, <&dai_quat_tdm_rx_3>,
+ <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>,
+ <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898",
+ "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902",
+ "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899",
+ "msm-dai-q6-tdm.36901", "msm-dai-q6-tdm.36903",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36914",
+ "msm-dai-q6-tdm.36916", "msm-dai-q6-tdm.36918",
+ "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36915",
+ "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ };
+
+* MSMFALCON ASoC Slimbus Machine driver
+
+Required properties:
+- compatible : "qcom,msmfalcon-asoc-snd-tasha" for tasha codec,
+ "qcom,msmfalcon-asoc-snd-tavil" for tavil codec.
+- qcom,model : The user-visible name of this sound card.
+- qcom,msm-mclk-freq : MCLK frequency value for external codec
+- qcom,msm-gpios : Lists down all the gpio sets that are supported.
+- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets
+mentioned in qcom,msm-gpios. Say we have 2^N combinations for N GPIOs,
+this would list all the 2^N combinations.
+- pinctrl-names : The combinations of gpio sets from above that are supported in
+the flavor. This can be sometimes same as qcom, pinctrl-names i.e with 2^N
+combinations or will have less incase if some combination is not supported.
+- pinctrl-# : Pinctrl states as mentioned in pinctrl-names.
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+
+Example:
+
+ sound-9335 {
+ compatible = "qcom,msmfalcon-asoc-snd-tasha";
+ qcom,model = "msmfalcon-tasha-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AIF4 MAD", "MCLK",
+ "ultrasound amp", "LINEOUT1",
+ "ultrasound amp", "LINEOUT3",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-gpios =
+ "slim",
+ "us_eu_gpio";
+ qcom,pinctrl-names =
+ "all_off",
+ "slim_act",
+ "us_eu_gpio_act",
+ "slim_us_eu_gpio_act";
+ pinctrl-names =
+ "all_off",
+ "slim_act",
+ "us_eu_gpio_act",
+ "slim_us_eu_gpio_act";
+ pinctrl-0 = <&cdc_slim_lines_sus &cross_conn_det_sus>;
+ pinctrl-1 = <&cdc_slim_lines_act &cross_conn_det_sus>;
+ pinctrl-2 = <&cdc_slim_lines_sus &cross_conn_det_act>;
+ pinctrl-3 = <&cdc_slim_lines_act &cross_conn_det_act>;
+ qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp";
+ asoc-cpu = <&dai_hdmi>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>;
+ asoc-cpu-names = "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
+ "SpkrRight", "SpkrLeft";
+ };
+
+* MSM8998 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8998-asoc-snd-tasha" for tasha codec,
+ "qcom,msm8998-asoc-snd-tavil" for tavil codec.
+- qcom,model : The user-visible name of this sound card.
+- qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec
+- qcom,tavil-mclk-clk-freq : MCLK frequency value for tavil codec
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,mbhc-audio-jack-type : String to indicate the jack type on the hardware.
+ Possible Values:
+ 4-pole-jack : Jack on the hardware is 4-pole.
+ 5-pole-jack : Jack on the hardware is 5-pole.
+ 6-pole-jack : Jack on the hardware is 6-pole.
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- qcom,hph-en1-gpio : GPIO to enable HiFi amplifiers.
+- qcom,hph-en0-gpio : GPIO to enable HiFi audio route to headset.
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
+- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
+
+Example:
+
+ sound-9335 {
+ compatible = "qcom,msm8998-asoc-snd";
+ qcom,model = "msm8998-tasha-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AIF4 MAD", "MCLK",
+ "ultrasound amp", "LINEOUT1",
+ "ultrasound amp", "LINEOUT3",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,tasha-mclk-clk-freq = <9600000>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp";
+ asoc-cpu = <&dai_hdmi>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>;
+ asoc-cpu-names = "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
+ "SpkrRight", "SpkrLeft";
+ };
+
+* MSMSTUB ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8998-asoc-snd-stub"
+- qcom,model : The user-visible name of this sound card.
+- qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+Optional properties:
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+
+Example:
+
+ sound_msm:sound-9335 {
+ compatible = "qcom,msm8998-asoc-snd";
+ qcom,model = "msm8998-stub-snd-card";
+
+ qcom,tasha-mclk-clk-freq = <9600000>;
+ asoc-platform = <&pcm0>;
+ asoc-platform-names = "msm-pcm-dsp.0";
+ asoc-cpu = <&sb_0_rx>, <&sb_0_tx>;
+ asoc-cpu-names = "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <0>;
+ };
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 407cf29..f513ed4 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -786,6 +786,7 @@
source "drivers/misc/altera-stapl/Kconfig"
source "drivers/misc/mei/Kconfig"
source "drivers/misc/vmw_vmci/Kconfig"
+source "drivers/misc/qcom/Kconfig"
source "drivers/misc/mic/Kconfig"
source "drivers/misc/genwqe/Kconfig"
source "drivers/misc/echo/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6c2fde7..7ea17ec 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,6 +54,7 @@
obj-$(CONFIG_CXL_BASE) += cxl/
obj-$(CONFIG_PANEL) += panel.o
obj-$(CONFIG_UID_CPUTIME) += uid_cputime.o
+obj-y += qcom/
obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
diff --git a/drivers/misc/qcom/Kconfig b/drivers/misc/qcom/Kconfig
new file mode 100644
index 0000000..9c73960
--- /dev/null
+++ b/drivers/misc/qcom/Kconfig
@@ -0,0 +1,20 @@
+config MSM_QDSP6V2_CODECS
+ bool "Audio QDSP6V2 APR support"
+ depends on MSM_SMD
+ select SND_SOC_QDSP6V2
+ help
+ Enable Audio codecs with APR IPC protocol support between
+ application processor and QDSP6 for B-family. APR is
+ used by audio driver to configure QDSP6's
+ ASM, ADM and AFE.
+
+config MSM_ULTRASOUND
+ bool "QDSP6V2 HW Ultrasound support"
+ select SND_SOC_QDSP6V2
+ help
+ Enable HW Ultrasound support in QDSP6V2.
+ QDSP6V2 can support HW encoder & decoder and
+ ultrasound processing. It will enable
+ ultrasound data paths between
+ HW and services, calculating input events
+ upon the ultrasound data.
diff --git a/drivers/misc/qcom/Makefile b/drivers/misc/qcom/Makefile
new file mode 100644
index 0000000..120bddd
--- /dev/null
+++ b/drivers/misc/qcom/Makefile
@@ -0,0 +1 @@
+obj-y += qdsp6v2/
diff --git a/drivers/misc/qcom/qdsp6v2/Makefile b/drivers/misc/qcom/qdsp6v2/Makefile
new file mode 100644
index 0000000..90a123a
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o g711mlaw_in.o g711alaw_in.o audio_utils.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_alac.o audio_ape.o audio_utils_aio.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += q6audio_v2.o q6audio_v2_aio.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_g711mlaw.o audio_g711alaw.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o audio_hwacc_effects.o
+obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
diff --git a/drivers/misc/qcom/qdsp6v2/aac_in.c b/drivers/misc/qcom/qdsp6v2/aac_in.c
new file mode 100644
index 0000000..fb18764
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/aac_in.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_aac.h>
+#include <linux/compat.h>
+#include <linux/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 5 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((1536+sizeof(struct meta_out_dsp)) * 5))
+
+#define AAC_FORMAT_ADTS 65535
+
+static long aac_in_ioctl_shared(struct file *file, unsigned int cmd, void *arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_aac_enc_config *enc_cfg;
+ struct msm_audio_aac_config *aac_config;
+ uint32_t aac_mode = AAC_ENC_MODE_AAC_LC;
+
+ enc_cfg = audio->enc_cfg;
+ aac_config = audio->codec_cfg;
+ /* ENCODE CFG (after new set of API's are published )bharath*/
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ pr_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+
+ if (audio->opened) {
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+ } else {
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ pr_debug("%s: starting in non_tunnel mode",
+ __func__);
+ rc = q6asm_open_read_write(audio->ac,
+ FORMAT_MPEG4_AAC, FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:open read write failed\n",
+ __func__);
+ break;
+ }
+ }
+ if (audio->feedback == TUNNEL_MODE) {
+ pr_debug("%s: starting in tunnel mode",
+ __func__);
+ rc = q6asm_open_read(audio->ac,
+ FORMAT_MPEG4_AAC);
+
+ if (rc < 0) {
+ pr_err("%s:open read failed\n",
+ __func__);
+ break;
+ }
+ }
+ audio->stopped = 0;
+ }
+
+ pr_debug("%s:sbr_ps_flag = %d, sbr_flag = %d\n", __func__,
+ aac_config->sbr_ps_on_flag, aac_config->sbr_on_flag);
+ if (aac_config->sbr_ps_on_flag)
+ aac_mode = AAC_ENC_MODE_EAAC_P;
+ else if (aac_config->sbr_on_flag)
+ aac_mode = AAC_ENC_MODE_AAC_P;
+ else
+ aac_mode = AAC_ENC_MODE_AAC_LC;
+
+ rc = q6asm_enc_cfg_blk_aac(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->sample_rate,
+ enc_cfg->channels,
+ enc_cfg->bit_rate,
+ aac_mode,
+ enc_cfg->stream_format);
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd media format block",
+ "failed\n", __func__, audio->ac->session);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block",
+ "failed\n", __func__, audio->ac->session);
+ break;
+ }
+ }
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure",
+ "failed rc=%d\n", __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac);
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:session id %d: Rxed AUDIO_STOP\n", __func__,
+ audio->ac->session);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed",
+ "rc=%d\n", __func__, audio->ac->session, rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_GET_AAC_ENC_CONFIG: {
+ struct msm_audio_aac_enc_config *cfg;
+ struct msm_audio_aac_enc_config *enc_cfg;
+
+ cfg = (struct msm_audio_aac_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer for %s\n",
+ __func__, "AUDIO_GET_AAC_CONFIG");
+ rc = -EINVAL;
+ break;
+ }
+ memset(cfg, 0, sizeof(*cfg));
+ enc_cfg = audio->enc_cfg;
+ if (enc_cfg->channels == CH_MODE_MONO)
+ cfg->channels = 1;
+ else
+ cfg->channels = 2;
+
+ cfg->sample_rate = enc_cfg->sample_rate;
+ cfg->bit_rate = enc_cfg->bit_rate;
+ switch (enc_cfg->stream_format) {
+ case 0x00:
+ cfg->stream_format = AUDIO_AAC_FORMAT_ADTS;
+ break;
+ case 0x01:
+ cfg->stream_format = AUDIO_AAC_FORMAT_LOAS;
+ break;
+ case 0x02:
+ cfg->stream_format = AUDIO_AAC_FORMAT_ADIF;
+ break;
+ default:
+ case 0x03:
+ cfg->stream_format = AUDIO_AAC_FORMAT_RAW;
+ }
+ pr_debug("%s:session id %d: Get-aac-cfg: format=%d sr=%d",
+ "bitrate=%d\n", __func__, audio->ac->session,
+ cfg->stream_format, cfg->sample_rate, cfg->bit_rate);
+ break;
+ }
+ case AUDIO_SET_AAC_ENC_CONFIG: {
+ struct msm_audio_aac_enc_config *cfg;
+ struct msm_audio_aac_enc_config *enc_cfg;
+ uint32_t min_bitrate, max_bitrate;
+
+ cfg = (struct msm_audio_aac_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer for %s\n",
+ "AUDIO_SET_AAC_ENC_CONFIG", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg = audio->enc_cfg;
+ pr_debug("%s:session id %d: Set-aac-cfg: stream=%d\n", __func__,
+ audio->ac->session, cfg->stream_format);
+
+ switch (cfg->stream_format) {
+ case AUDIO_AAC_FORMAT_ADTS:
+ enc_cfg->stream_format = 0x00;
+ break;
+ case AUDIO_AAC_FORMAT_LOAS:
+ enc_cfg->stream_format = 0x01;
+ break;
+ case AUDIO_AAC_FORMAT_ADIF:
+ enc_cfg->stream_format = 0x02;
+ break;
+ case AUDIO_AAC_FORMAT_RAW:
+ enc_cfg->stream_format = 0x03;
+ break;
+ default:
+ pr_err("%s:session id %d: unsupported AAC format %d\n",
+ __func__, audio->ac->session,
+ cfg->stream_format);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (cfg->channels == 1) {
+ cfg->channels = CH_MODE_MONO;
+ } else if (cfg->channels == 2) {
+ cfg->channels = CH_MODE_STEREO;
+ } else {
+ rc = -EINVAL;
+ break;
+ }
+
+ min_bitrate = ((cfg->sample_rate)*(cfg->channels))/2;
+ /* This calculation should be based on AAC mode. But we cannot
+ * get AAC mode in this setconfig. min_bitrate's logical max
+ * value is 24000. So if min_bitrate is higher than 24000,
+ * choose 24000.
+ */
+ if (min_bitrate > 24000)
+ min_bitrate = 24000;
+ max_bitrate = 6*(cfg->sample_rate)*(cfg->channels);
+ if (max_bitrate > 192000)
+ max_bitrate = 192000;
+ if ((cfg->bit_rate < min_bitrate) ||
+ (cfg->bit_rate > max_bitrate)) {
+ pr_err("%s: bitrate permissible: max=%d, min=%d\n",
+ __func__, max_bitrate, min_bitrate);
+ pr_err("%s: ERROR in setting bitrate = %d\n",
+ __func__, cfg->bit_rate);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg->sample_rate = cfg->sample_rate;
+ enc_cfg->channels = cfg->channels;
+ enc_cfg->bit_rate = cfg->bit_rate;
+ pr_debug("%s:session id %d: Set-aac-cfg:SR= 0x%x ch=0x%x",
+ "bitrate=0x%x, format(adts/raw) = %d\n",
+ __func__, audio->ac->session, enc_cfg->sample_rate,
+ enc_cfg->channels, enc_cfg->bit_rate,
+ enc_cfg->stream_format);
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG: {
+ struct msm_audio_aac_config *aac_cfg;
+ struct msm_audio_aac_config *audio_aac_cfg;
+ struct msm_audio_aac_enc_config *enc_cfg;
+
+ enc_cfg = audio->enc_cfg;
+ audio_aac_cfg = audio->codec_cfg;
+ aac_cfg = (struct msm_audio_aac_config *)arg;
+
+ if (aac_cfg == NULL) {
+ pr_err("%s: NULL config pointer %s\n",
+ __func__, "AUDIO_SET_AAC_CONFIG");
+ rc = -EINVAL;
+ break;
+ }
+ pr_debug("%s:session id %d: AUDIO_SET_AAC_CONFIG: sbr_flag = %d sbr_ps_flag = %d\n",
+ __func__, audio->ac->session, aac_cfg->sbr_on_flag,
+ aac_cfg->sbr_ps_on_flag);
+ audio_aac_cfg->sbr_on_flag = aac_cfg->sbr_on_flag;
+ audio_aac_cfg->sbr_ps_on_flag = aac_cfg->sbr_ps_on_flag;
+ if ((audio_aac_cfg->sbr_on_flag == 1) ||
+ (audio_aac_cfg->sbr_ps_on_flag == 1)) {
+ if (enc_cfg->sample_rate < 24000) {
+ pr_err("%s: ERROR in setting samplerate = %d",
+ "\n", __func__, enc_cfg->sample_rate);
+ rc = -EINVAL;
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static long aac_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = aac_in_ioctl_shared(file, cmd, NULL);
+ break;
+ }
+ case AUDIO_GET_AAC_ENC_CONFIG: {
+ struct msm_audio_aac_enc_config cfg;
+
+ rc = aac_in_ioctl_shared(file, cmd, &cfg);
+ if (rc) {
+ pr_err("%s:AUDIO_GET_AAC_ENC_CONFIG failed. rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ if (copy_to_user((void *)arg, &cfg, sizeof(cfg))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AAC_ENC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_ENC_CONFIG: {
+ struct msm_audio_aac_enc_config cfg;
+
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AAC_ENC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = aac_in_ioctl_shared(file, cmd, &cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG failed. rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ case AUDIO_GET_AAC_CONFIG: {
+ if (copy_to_user((void *)arg, &audio->codec_cfg,
+ sizeof(struct msm_audio_aac_config))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG: {
+ struct msm_audio_aac_config aac_cfg;
+
+ if (copy_from_user(&aac_cfg, (void *)arg,
+ sizeof(struct msm_audio_aac_config))) {
+ pr_err("%s: copy_to_user for AUDIO_SET_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = aac_in_ioctl_shared(file, cmd, &aac_cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_CONFIG failed. rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd=%d\n", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_aac_enc_config32 {
+ u32 channels;
+ u32 sample_rate;
+ u32 bit_rate;
+ u32 stream_format;
+};
+
+struct msm_audio_aac_config32 {
+ s16 format;
+ u16 audio_object;
+ u16 ep_config; /* 0 ~ 3 useful only obj = ERLC */
+ u16 aac_section_data_resilience_flag;
+ u16 aac_scalefactor_data_resilience_flag;
+ u16 aac_spectral_data_resilience_flag;
+ u16 sbr_on_flag;
+ u16 sbr_ps_on_flag;
+ u16 dual_mono_mode;
+ u16 channel_configuration;
+ u16 sample_rate;
+};
+
+enum {
+ AUDIO_SET_AAC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_aac_config32),
+ AUDIO_GET_AAC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_aac_config32),
+ AUDIO_SET_AAC_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_aac_enc_config32),
+ AUDIO_GET_AAC_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+4), struct msm_audio_aac_enc_config32)
+};
+
+static long aac_in_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = aac_in_ioctl_shared(file, cmd, NULL);
+ break;
+ }
+ case AUDIO_GET_AAC_ENC_CONFIG_32: {
+ struct msm_audio_aac_enc_config cfg;
+ struct msm_audio_aac_enc_config32 cfg_32;
+
+ memset(&cfg_32, 0, sizeof(cfg_32));
+
+ cmd = AUDIO_GET_AAC_ENC_CONFIG;
+ rc = aac_in_ioctl_shared(file, cmd, &cfg);
+ if (rc) {
+ pr_err("%s:AUDIO_GET_AAC_ENC_CONFIG_32 failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ cfg_32.channels = cfg.channels;
+ cfg_32.sample_rate = cfg.sample_rate;
+ cfg_32.bit_rate = cfg.bit_rate;
+ cfg_32.stream_format = cfg.stream_format;
+ if (copy_to_user((void *)arg, &cfg_32, sizeof(cfg_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AAC_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_ENC_CONFIG_32: {
+ struct msm_audio_aac_enc_config cfg;
+ struct msm_audio_aac_enc_config32 cfg_32;
+
+ if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_GET_AAC_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.channels = cfg_32.channels;
+ cfg.sample_rate = cfg_32.sample_rate;
+ cfg.bit_rate = cfg_32.bit_rate;
+ cfg.stream_format = cfg_32.stream_format;
+ /* The command should be converted from 32 bit to normal
+ * before the shared ioctl is called as shared ioctl
+ * can process only normal commands
+ */
+ cmd = AUDIO_SET_AAC_ENC_CONFIG;
+ rc = aac_in_ioctl_shared(file, cmd, &cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG_32 failed. rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ case AUDIO_GET_AAC_CONFIG_32: {
+ struct msm_audio_aac_config *aac_config;
+ struct msm_audio_aac_config32 aac_config_32;
+
+ aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
+ aac_config_32.format = aac_config->format;
+ aac_config_32.audio_object = aac_config->audio_object;
+ aac_config_32.ep_config = aac_config->ep_config;
+ aac_config_32.aac_section_data_resilience_flag =
+ aac_config->aac_section_data_resilience_flag;
+ aac_config_32.aac_scalefactor_data_resilience_flag =
+ aac_config->aac_scalefactor_data_resilience_flag;
+ aac_config_32.aac_spectral_data_resilience_flag =
+ aac_config->aac_spectral_data_resilience_flag;
+ aac_config_32.sbr_on_flag = aac_config->sbr_on_flag;
+ aac_config_32.sbr_ps_on_flag = aac_config->sbr_ps_on_flag;
+ aac_config_32.dual_mono_mode = aac_config->dual_mono_mode;
+ aac_config_32.channel_configuration =
+ aac_config->channel_configuration;
+ aac_config_32.sample_rate = aac_config->sample_rate;
+
+ if (copy_to_user((void *)arg, &aac_config_32,
+ sizeof(aac_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG_32: {
+ struct msm_audio_aac_config aac_cfg;
+ struct msm_audio_aac_config32 aac_cfg_32;
+
+ if (copy_from_user(&aac_cfg_32, (void *)arg,
+ sizeof(aac_cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AAC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ aac_cfg.format = aac_cfg_32.format;
+ aac_cfg.audio_object = aac_cfg_32.audio_object;
+ aac_cfg.ep_config = aac_cfg_32.ep_config;
+ aac_cfg.aac_section_data_resilience_flag =
+ aac_cfg_32.aac_section_data_resilience_flag;
+ aac_cfg.aac_scalefactor_data_resilience_flag =
+ aac_cfg_32.aac_scalefactor_data_resilience_flag;
+ aac_cfg.aac_spectral_data_resilience_flag =
+ aac_cfg_32.aac_spectral_data_resilience_flag;
+ aac_cfg.sbr_on_flag = aac_cfg_32.sbr_on_flag;
+ aac_cfg.sbr_ps_on_flag = aac_cfg_32.sbr_ps_on_flag;
+ aac_cfg.dual_mono_mode = aac_cfg_32.dual_mono_mode;
+ aac_cfg.channel_configuration =
+ aac_cfg_32.channel_configuration;
+ aac_cfg.sample_rate = aac_cfg_32.sample_rate;
+
+ cmd = AUDIO_SET_AAC_CONFIG;
+ rc = aac_in_ioctl_shared(file, cmd, &aac_cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d\n", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+#else
+#define aac_in_compat_ioctl NULL
+#endif
+
+static int aac_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_aac_enc_config *enc_cfg;
+ struct msm_audio_aac_config *aac_config;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_aac_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
+ GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ aac_config = audio->codec_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 1536;
+ audio->max_frames_per_buf = 5;
+ enc_cfg->sample_rate = 8000;
+ enc_cfg->channels = 1;
+ enc_cfg->bit_rate = 16000;
+ enc_cfg->stream_format = 0x00;/* 0:ADTS, 3:RAW */
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ aac_config->format = AUDIO_AAC_FORMAT_ADTS;
+ aac_config->audio_object = AUDIO_AAC_OBJECT_LC;
+ aac_config->sbr_on_flag = 0;
+ aac_config->sbr_ps_on_flag = 0;
+ aac_config->channel_configuration = 1;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s: Could not allocate memory for",
+ "audio client\n", __func__);
+ kfree(audio->enc_cfg);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ /* open aac encoder in tunnel mode */
+ audio->buf_cfg.frames_per_buf = 0x01;
+
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_MPEG4_AAC,
+ FORMAT_LINEAR_PCM);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->buf_cfg.meta_info_enable = 0x01;
+ pr_info("%s:session id %d: NT mode encoder success\n", __func__,
+ audio->ac->session);
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_MPEG4_AAC);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: Tunnel Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration",
+ "failed rc=%d\n", __func__,
+ audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->buf_cfg.meta_info_enable = 0x00;
+ pr_info("%s:session id %d: T mode encoder success\n", __func__,
+ audio->ac->session);
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+ audio->opened = 1;
+ audio->reset_event = false;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = aac_in_compat_ioctl;
+ audio->enc_ioctl = aac_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = aac_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+ .compat_ioctl = audio_in_compat_ioctl
+};
+
+struct miscdevice audio_aac_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_aac_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init aac_in_init(void)
+{
+ return misc_register(&audio_aac_in_misc);
+}
+device_initcall(aac_in_init);
diff --git a/drivers/misc/qcom/qdsp6v2/amrnb_in.c b/drivers/misc/qcom/qdsp6v2/amrnb_in.c
new file mode 100644
index 0000000..d76509d
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/amrnb_in.c
@@ -0,0 +1,405 @@
+/* Copyright (c) 2010-2012, 2014, 2016-2017 The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_amrnb.h>
+#include <linux/compat.h>
+#include <linux/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((32+sizeof(struct meta_out_dsp)) * 10))
+
+static long amrnb_in_ioctl_shared(struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+
+ enc_cfg = audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ pr_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+
+ rc = q6asm_enc_cfg_blk_amrnb(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->band_mode,
+ enc_cfg->dtx_enable);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd amrnb media format block",
+ "failed\n", __func__, audio->ac->session);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block",
+ "failed\n", __func__, audio->ac->session);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+ __func__, audio->ac->session,
+ audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed",
+ "rc=%d\n", __func__,
+ audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:AUDIO_STOP\n", __func__);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed",
+ "rc=%d\n", __func__,
+ audio->ac->session, rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
+ struct msm_audio_amrnb_enc_config_v2 *cfg;
+ struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+
+ cfg = (struct msm_audio_amrnb_enc_config_v2 *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer for %s\n",
+ __func__,
+ "AUDIO_SET_AMRNB_ENC_CONFIG_V2");
+ rc = -EINVAL;
+ break;
+ }
+
+ enc_cfg = audio->enc_cfg;
+ if (cfg->band_mode > 8 ||
+ cfg->band_mode < 1) {
+ pr_err("%s:session id %d: invalid band mode\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ /* AMR NB encoder accepts values between 0-7
+ * while openmax provides value between 1-8
+ * as per spec
+ */
+ enc_cfg->band_mode = (cfg->band_mode - 1);
+ enc_cfg->dtx_enable = (cfg->dtx_enable ? 1 : 0);
+ enc_cfg->frame_format = 0;
+ pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
+ __func__, audio->ac->session,
+ enc_cfg->band_mode, enc_cfg->dtx_enable);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static long amrnb_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = amrnb_in_ioctl_shared(file, cmd, NULL);
+ break;
+ }
+ case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_amrnb_enc_config_v2))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AMRNB_ENC_CONFIG_V2 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
+ struct msm_audio_amrnb_enc_config_v2 cfg;
+
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(cfg))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AMRNB_ENC_CONFIG_V2 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = amrnb_in_ioctl_shared(file, cmd, &cfg);
+ if (rc)
+ pr_err("%s: AUDIO_SET_AMRNB_ENC_CONFIG_V2 failed. rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd=%d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_amrnb_enc_config_v2_32 {
+ u32 band_mode;
+ u32 dtx_enable;
+ u32 frame_format;
+};
+
+enum {
+ AUDIO_GET_AMRNB_ENC_CONFIG_V2_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2),
+ struct msm_audio_amrnb_enc_config_v2_32),
+ AUDIO_SET_AMRNB_ENC_CONFIG_V2_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3),
+ struct msm_audio_amrnb_enc_config_v2_32)
+};
+
+static long amrnb_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = amrnb_in_ioctl_shared(file, cmd, NULL);
+ break;
+ }
+ case AUDIO_GET_AMRNB_ENC_CONFIG_V2_32: {
+ struct msm_audio_amrnb_enc_config_v2 *amrnb_config;
+ struct msm_audio_amrnb_enc_config_v2_32 amrnb_config_32;
+
+ memset(&amrnb_config_32, 0, sizeof(amrnb_config_32));
+
+ amrnb_config =
+ (struct msm_audio_amrnb_enc_config_v2 *)audio->enc_cfg;
+ amrnb_config_32.band_mode = amrnb_config->band_mode;
+ amrnb_config_32.dtx_enable = amrnb_config->dtx_enable;
+ amrnb_config_32.frame_format = amrnb_config->frame_format;
+
+ if (copy_to_user((void *)arg, &amrnb_config_32,
+ sizeof(amrnb_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AMRNB_ENC_CONFIG_V2_32 failed",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRNB_ENC_CONFIG_V2_32: {
+ struct msm_audio_amrnb_enc_config_v2_32 cfg_32;
+
+ if (copy_from_user(&cfg_32, (void *) arg,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AMRNB_ENC_CONFIG_V2_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cmd = AUDIO_SET_AMRNB_ENC_CONFIG_V2;
+ rc = amrnb_in_ioctl_shared(file, cmd, &cfg_32);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AMRNB_ENC_CONFIG_V2 failed rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+#else
+#define amrnb_in_compat_ioctl NULL
+#endif
+
+static int amrnb_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrnb_enc_config_v2),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 32;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->band_mode = 7;
+ enc_cfg->dtx_enable = 0;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s: Could not allocate memory for audio",
+ "client\n", __func__);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open amrnb encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_AMRNB,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: NT mode encoder success\n",
+ __func__, audio->ac->session);
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_AMRNB);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration",
+ "failed rc=%d\n", __func__, audio->ac->session,
+ rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: T mode encoder success\n",
+ __func__, audio->ac->session);
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = amrnb_in_compat_ioctl;
+ audio->enc_ioctl = amrnb_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = amrnb_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+ .compat_ioctl = audio_in_compat_ioctl
+};
+
+struct miscdevice audio_amrnb_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrnb_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init amrnb_in_init(void)
+{
+ return misc_register(&audio_amrnb_in_misc);
+}
+
+device_initcall(amrnb_in_init);
diff --git a/drivers/misc/qcom/qdsp6v2/amrwb_in.c b/drivers/misc/qcom/qdsp6v2/amrwb_in.c
new file mode 100644
index 0000000..541a6c0
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/amrwb_in.c
@@ -0,0 +1,400 @@
+/* Copyright (c) 2011-2012, 2014, 2016-2017 The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/msm_audio_amrwb.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/compat.h>
+#include <linux/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((61+sizeof(struct meta_out_dsp)) * 10))
+
+static long amrwb_in_ioctl_shared(struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_amrwb_enc_config *enc_cfg;
+
+ enc_cfg = audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ pr_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+
+ rc = q6asm_enc_cfg_blk_amrwb(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->band_mode,
+ enc_cfg->dtx_enable);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd amrwb media format block",
+ "failed\n", __func__, audio->ac->session);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block",
+ "failed\n", __func__, audio->ac->session);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+ __func__, audio->ac->session,
+ audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed",
+ "rc=%d\n", __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:AUDIO_STOP\n", __func__);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed",
+ "rc=%d\n", __func__, audio->ac->session, rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRWB_ENC_CONFIG: {
+ struct msm_audio_amrwb_enc_config *cfg;
+ struct msm_audio_amrwb_enc_config *enc_cfg;
+
+ enc_cfg = audio->enc_cfg;
+ cfg = (struct msm_audio_amrwb_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer for %s\n",
+ __func__, "AUDIO_SET_AMRWB_ENC_CONFIG");
+ rc = -EINVAL;
+ break;
+ }
+
+ if (cfg->band_mode > 8) {
+ pr_err("%s:session id %d: invalid band mode\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ /* ToDo: AMR WB encoder accepts values between 0-8
+ * while openmax provides value between 9-17
+ * as per spec
+ */
+ enc_cfg->band_mode = cfg->band_mode;
+ enc_cfg->dtx_enable = (cfg->dtx_enable ? 1 : 0);
+ /* Currently DSP does not support different frameformat */
+ enc_cfg->frame_format = 0;
+ pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
+ __func__, audio->ac->session,
+ enc_cfg->band_mode, enc_cfg->dtx_enable);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static long amrwb_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = amrwb_in_ioctl_shared(file, cmd, NULL);
+ break;
+ }
+ case AUDIO_GET_AMRWB_ENC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_amrwb_enc_config)))
+ pr_err("%s: copy_to_user for AUDIO_GET_AMRWB_ENC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ case AUDIO_SET_AMRWB_ENC_CONFIG: {
+ struct msm_audio_amrwb_enc_config cfg;
+
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(cfg))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AMRWB_ENC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = amrwb_in_ioctl_shared(file, cmd, &cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG failed. rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_amrwb_enc_config_32 {
+ u32 band_mode;
+ u32 dtx_enable;
+ u32 frame_format;
+};
+
+enum {
+ AUDIO_GET_AMRWB_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0),
+ struct msm_audio_amrwb_enc_config_32),
+ AUDIO_SET_AMRWB_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1),
+ struct msm_audio_amrwb_enc_config_32)
+};
+
+static long amrwb_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = amrwb_in_ioctl_shared(file, cmd, NULL);
+ break;
+ }
+ case AUDIO_GET_AMRWB_ENC_CONFIG_32: {
+ struct msm_audio_amrwb_enc_config *amrwb_config;
+ struct msm_audio_amrwb_enc_config_32 amrwb_config_32;
+
+ memset(&amrwb_config_32, 0, sizeof(amrwb_config_32));
+
+ amrwb_config =
+ (struct msm_audio_amrwb_enc_config *)audio->enc_cfg;
+ amrwb_config_32.band_mode = amrwb_config->band_mode;
+ amrwb_config_32.dtx_enable = amrwb_config->dtx_enable;
+ amrwb_config_32.frame_format = amrwb_config->frame_format;
+
+ if (copy_to_user((void *)arg, &amrwb_config_32,
+ sizeof(struct msm_audio_amrwb_enc_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AMRWB_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRWB_ENC_CONFIG_32: {
+ struct msm_audio_amrwb_enc_config cfg_32;
+
+ if (copy_from_user(&cfg_32, (void *) arg,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AMRWB_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cmd = AUDIO_SET_AMRWB_ENC_CONFIG;
+ rc = amrwb_in_ioctl_shared(file, cmd, &cfg_32);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG failed. rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+#else
+#define amrwb_in_compat_ioctl NULL
+#endif
+
+static int amrwb_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_amrwb_enc_config *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrwb_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 32;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->band_mode = 8;
+ enc_cfg->dtx_enable = 0;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 16000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s:audio[%pK]: Could not allocate memory for audio",
+ "client\n", __func__, audio);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open amrwb encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_AMRWB,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: NT mode encoder success\n",
+ __func__, audio->ac->session);
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_AMRWB);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration",
+ "failed rc=%d\n", __func__, audio->ac->session,
+ rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: T mode encoder success\n",
+ __func__, audio->ac->session);
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = amrwb_in_compat_ioctl;
+ audio->enc_ioctl = amrwb_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = amrwb_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+ .compat_ioctl = audio_in_compat_ioctl
+};
+
+struct miscdevice audio_amrwb_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrwb_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init amrwb_in_init(void)
+{
+ return misc_register(&audio_amrwb_in_misc);
+}
+
+device_initcall(amrwb_in_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_aac.c b/drivers/misc/qcom/qdsp6v2/audio_aac.c
new file mode 100644
index 0000000..0f371fd
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_aac.c
@@ -0,0 +1,474 @@
+/* aac audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/msm_audio_aac.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+#define AUDIO_AAC_DUAL_MONO_INVALID -1
+#define PCM_BUFSZ_MIN_AAC ((8*1024) + sizeof(struct dec_meta_out))
+
+static struct miscdevice audio_aac_misc;
+static struct ws_mgr audio_aac_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_aac_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_aac_cfg aac_cfg;
+ struct msm_audio_aac_config *aac_config;
+ uint32_t sbr_ps = 0x00;
+
+ pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
+ audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac, 0, 0);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ /* turn on both sbr and ps */
+ rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
+ if (rc < 0)
+ pr_err("sbr-ps enable failed\n");
+ aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
+ if (aac_config->sbr_ps_on_flag)
+ aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+ else if (aac_config->sbr_on_flag)
+ aac_cfg.aot = AAC_ENC_MODE_AAC_P;
+ else
+ aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
+
+ switch (aac_config->format) {
+ case AUDIO_AAC_FORMAT_ADTS:
+ aac_cfg.format = 0x00;
+ break;
+ case AUDIO_AAC_FORMAT_LOAS:
+ aac_cfg.format = 0x01;
+ break;
+ case AUDIO_AAC_FORMAT_ADIF:
+ aac_cfg.format = 0x02;
+ break;
+ default:
+ case AUDIO_AAC_FORMAT_RAW:
+ aac_cfg.format = 0x03;
+ }
+ aac_cfg.ep_config = aac_config->ep_config;
+ aac_cfg.section_data_resilience =
+ aac_config->aac_section_data_resilience_flag;
+ aac_cfg.scalefactor_data_resilience =
+ aac_config->aac_scalefactor_data_resilience_flag;
+ aac_cfg.spectral_data_resilience =
+ aac_config->aac_spectral_data_resilience_flag;
+ aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
+ if (audio->feedback == TUNNEL_MODE) {
+ aac_cfg.sample_rate = aac_config->sample_rate;
+ aac_cfg.ch_cfg = aac_config->channel_configuration;
+ } else {
+ aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
+ aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
+ }
+
+ pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
+ __func__, aac_cfg.format,
+ aac_cfg.aot, aac_cfg.ch_cfg,
+ aac_cfg.sample_rate);
+
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_aac(audio->ac, &aac_cfg);
+ if (rc < 0) {
+ pr_err("cmd media format block failed\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ rc = enable_volume_ramp(audio);
+ if (rc < 0) {
+ pr_err("%s: Failed to enable volume ramp\n",
+ __func__);
+ }
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG: {
+ struct msm_audio_aac_config *aac_config;
+ uint16_t sce_left = 1, sce_right = 2;
+
+ pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
+ aac_config = (struct msm_audio_aac_config *)arg;
+ if (aac_config == NULL) {
+ pr_err("%s: Invalid config pointer\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ memcpy(audio->codec_cfg, aac_config,
+ sizeof(struct msm_audio_aac_config));
+ /* PL_PR is 0 only need to check PL_SR */
+ if (aac_config->dual_mono_mode >
+ AUDIO_AAC_DUAL_MONO_PL_SR) {
+ pr_err("%s:Invalid dual_mono mode =%d\n", __func__,
+ aac_config->dual_mono_mode);
+ } else {
+ /* convert the data from user into sce_left
+ * and sce_right based on the definitions
+ */
+ pr_debug("%s: modify dual_mono mode =%d\n", __func__,
+ aac_config->dual_mono_mode);
+ switch (aac_config->dual_mono_mode) {
+ case AUDIO_AAC_DUAL_MONO_PL_PR:
+ sce_left = 1;
+ sce_right = 1;
+ break;
+ case AUDIO_AAC_DUAL_MONO_SL_SR:
+ sce_left = 2;
+ sce_right = 2;
+ break;
+ case AUDIO_AAC_DUAL_MONO_SL_PR:
+ sce_left = 2;
+ sce_right = 1;
+ break;
+ case AUDIO_AAC_DUAL_MONO_PL_SR:
+ default:
+ sce_left = 1;
+ sce_right = 2;
+ break;
+ }
+ rc = q6asm_cfg_dual_mono_aac(audio->ac,
+ sce_left, sce_right);
+ if (rc < 0)
+ pr_err("%s:asm cmd dualmono failed rc=%d\n",
+ __func__, rc);
+ }
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_AAC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_aac_config))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG: {
+ struct msm_audio_aac_config aac_config;
+
+ pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
+ if (copy_from_user(&aac_config, (void *)arg,
+ sizeof(aac_config))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AAC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = audio_ioctl_shared(file, cmd, &aac_config);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s[%pK]:Failed in utils_ioctl: %d\n",
+ __func__, audio, rc);
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_aac_config32 {
+ s16 format;
+ u16 audio_object;
+ u16 ep_config; /* 0 ~ 3 useful only obj = ERLC */
+ u16 aac_section_data_resilience_flag;
+ u16 aac_scalefactor_data_resilience_flag;
+ u16 aac_spectral_data_resilience_flag;
+ u16 sbr_on_flag;
+ u16 sbr_ps_on_flag;
+ u16 dual_mono_mode;
+ u16 channel_configuration;
+ u16 sample_rate;
+};
+
+enum {
+ AUDIO_SET_AAC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_aac_config32),
+ AUDIO_GET_AAC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_aac_config32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_AAC_CONFIG_32: {
+ struct msm_audio_aac_config *aac_config;
+ struct msm_audio_aac_config32 aac_config_32;
+
+ aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
+ aac_config_32.format = aac_config->format;
+ aac_config_32.audio_object = aac_config->audio_object;
+ aac_config_32.ep_config = aac_config->ep_config;
+ aac_config_32.aac_section_data_resilience_flag =
+ aac_config->aac_section_data_resilience_flag;
+ aac_config_32.aac_scalefactor_data_resilience_flag =
+ aac_config->aac_scalefactor_data_resilience_flag;
+ aac_config_32.aac_spectral_data_resilience_flag =
+ aac_config->aac_spectral_data_resilience_flag;
+ aac_config_32.sbr_on_flag = aac_config->sbr_on_flag;
+ aac_config_32.sbr_ps_on_flag = aac_config->sbr_ps_on_flag;
+ aac_config_32.dual_mono_mode = aac_config->dual_mono_mode;
+ aac_config_32.channel_configuration =
+ aac_config->channel_configuration;
+ aac_config_32.sample_rate = aac_config->sample_rate;
+
+ if (copy_to_user((void *)arg, &aac_config_32,
+ sizeof(aac_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG_32: {
+ struct msm_audio_aac_config aac_config;
+ struct msm_audio_aac_config32 aac_config_32;
+
+ pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
+ if (copy_from_user(&aac_config_32, (void *)arg,
+ sizeof(aac_config_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AAC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ aac_config.format = aac_config_32.format;
+ aac_config.audio_object = aac_config_32.audio_object;
+ aac_config.ep_config = aac_config_32.ep_config;
+ aac_config.aac_section_data_resilience_flag =
+ aac_config_32.aac_section_data_resilience_flag;
+ aac_config.aac_scalefactor_data_resilience_flag =
+ aac_config_32.aac_scalefactor_data_resilience_flag;
+ aac_config.aac_spectral_data_resilience_flag =
+ aac_config_32.aac_spectral_data_resilience_flag;
+ aac_config.sbr_on_flag = aac_config_32.sbr_on_flag;
+ aac_config.sbr_ps_on_flag = aac_config_32.sbr_ps_on_flag;
+ aac_config.dual_mono_mode = aac_config_32.dual_mono_mode;
+ aac_config.channel_configuration =
+ aac_config_32.channel_configuration;
+ aac_config.sample_rate = aac_config_32.sample_rate;
+
+ cmd = AUDIO_SET_AAC_CONFIG;
+ rc = audio_ioctl_shared(file, cmd, &aac_config);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s[%pK]:Failed in utils_ioctl: %d\n",
+ __func__, audio, rc);
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+ struct msm_audio_aac_config *aac_config = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_aac_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
+ GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ aac_config = audio->codec_cfg;
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AAC;
+ audio->miscdevice = &audio_aac_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_aac_ws_mgr;
+ aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_MPEG4_AAC);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open AAC decoder, expected frames is always 1
+ * audio->buf_cfg.frames_per_buf = 0x01;
+ */
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_AAC);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_aac_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_aac_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:aacdec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_aac_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl
+};
+
+static struct miscdevice audio_aac_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_aac",
+ .fops = &audio_aac_fops,
+};
+
+static int __init audio_aac_init(void)
+{
+ int ret = misc_register(&audio_aac_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_aac_misc.this_device, true);
+ audio_aac_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_aac_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_aac_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_alac.c b/drivers/misc/qcom/qdsp6v2/audio_alac.c
new file mode 100644
index 0000000..d0b86c6
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_alac.c
@@ -0,0 +1,435 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/msm_audio_alac.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_alac_misc;
+static struct ws_mgr audio_alac_ws_mgr;
+
+static const struct file_operations audio_alac_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+
+static struct dentry *config_debugfs_create_file(const char *name, void *data)
+{
+ return debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)data, &audio_alac_debug_fops);
+}
+
+static int alac_channel_map(u8 *channel_mapping, uint32_t channels);
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_alac_cfg alac_cfg;
+ struct msm_audio_alac_config *alac_config;
+ u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (alac_channel_map(channel_mapping,
+ audio->pcm_cfg.channel_count)) {
+ pr_err("%s: setting channel map failed %d\n",
+ __func__, audio->pcm_cfg.channel_count);
+ }
+
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count,
+ 16, /*bits per sample*/
+ false, false, channel_mapping);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ alac_config = (struct msm_audio_alac_config *)audio->codec_cfg;
+ alac_cfg.frame_length = alac_config->frameLength;
+ alac_cfg.compatible_version = alac_config->compatVersion;
+ alac_cfg.bit_depth = alac_config->bitDepth;
+ alac_cfg.pb = alac_config->pb;
+ alac_cfg.mb = alac_config->mb;
+ alac_cfg.kb = alac_config->kb;
+ alac_cfg.num_channels = alac_config->channelCount;
+ alac_cfg.max_run = alac_config->maxRun;
+ alac_cfg.max_frame_bytes = alac_config->maxSize;
+ alac_cfg.avg_bit_rate = alac_config->averageBitRate;
+ alac_cfg.sample_rate = alac_config->sampleRate;
+ alac_cfg.channel_layout_tag = alac_config->channelLayout;
+ pr_debug("%s: frame_length %d compatible_version %d bit_depth %d pb %d mb %d kb %d num_channels %d max_run %d max_frame_bytes %d avg_bit_rate %d sample_rate %d channel_layout_tag %d\n",
+ __func__, alac_config->frameLength,
+ alac_config->compatVersion,
+ alac_config->bitDepth, alac_config->pb,
+ alac_config->mb, alac_config->kb,
+ alac_config->channelCount, alac_config->maxRun,
+ alac_config->maxSize,
+ alac_config->averageBitRate,
+ alac_config->sampleRate,
+ alac_config->channelLayout);
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_alac(audio->ac, &alac_cfg,
+ audio->ac->stream_id);
+ if (rc < 0) {
+ pr_err("cmd media format block failed\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_ALAC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_alac_config))) {
+ pr_err("%s:copy_to_user for AUDIO_GET_ALAC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_ALAC_CONFIG: {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_alac_config))) {
+ pr_err("%s:copy_from_user for AUDIO_SET_ALAC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ default: {
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("Failed in utils_ioctl: %d\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_alac_config_32 {
+ u32 frameLength;
+ u8 compatVersion;
+ u8 bitDepth;
+ u8 pb;
+ u8 mb;
+ u8 kb;
+ u8 channelCount;
+ u16 maxRun;
+ u32 maxSize;
+ u32 averageBitRate;
+ u32 sampleRate;
+ u32 channelLayout;
+};
+
+enum {
+ AUDIO_GET_ALAC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_alac_config_32),
+ AUDIO_SET_ALAC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_alac_config_32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_ALAC_CONFIG_32: {
+ struct msm_audio_alac_config *alac_config;
+ struct msm_audio_alac_config_32 alac_config_32;
+
+ memset(&alac_config_32, 0, sizeof(alac_config_32));
+
+ alac_config = (struct msm_audio_alac_config *)audio->codec_cfg;
+ alac_config_32.frameLength = alac_config->frameLength;
+ alac_config_32.compatVersion =
+ alac_config->compatVersion;
+ alac_config_32.bitDepth = alac_config->bitDepth;
+ alac_config_32.pb = alac_config->pb;
+ alac_config_32.mb = alac_config->mb;
+ alac_config_32.kb = alac_config->kb;
+ alac_config_32.channelCount = alac_config->channelCount;
+ alac_config_32.maxRun = alac_config->maxRun;
+ alac_config_32.maxSize = alac_config->maxSize;
+ alac_config_32.averageBitRate = alac_config->averageBitRate;
+ alac_config_32.sampleRate = alac_config->sampleRate;
+ alac_config_32.channelLayout = alac_config->channelLayout;
+
+ if (copy_to_user((void *)arg, &alac_config_32,
+ sizeof(alac_config_32))) {
+ pr_err("%s: copy_to_user for GET_ALAC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_ALAC_CONFIG_32: {
+ struct msm_audio_alac_config *alac_config;
+ struct msm_audio_alac_config_32 alac_config_32;
+
+ if (copy_from_user(&alac_config_32, (void *)arg,
+ sizeof(alac_config_32))) {
+ pr_err("%s: copy_from_user for SET_ALAC_CONFIG_32 failed\n"
+ , __func__);
+ rc = -EFAULT;
+ break;
+ }
+ alac_config = (struct msm_audio_alac_config *)audio->codec_cfg;
+ alac_config->frameLength = alac_config_32.frameLength;
+ alac_config->compatVersion =
+ alac_config_32.compatVersion;
+ alac_config->bitDepth = alac_config_32.bitDepth;
+ alac_config->pb = alac_config_32.pb;
+ alac_config->mb = alac_config_32.mb;
+ alac_config->kb = alac_config_32.kb;
+ alac_config->channelCount = alac_config_32.channelCount;
+ alac_config->maxRun = alac_config_32.maxRun;
+ alac_config->maxSize = alac_config_32.maxSize;
+ alac_config->averageBitRate = alac_config_32.averageBitRate;
+ alac_config->sampleRate = alac_config_32.sampleRate;
+ alac_config->channelLayout = alac_config_32.channelLayout;
+
+ break;
+ }
+ default: {
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("Failed in utils_ioctl: %d\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_alac_" + 5];
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+ if (!audio)
+ return -ENOMEM;
+
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_alac_config),
+ GFP_KERNEL);
+ if (!audio->codec_cfg) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_alac_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_alac_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_ALAC);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open ALAC decoder, expected frames is always 1*/
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_ALAC);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "msm_alac_%04x", audio->ac->session);
+ audio->dentry = config_debugfs_create_file(name, (void *)audio);
+
+ if (IS_ERR_OR_NULL(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+ pr_debug("%s:alacdec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static int alac_channel_map(u8 *channel_mapping, uint32_t channels)
+{
+ u8 *lchannel_mapping;
+
+ lchannel_mapping = channel_mapping;
+ pr_debug("%s: channels passed: %d\n", __func__, channels);
+ if (channels == 1) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channels == 3) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ } else if (channels == 4) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_CS;
+ } else if (channels == 5) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ } else if (channels == 7) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_CS;
+ lchannel_mapping[6] = PCM_CHANNEL_LFE;
+ } else if (channels == 8) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FLC;
+ lchannel_mapping[2] = PCM_CHANNEL_FRC;
+ lchannel_mapping[3] = PCM_CHANNEL_FL;
+ lchannel_mapping[4] = PCM_CHANNEL_FR;
+ lchannel_mapping[5] = PCM_CHANNEL_LS;
+ lchannel_mapping[6] = PCM_CHANNEL_RS;
+ lchannel_mapping[7] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct file_operations audio_alac_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl
+};
+
+static struct miscdevice audio_alac_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_alac",
+ .fops = &audio_alac_fops,
+};
+
+static int __init audio_alac_init(void)
+{
+ int ret = misc_register(&audio_alac_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_alac_misc.this_device, true);
+ audio_alac_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_alac_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_alac_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrnb.c b/drivers/misc/qcom/qdsp6v2/audio_amrnb.c
new file mode 100644
index 0000000..950098b
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_amrnb.c
@@ -0,0 +1,226 @@
+/* amrnb audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_amrnb_misc;
+static struct ws_mgr audio_amrnb_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrnb_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("%s: pcm output block config failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s: Audio Start procedure failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_amrnb_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_amrnb_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_amrnb_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_AMRNB);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_AMRNB);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_amrnb_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_amrnb_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:amrnb decoder open success, session_id = %d\n", __func__,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_amrnb_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl,
+};
+
+static struct miscdevice audio_amrnb_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrnb",
+ .fops = &audio_amrnb_fops,
+};
+
+static int __init audio_amrnb_init(void)
+{
+ int ret = misc_register(&audio_amrnb_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_amrnb_misc.this_device, true);
+ audio_amrnb_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_amrnb_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_amrnb_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrwb.c b/drivers/misc/qcom/qdsp6v2/audio_amrwb.c
new file mode 100644
index 0000000..cb5db0d
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_amrwb.c
@@ -0,0 +1,231 @@
+/* amrwb audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/compat.h>
+#include <linux/types.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_amrwb_misc;
+static struct ws_mgr audio_amrwb_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrwb_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("%s: pcm output block config failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s: Audio Start procedure failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_amrwb_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_amrwb_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_amrwb_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_AMRWB);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_AMRWB);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_amrwb_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_amrwb_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s: AMRWB dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_amrwb_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl,
+};
+
+static struct miscdevice audio_amrwb_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrwb",
+ .fops = &audio_amrwb_fops,
+};
+
+static int __init audio_amrwb_init(void)
+{
+ int ret = misc_register(&audio_amrwb_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_amrwb_misc.this_device, true);
+ audio_amrwb_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_amrwb_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_amrwb_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrwbplus.c b/drivers/misc/qcom/qdsp6v2/audio_amrwbplus.c
new file mode 100644
index 0000000..2132591
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_amrwbplus.c
@@ -0,0 +1,397 @@
+/* amr-wbplus audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/msm_audio_amrwbplus.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_amrwbplus_misc;
+static struct ws_mgr audio_amrwbplus_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrwbplus_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+static void config_debug_fs(struct q6audio_aio *audio)
+{
+ if (audio != NULL) {
+ char name[sizeof("msm_amrwbplus_") + 5];
+
+ snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
+ audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_amrwbplus_debug_fops);
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+ }
+}
+#else
+static void config_debug_fs(struct q6audio_aio *audio)
+{
+}
+#endif
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct asm_amrwbplus_cfg q6_amrwbplus_cfg;
+ struct msm_audio_amrwbplus_config_v2 *amrwbplus_drv_config;
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_err("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ amrwbplus_drv_config =
+ (struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
+
+ q6_amrwbplus_cfg.size_bytes =
+ amrwbplus_drv_config->size_bytes;
+ q6_amrwbplus_cfg.version =
+ amrwbplus_drv_config->version;
+ q6_amrwbplus_cfg.num_channels =
+ amrwbplus_drv_config->num_channels;
+ q6_amrwbplus_cfg.amr_band_mode =
+ amrwbplus_drv_config->amr_band_mode;
+ q6_amrwbplus_cfg.amr_dtx_mode =
+ amrwbplus_drv_config->amr_dtx_mode;
+ q6_amrwbplus_cfg.amr_frame_fmt =
+ amrwbplus_drv_config->amr_frame_fmt;
+ q6_amrwbplus_cfg.amr_lsf_idx =
+ amrwbplus_drv_config->amr_lsf_idx;
+
+ rc = q6asm_media_format_block_amrwbplus(audio->ac,
+ &q6_amrwbplus_cfg);
+ if (rc < 0) {
+ pr_err("q6asm_media_format_block_amrwb+ failed...\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_AMRWBPLUS_CONFIG_V2: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_amrwbplus_config_v2))) {
+ rc = -EFAULT;
+ pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2 failed\n",
+ __func__);
+ break;
+ }
+ } else {
+ pr_err("%s: wb+ config v2 invalid parameters\n"
+ , __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRWBPLUS_CONFIG_V2: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_amrwbplus_config_v2))) {
+ rc = -EFAULT;
+ pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2 failed\n",
+ __func__);
+ break;
+ }
+ } else {
+ pr_err("%s: wb+ config invalid parameters\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ break;
+ }
+ }
+ return rc;
+}
+#ifdef CONFIG_COMPAT
+struct msm_audio_amrwbplus_config_v2_32 {
+ u32 size_bytes;
+ u32 version;
+ u32 num_channels;
+ u32 amr_band_mode;
+ u32 amr_dtx_mode;
+ u32 amr_frame_fmt;
+ u32 amr_lsf_idx;
+};
+
+enum {
+ AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2),
+ struct msm_audio_amrwbplus_config_v2_32),
+ AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3),
+ struct msm_audio_amrwbplus_config_v2_32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_AMRWBPLUS_CONFIG_V2_32: {
+ if (audio && arg && (audio->codec_cfg)) {
+ struct msm_audio_amrwbplus_config_v2 *amrwbplus_config;
+ struct msm_audio_amrwbplus_config_v2_32
+ amrwbplus_config_32;
+
+ memset(&amrwbplus_config_32, 0,
+ sizeof(amrwbplus_config_32));
+
+ amrwbplus_config =
+ (struct msm_audio_amrwbplus_config_v2 *)
+ audio->codec_cfg;
+ amrwbplus_config_32.size_bytes =
+ amrwbplus_config->size_bytes;
+ amrwbplus_config_32.version =
+ amrwbplus_config->version;
+ amrwbplus_config_32.num_channels =
+ amrwbplus_config->num_channels;
+ amrwbplus_config_32.amr_band_mode =
+ amrwbplus_config->amr_band_mode;
+ amrwbplus_config_32.amr_dtx_mode =
+ amrwbplus_config->amr_dtx_mode;
+ amrwbplus_config_32.amr_frame_fmt =
+ amrwbplus_config->amr_frame_fmt;
+ amrwbplus_config_32.amr_lsf_idx =
+ amrwbplus_config->amr_lsf_idx;
+
+ if (copy_to_user((void *)arg, &amrwbplus_config_32,
+ sizeof(amrwbplus_config_32))) {
+ rc = -EFAULT;
+ pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 failed\n"
+ , __func__);
+ }
+ } else {
+ pr_err("%s: wb+ Get config v2 invalid parameters\n"
+ , __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRWBPLUS_CONFIG_V2_32: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ struct msm_audio_amrwbplus_config_v2 *amrwbplus_config;
+ struct msm_audio_amrwbplus_config_v2_32
+ amrwbplus_config_32;
+
+ if (copy_from_user(&amrwbplus_config_32, (void *)arg,
+ sizeof(struct msm_audio_amrwbplus_config_v2_32))) {
+ rc = -EFAULT;
+ pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 failed\n"
+ , __func__);
+ break;
+ }
+ amrwbplus_config =
+ (struct msm_audio_amrwbplus_config_v2 *)
+ audio->codec_cfg;
+ amrwbplus_config->size_bytes =
+ amrwbplus_config_32.size_bytes;
+ amrwbplus_config->version =
+ amrwbplus_config_32.version;
+ amrwbplus_config->num_channels =
+ amrwbplus_config_32.num_channels;
+ amrwbplus_config->amr_band_mode =
+ amrwbplus_config_32.amr_band_mode;
+ amrwbplus_config->amr_dtx_mode =
+ amrwbplus_config_32.amr_dtx_mode;
+ amrwbplus_config->amr_frame_fmt =
+ amrwbplus_config_32.amr_frame_fmt;
+ amrwbplus_config->amr_lsf_idx =
+ amrwbplus_config_32.amr_lsf_idx;
+ } else {
+ pr_err("%s: wb+ config invalid parameters\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ audio->codec_cfg =
+ kzalloc(sizeof(struct msm_audio_amrwbplus_config_v2), GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_amrwbplus_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_amrwbplus_ws_mgr;
+
+ audio->ac =
+ q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_AMR_WB_PLUS);
+ if (rc < 0) {
+ pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_AMR_WB_PLUS);
+ if (rc < 0) {
+ pr_err("wb+ T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("audio_amrwbplus Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+ config_debug_fs(audio);
+ pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_amrwbplus_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl
+};
+
+static struct miscdevice audio_amrwbplus_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrwbplus",
+ .fops = &audio_amrwbplus_fops,
+};
+
+static int __init audio_amrwbplus_init(void)
+{
+ int ret = misc_register(&audio_amrwbplus_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_amrwbplus_misc.this_device, true);
+ audio_amrwbplus_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_amrwbplus_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_amrwbplus_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_ape.c b/drivers/misc/qcom/qdsp6v2/audio_ape.c
new file mode 100644
index 0000000..d7dc064
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_ape.c
@@ -0,0 +1,359 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/msm_audio_ape.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_ape_misc;
+static struct ws_mgr audio_ape_ws_mgr;
+
+static const struct file_operations audio_ape_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+static struct dentry *config_debugfs_create_file(const char *name, void *data)
+{
+ return debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)data, &audio_ape_debug_fops);
+}
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_ape_cfg ape_cfg;
+ struct msm_audio_ape_config *ape_config;
+
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ ape_config = (struct msm_audio_ape_config *)audio->codec_cfg;
+ ape_cfg.compatible_version = ape_config->compatibleVersion;
+ ape_cfg.compression_level = ape_config->compressionLevel;
+ ape_cfg.format_flags = ape_config->formatFlags;
+ ape_cfg.blocks_per_frame = ape_config->blocksPerFrame;
+ ape_cfg.final_frame_blocks = ape_config->finalFrameBlocks;
+ ape_cfg.total_frames = ape_config->totalFrames;
+ ape_cfg.bits_per_sample = ape_config->bitsPerSample;
+ ape_cfg.num_channels = ape_config->numChannels;
+ ape_cfg.sample_rate = ape_config->sampleRate;
+ ape_cfg.seek_table_present = ape_config->seekTablePresent;
+ pr_debug("%s: compatibleVersion %d compressionLevel %d formatFlags %d blocksPerFrame %d finalFrameBlocks %d totalFrames %d bitsPerSample %d numChannels %d sampleRate %d seekTablePresent %d\n",
+ __func__, ape_config->compatibleVersion,
+ ape_config->compressionLevel,
+ ape_config->formatFlags,
+ ape_config->blocksPerFrame,
+ ape_config->finalFrameBlocks,
+ ape_config->totalFrames,
+ ape_config->bitsPerSample,
+ ape_config->numChannels,
+ ape_config->sampleRate,
+ ape_config->seekTablePresent);
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_ape(audio->ac, &ape_cfg,
+ audio->ac->stream_id);
+ if (rc < 0) {
+ pr_err("cmd media format block failed\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_APE_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_ape_config))) {
+ pr_err("%s:copy_to_user for AUDIO_GET_APE_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_APE_CONFIG: {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_ape_config))) {
+ pr_err("%s:copy_from_user for AUDIO_SET_APE_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("Failed in utils_ioctl: %d\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_ape_config_32 {
+ u16 compatibleVersion;
+ u16 compressionLevel;
+ u32 formatFlags;
+ u32 blocksPerFrame;
+ u32 finalFrameBlocks;
+ u32 totalFrames;
+ u16 bitsPerSample;
+ u16 numChannels;
+ u32 sampleRate;
+ u32 seekTablePresent;
+
+};
+
+enum {
+ AUDIO_GET_APE_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_ape_config_32),
+ AUDIO_SET_APE_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_ape_config_32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_APE_CONFIG_32: {
+ struct msm_audio_ape_config *ape_config;
+ struct msm_audio_ape_config_32 ape_config_32;
+
+ memset(&ape_config_32, 0, sizeof(ape_config_32));
+
+ ape_config = (struct msm_audio_ape_config *)audio->codec_cfg;
+ ape_config_32.compatibleVersion = ape_config->compatibleVersion;
+ ape_config_32.compressionLevel =
+ ape_config->compressionLevel;
+ ape_config_32.formatFlags = ape_config->formatFlags;
+ ape_config_32.blocksPerFrame = ape_config->blocksPerFrame;
+ ape_config_32.finalFrameBlocks = ape_config->finalFrameBlocks;
+ ape_config_32.totalFrames = ape_config->totalFrames;
+ ape_config_32.bitsPerSample = ape_config->bitsPerSample;
+ ape_config_32.numChannels = ape_config->numChannels;
+ ape_config_32.sampleRate = ape_config->sampleRate;
+ ape_config_32.seekTablePresent = ape_config->seekTablePresent;
+
+ if (copy_to_user((void *)arg, &ape_config_32,
+ sizeof(ape_config_32))) {
+ pr_err("%s: copy_to_user for GET_APE_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_APE_CONFIG_32: {
+ struct msm_audio_ape_config *ape_config;
+ struct msm_audio_ape_config_32 ape_config_32;
+
+ if (copy_from_user(&ape_config_32, (void *)arg,
+ sizeof(ape_config_32))) {
+ pr_err("%s: copy_from_user for SET_APE_CONFIG_32 failed\n"
+ , __func__);
+ rc = -EFAULT;
+ break;
+ }
+ ape_config = (struct msm_audio_ape_config *)audio->codec_cfg;
+ ape_config->compatibleVersion = ape_config_32.compatibleVersion;
+ ape_config->compressionLevel =
+ ape_config_32.compressionLevel;
+ ape_config->formatFlags = ape_config_32.formatFlags;
+ ape_config->blocksPerFrame = ape_config_32.blocksPerFrame;
+ ape_config->finalFrameBlocks = ape_config_32.finalFrameBlocks;
+ ape_config->totalFrames = ape_config_32.totalFrames;
+ ape_config->bitsPerSample = ape_config_32.bitsPerSample;
+ ape_config->numChannels = ape_config_32.numChannels;
+ ape_config->sampleRate = ape_config_32.sampleRate;
+ ape_config->seekTablePresent = ape_config_32.seekTablePresent;
+
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("Failed in utils_ioctl: %d\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_ape_" + 5];
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+ if (!audio)
+ return -ENOMEM;
+
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_ape_config),
+ GFP_KERNEL);
+ if (!audio->codec_cfg) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_ape_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_ape_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_APE);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open APE decoder, expected frames is always 1*/
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_APE);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "msm_ape_%04x", audio->ac->session);
+ audio->dentry = config_debugfs_create_file(name, (void *)audio);
+
+ if (IS_ERR_OR_NULL(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+ pr_debug("%s:apedec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_ape_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl
+};
+
+static struct miscdevice audio_ape_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_ape",
+ .fops = &audio_ape_fops,
+};
+
+static int __init audio_ape_init(void)
+{
+ int ret = misc_register(&audio_ape_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_ape_misc.this_device, true);
+ audio_ape_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_ape_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_ape_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_evrc.c b/drivers/misc/qcom/qdsp6v2/audio_evrc.c
new file mode 100644
index 0000000..8776231
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_evrc.c
@@ -0,0 +1,184 @@
+/* evrc audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_evrc_misc;
+static struct ws_mgr audio_evrc_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_evrc_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_evrc_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_evrc_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_evrc_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_EVRC);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_EVRC);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_evrc_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_evrc_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_evrc_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+static struct miscdevice audio_evrc_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_evrc",
+ .fops = &audio_evrc_fops,
+};
+
+static int __init audio_evrc_init(void)
+{
+ int ret = misc_register(&audio_evrc_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_evrc_misc.this_device, true);
+ audio_evrc_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_evrc_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_evrc_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c b/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c
new file mode 100644
index 0000000..24f87e4
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c
@@ -0,0 +1,396 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/msm_audio_g711_dec.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_g711alaw_misc;
+static struct ws_mgr audio_g711_ws_mgr;
+
+static const struct file_operations audio_g711_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+
+static struct dentry *config_debugfs_create_file(const char *name, void *data)
+{
+ return debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)data, &audio_g711_debug_fops);
+}
+
+static int g711_channel_map(u8 *channel_mapping, uint32_t channels);
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_g711_dec_cfg g711_dec_cfg;
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg));
+
+ if (g711_channel_map(channel_mapping,
+ audio->pcm_cfg.channel_count)) {
+ pr_err("%s: setting channel map failed %d\n",
+ __func__, audio->pcm_cfg.channel_count);
+ }
+
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count,
+ 16, /*bits per sample*/
+ false, false, channel_mapping);
+ if (rc < 0) {
+ pr_err("%s: pcm output block config failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_cfg.sample_rate = g711_dec_config->sample_rate;
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg,
+ audio->ac->stream_id);
+ if (rc < 0) {
+ pr_err("%s: cmd media format block failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s: Audio Start procedure failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START success enable[%d]\n",
+ __func__, audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_G711_DEC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_g711_dec_config))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_DEC_CONFIG: {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_g711_dec_config))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ default: {
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n",
+ __func__, rc, cmd);
+ break;
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_g711_dec_config_32 {
+ u32 sample_rate;
+};
+
+enum {
+ AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32),
+ AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_G711_DEC_CONFIG_32: {
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ struct msm_audio_g711_dec_config_32 g711_dec_config_32;
+
+ memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
+
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_config_32.sample_rate = g711_dec_config->sample_rate;
+
+ if (copy_to_user((void *)arg, &g711_dec_config_32,
+ sizeof(g711_dec_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_DEC_CONFIG_32: {
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ struct msm_audio_g711_dec_config_32 g711_dec_config_32;
+
+ memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
+
+ if (copy_from_user(&g711_dec_config_32, (void *)arg,
+ sizeof(g711_dec_config_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_config->sample_rate = g711_dec_config_32.sample_rate;
+
+ break;
+ }
+ default: {
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n",
+ __func__, rc, cmd);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_g711_" + 5];
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (!audio)
+ return -ENOMEM;
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config),
+ GFP_KERNEL);
+ if (!audio->codec_cfg) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_g711alaw_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_g711_ws_mgr;
+
+ init_waitqueue_head(&audio->event_wait);
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */ /*foramt:G711_ALAW*/
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_G711_ALAW_FS);
+ if (rc < 0) {
+ pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc);
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open G711 decoder, expected frames is always 1*/
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_G711_ALAW_FS);
+ if (rc < 0) {
+ pr_err("%s: T mode Open failed rc=%d\n", __func__, rc);
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("%s: %d mode is not supported mode\n",
+ __func__, file->f_mode);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session);
+ audio->dentry = config_debugfs_create_file(name, (void *)audio);
+
+ if (IS_ERR_OR_NULL(audio->dentry))
+ pr_debug("%s: debugfs_create_file failed\n", __func__);
+ pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static int g711_channel_map(u8 *channel_mapping, uint32_t channels)
+{
+ u8 *lchannel_mapping;
+
+ lchannel_mapping = channel_mapping;
+ pr_debug("%s: channels passed: %d\n", __func__, channels);
+ if (channels == 1) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channels == 3) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ } else if (channels == 4) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_CS;
+ } else if (channels == 5) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ } else if (channels == 7) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_CS;
+ lchannel_mapping[6] = PCM_CHANNEL_LFE;
+ } else if (channels == 8) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FLC;
+ lchannel_mapping[2] = PCM_CHANNEL_FRC;
+ lchannel_mapping[3] = PCM_CHANNEL_FL;
+ lchannel_mapping[4] = PCM_CHANNEL_FR;
+ lchannel_mapping[5] = PCM_CHANNEL_LS;
+ lchannel_mapping[6] = PCM_CHANNEL_RS;
+ lchannel_mapping[7] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct file_operations audio_g711_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .compat_ioctl = audio_compat_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+static struct miscdevice audio_g711alaw_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_g711alaw",
+ .fops = &audio_g711_fops,
+};
+
+static int __init audio_g711alaw_init(void)
+{
+ int ret = misc_register(&audio_g711alaw_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_g711alaw_misc.this_device, true);
+ audio_g711_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_g711_ws_mgr.ws_lock);
+
+ return ret;
+}
+static void __exit audio_g711alaw_exit(void)
+{
+ misc_deregister(&audio_g711alaw_misc);
+ mutex_destroy(&audio_g711_ws_mgr.ws_lock);
+}
+
+device_initcall(audio_g711alaw_init);
+__exitcall(audio_g711alaw_exit);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c b/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c
new file mode 100644
index 0000000..10d3680
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c
@@ -0,0 +1,396 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/msm_audio_g711_dec.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_g711mlaw_misc;
+static struct ws_mgr audio_g711_ws_mgr;
+
+static const struct file_operations audio_g711_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+
+static struct dentry *config_debugfs_create_file(const char *name, void *data)
+{
+ return debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)data, &audio_g711_debug_fops);
+}
+
+static int g711_channel_map(u8 *channel_mapping, uint32_t channels);
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_g711_dec_cfg g711_dec_cfg;
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg));
+
+ if (g711_channel_map(channel_mapping,
+ audio->pcm_cfg.channel_count)) {
+ pr_err("%s: setting channel map failed %d\n",
+ __func__, audio->pcm_cfg.channel_count);
+ }
+
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count,
+ 16, /*bits per sample*/
+ false, false, channel_mapping);
+ if (rc < 0) {
+ pr_err("%s: pcm output block config failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_cfg.sample_rate = g711_dec_config->sample_rate;
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg,
+ audio->ac->stream_id);
+ if (rc < 0) {
+ pr_err("%s: cmd media format block failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s: Audio Start procedure failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START success enable[%d]\n",
+ __func__, audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_G711_DEC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_g711_dec_config))) {
+ pr_err("%s: AUDIO_GET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_DEC_CONFIG: {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_g711_dec_config))) {
+ pr_err("%s: AUDIO_SET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ default: {
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n",
+ __func__, rc, cmd);
+ break;
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_g711_dec_config_32 {
+ u32 sample_rate;
+};
+
+enum {
+ AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32),
+ AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_G711_DEC_CONFIG_32: {
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ struct msm_audio_g711_dec_config_32 g711_dec_config_32;
+
+ memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
+
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_config_32.sample_rate = g711_dec_config->sample_rate;
+
+ if (copy_to_user((void *)arg, &g711_dec_config_32,
+ sizeof(g711_dec_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_DEC_CONFIG_32: {
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ struct msm_audio_g711_dec_config_32 g711_dec_config_32;
+
+ memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
+
+ if (copy_from_user(&g711_dec_config_32, (void *)arg,
+ sizeof(g711_dec_config_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_config->sample_rate = g711_dec_config_32.sample_rate;
+
+ break;
+ }
+ default: {
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n",
+ __func__, rc, cmd);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_g711_" + 5];
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (!audio)
+ return -ENOMEM;
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config),
+ GFP_KERNEL);
+ if (!audio->codec_cfg) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_g711mlaw_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_g711_ws_mgr;
+
+ init_waitqueue_head(&audio->event_wait);
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */ /*foramt:G711_ALAW*/
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_G711_MLAW_FS);
+ if (rc < 0) {
+ pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc);
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open G711 decoder, expected frames is always 1*/
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_G711_MLAW_FS);
+ if (rc < 0) {
+ pr_err("%s: T mode Open failed rc=%d\n", __func__, rc);
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("%s: %d mode is not supported\n", __func__,
+ file->f_mode);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session);
+ audio->dentry = config_debugfs_create_file(name, (void *)audio);
+
+ if (IS_ERR_OR_NULL(audio->dentry))
+ pr_debug("%s: debugfs_create_file failed\n", __func__);
+ pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static int g711_channel_map(u8 *channel_mapping, uint32_t channels)
+{
+ u8 *lchannel_mapping;
+
+ lchannel_mapping = channel_mapping;
+ pr_debug("%s: channels passed: %d\n", __func__, channels);
+ if (channels == 1) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channels == 3) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ } else if (channels == 4) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_CS;
+ } else if (channels == 5) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ } else if (channels == 7) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_CS;
+ lchannel_mapping[6] = PCM_CHANNEL_LFE;
+ } else if (channels == 8) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FLC;
+ lchannel_mapping[2] = PCM_CHANNEL_FRC;
+ lchannel_mapping[3] = PCM_CHANNEL_FL;
+ lchannel_mapping[4] = PCM_CHANNEL_FR;
+ lchannel_mapping[5] = PCM_CHANNEL_LS;
+ lchannel_mapping[6] = PCM_CHANNEL_RS;
+ lchannel_mapping[7] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct file_operations audio_g711_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .compat_ioctl = audio_compat_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+static struct miscdevice audio_g711mlaw_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_g711mlaw",
+ .fops = &audio_g711_fops,
+};
+
+static int __init audio_g711mlaw_init(void)
+{
+ int ret = misc_register(&audio_g711mlaw_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_g711mlaw_misc.this_device, true);
+ audio_g711_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_g711_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+static void __exit audio_g711mlaw_exit(void)
+{
+ misc_deregister(&audio_g711mlaw_misc);
+ mutex_destroy(&audio_g711_ws_mgr.ws_lock);
+}
+
+device_initcall(audio_g711mlaw_init);
+__exitcall(audio_g711mlaw_exit);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
new file mode 100644
index 0000000..c1d792b
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/msm_audio.h>
+#include <linux/compat.h>
+#include "q6audio_common.h"
+#include "audio_utils_aio.h"
+#include <sound/msm-audio-effects-q6-v2.h>
+#include <sound/msm-dts-eagle.h>
+
+#define MAX_CHANNELS_SUPPORTED 8
+#define WAIT_TIMEDOUT_DURATION_SECS 1
+
+struct q6audio_effects {
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+
+ struct audio_client *ac;
+ struct msm_hwacc_effects_config config;
+
+ atomic_t in_count;
+ atomic_t out_count;
+
+ int opened;
+ int started;
+ int buf_alloc;
+ struct msm_nt_eff_all_config audio_effects;
+};
+
+static void audio_effects_init_pp(struct audio_client *ac)
+{
+ int ret = 0;
+ struct asm_softvolume_params softvol = {
+ .period = SOFT_VOLUME_PERIOD,
+ .step = SOFT_VOLUME_STEP,
+ .rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
+ };
+
+ if (!ac) {
+ pr_err("%s: audio client null to init pp\n", __func__);
+ return;
+ }
+ switch (ac->topology) {
+ case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
+
+ ret = q6asm_set_softvolume_v2(ac, &softvol,
+ SOFT_VOLUME_INSTANCE_1);
+ if (ret < 0)
+ pr_err("%s: Send SoftVolume1 Param failed ret=%d\n",
+ __func__, ret);
+ ret = q6asm_set_softvolume_v2(ac, &softvol,
+ SOFT_VOLUME_INSTANCE_2);
+ if (ret < 0)
+ pr_err("%s: Send SoftVolume2 Param failed ret=%d\n",
+ __func__, ret);
+
+ msm_dts_eagle_init_master_module(ac);
+
+ break;
+ default:
+ ret = q6asm_set_softvolume_v2(ac, &softvol,
+ SOFT_VOLUME_INSTANCE_1);
+ if (ret < 0)
+ pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+ __func__, ret);
+ break;
+ }
+}
+
+static void audio_effects_deinit_pp(struct audio_client *ac)
+{
+ if (!ac) {
+ pr_err("%s: audio client null to deinit pp\n", __func__);
+ return;
+ }
+ switch (ac->topology) {
+ case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
+ msm_dts_eagle_deinit_master_module(ac);
+ break;
+ default:
+ break;
+ }
+}
+
+static void audio_effects_event_handler(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_effects *effects;
+
+ if (!payload || !priv) {
+ pr_err("%s: invalid data to handle events, payload: %pK, priv: %pK\n",
+ __func__, payload, priv);
+ return;
+ }
+
+ effects = (struct q6audio_effects *)priv;
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE_V2: {
+ atomic_inc(&effects->out_count);
+ wake_up(&effects->write_wait);
+ break;
+ }
+ case ASM_DATA_EVENT_READ_DONE_V2: {
+ atomic_inc(&effects->in_count);
+ wake_up(&effects->read_wait);
+ break;
+ }
+ case APR_BASIC_RSP_RESULT: {
+ pr_debug("%s: APR_BASIC_RSP_RESULT Cmd[0x%x] Status[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ switch (payload[0]) {
+ case ASM_SESSION_CMD_RUN_V2:
+ pr_debug("ASM_SESSION_CMD_RUN_V2\n");
+ break;
+ default:
+ pr_debug("%s: Payload = [0x%x] stat[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ break;
+ }
+ break;
+ }
+ default:
+ pr_debug("%s: Unhandled Event 0x%x token = 0x%x\n",
+ __func__, opcode, token);
+ break;
+ }
+}
+
+static int audio_effects_shared_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_effects *effects = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s: AUDIO_START\n", __func__);
+
+ rc = q6asm_open_read_write_v2(effects->ac,
+ FORMAT_LINEAR_PCM,
+ FORMAT_MULTI_CHANNEL_LINEAR_PCM,
+ effects->config.meta_mode_enabled,
+ effects->config.output.bits_per_sample,
+ true /*overwrite topology*/,
+ ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER);
+ if (rc < 0) {
+ pr_err("%s: Open failed for hw accelerated effects:rc=%d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ goto ioctl_fail;
+ }
+ effects->opened = 1;
+
+ pr_debug("%s: dec buf size: %d, num_buf: %d, enc buf size: %d, num_buf: %d\n",
+ __func__, effects->config.output.buf_size,
+ effects->config.output.num_buf,
+ effects->config.input.buf_size,
+ effects->config.input.num_buf);
+ rc = q6asm_audio_client_buf_alloc_contiguous(IN, effects->ac,
+ effects->config.output.buf_size,
+ effects->config.output.num_buf);
+ if (rc < 0) {
+ pr_err("%s: Write buffer Allocation failed rc = %d\n",
+ __func__, rc);
+ rc = -ENOMEM;
+ goto ioctl_fail;
+ }
+ atomic_set(&effects->in_count, effects->config.input.num_buf);
+ rc = q6asm_audio_client_buf_alloc_contiguous(OUT, effects->ac,
+ effects->config.input.buf_size,
+ effects->config.input.num_buf);
+ if (rc < 0) {
+ pr_err("%s: Read buffer Allocation failed rc = %d\n",
+ __func__, rc);
+ rc = -ENOMEM;
+ goto readbuf_fail;
+ }
+ atomic_set(&effects->out_count, effects->config.output.num_buf);
+ effects->buf_alloc = 1;
+
+ pr_debug("%s: enc: sample_rate: %d, num_channels: %d\n",
+ __func__, effects->config.input.sample_rate,
+ effects->config.input.num_channels);
+ rc = q6asm_enc_cfg_blk_pcm(effects->ac,
+ effects->config.input.sample_rate,
+ effects->config.input.num_channels);
+ if (rc < 0) {
+ pr_err("%s: pcm read block config failed\n", __func__);
+ rc = -EINVAL;
+ goto cfg_fail;
+ }
+ pr_debug("%s: dec: sample_rate: %d, num_channels: %d, bit_width: %d\n",
+ __func__, effects->config.output.sample_rate,
+ effects->config.output.num_channels,
+ effects->config.output.bits_per_sample);
+ rc = q6asm_media_format_block_pcm_format_support(
+ effects->ac, effects->config.output.sample_rate,
+ effects->config.output.num_channels,
+ effects->config.output.bits_per_sample);
+ if (rc < 0) {
+ pr_err("%s: pcm write format block config failed\n",
+ __func__);
+ rc = -EINVAL;
+ goto cfg_fail;
+ }
+
+ audio_effects_init_pp(effects->ac);
+
+ rc = q6asm_run(effects->ac, 0x00, 0x00, 0x00);
+ if (!rc)
+ effects->started = 1;
+ else {
+ effects->started = 0;
+ pr_err("%s: ASM run state failed\n", __func__);
+ }
+ break;
+ }
+ case AUDIO_EFFECTS_WRITE: {
+ char *bufptr = NULL;
+ uint32_t idx = 0;
+ uint32_t size = 0;
+
+ if (!effects->started) {
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+
+ rc = wait_event_timeout(effects->write_wait,
+ atomic_read(&effects->out_count),
+ WAIT_TIMEDOUT_DURATION_SECS * HZ);
+ if (!rc) {
+ pr_err("%s: write wait_event_timeout\n", __func__);
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+ if (!atomic_read(&effects->out_count)) {
+ pr_err("%s: pcm stopped out_count 0\n", __func__);
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+
+ bufptr = q6asm_is_cpu_buf_avail(IN, effects->ac, &size, &idx);
+ if (bufptr) {
+ if ((effects->config.buf_cfg.output_len > size) ||
+ copy_from_user(bufptr, (void *)arg,
+ effects->config.buf_cfg.output_len)) {
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+ rc = q6asm_write(effects->ac,
+ effects->config.buf_cfg.output_len,
+ 0, 0, NO_TIMESTAMP);
+ if (rc < 0) {
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+ atomic_dec(&effects->out_count);
+ } else {
+ pr_err("%s: AUDIO_EFFECTS_WRITE: Buffer dropped\n",
+ __func__);
+ }
+ break;
+ }
+ case AUDIO_EFFECTS_READ: {
+ char *bufptr = NULL;
+ uint32_t idx = 0;
+ uint32_t size = 0;
+
+ if (!effects->started) {
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+
+ atomic_set(&effects->in_count, 0);
+
+ q6asm_read_v2(effects->ac, effects->config.buf_cfg.input_len);
+ /* Read might fail initially, don't error out */
+ if (rc < 0)
+ pr_err("%s: read failed\n", __func__);
+
+ rc = wait_event_timeout(effects->read_wait,
+ atomic_read(&effects->in_count),
+ WAIT_TIMEDOUT_DURATION_SECS * HZ);
+ if (!rc) {
+ pr_err("%s: read wait_event_timeout\n", __func__);
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+ if (!atomic_read(&effects->in_count)) {
+ pr_err("%s: pcm stopped in_count 0\n", __func__);
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+
+ bufptr = q6asm_is_cpu_buf_avail(OUT, effects->ac, &size, &idx);
+ if (bufptr) {
+ if (!((void *)arg)) {
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+ if ((effects->config.buf_cfg.input_len > size) ||
+ copy_to_user((void *)arg, bufptr,
+ effects->config.buf_cfg.input_len)) {
+ rc = -EFAULT;
+ goto ioctl_fail;
+ }
+ }
+ break;
+ }
+ default:
+ pr_err("%s: Invalid effects config module\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ioctl_fail:
+ return rc;
+readbuf_fail:
+ q6asm_audio_client_buf_free_contiguous(IN,
+ effects->ac);
+ return rc;
+cfg_fail:
+ q6asm_audio_client_buf_free_contiguous(IN,
+ effects->ac);
+ q6asm_audio_client_buf_free_contiguous(OUT,
+ effects->ac);
+ effects->buf_alloc = 0;
+ return rc;
+}
+
+static long audio_effects_set_pp_param(struct q6audio_effects *effects,
+ long *values)
+{
+ int rc = 0;
+ int effects_module = values[0];
+
+ switch (effects_module) {
+ case VIRTUALIZER_MODULE:
+ pr_debug("%s: VIRTUALIZER_MODULE\n", __func__);
+ if (msm_audio_effects_is_effmodule_supp_in_top(
+ effects_module, effects->ac->topology))
+ msm_audio_effects_virtualizer_handler(
+ effects->ac,
+ &(effects->audio_effects.virtualizer),
+ (long *)&values[1]);
+ break;
+ case REVERB_MODULE:
+ pr_debug("%s: REVERB_MODULE\n", __func__);
+ if (msm_audio_effects_is_effmodule_supp_in_top(
+ effects_module, effects->ac->topology))
+ msm_audio_effects_reverb_handler(effects->ac,
+ &(effects->audio_effects.reverb),
+ (long *)&values[1]);
+ break;
+ case BASS_BOOST_MODULE:
+ pr_debug("%s: BASS_BOOST_MODULE\n", __func__);
+ if (msm_audio_effects_is_effmodule_supp_in_top(
+ effects_module, effects->ac->topology))
+ msm_audio_effects_bass_boost_handler(
+ effects->ac,
+ &(effects->audio_effects.bass_boost),
+ (long *)&values[1]);
+ break;
+ case PBE_MODULE:
+ pr_debug("%s: PBE_MODULE\n", __func__);
+ if (msm_audio_effects_is_effmodule_supp_in_top(
+ effects_module, effects->ac->topology))
+ msm_audio_effects_pbe_handler(
+ effects->ac,
+ &(effects->audio_effects.pbe),
+ (long *)&values[1]);
+ break;
+ case EQ_MODULE:
+ pr_debug("%s: EQ_MODULE\n", __func__);
+ if (msm_audio_effects_is_effmodule_supp_in_top(
+ effects_module, effects->ac->topology))
+ msm_audio_effects_popless_eq_handler(
+ effects->ac,
+ &(effects->audio_effects.equalizer),
+ (long *)&values[1]);
+ break;
+ case SOFT_VOLUME_MODULE:
+ pr_debug("%s: SA PLUS VOLUME_MODULE\n", __func__);
+ msm_audio_effects_volume_handler_v2(effects->ac,
+ &(effects->audio_effects.saplus_vol),
+ (long *)&values[1], SOFT_VOLUME_INSTANCE_1);
+ break;
+ case SOFT_VOLUME2_MODULE:
+ pr_debug("%s: TOPOLOGY SWITCH VOLUME MODULE\n",
+ __func__);
+ if (msm_audio_effects_is_effmodule_supp_in_top(
+ effects_module, effects->ac->topology))
+ msm_audio_effects_volume_handler_v2(effects->ac,
+ &(effects->audio_effects.topo_switch_vol),
+ (long *)&values[1], SOFT_VOLUME_INSTANCE_2);
+ break;
+ case DTS_EAGLE_MODULE_ENABLE:
+ pr_debug("%s: DTS_EAGLE_MODULE_ENABLE\n", __func__);
+ if (msm_audio_effects_is_effmodule_supp_in_top(
+ effects_module, effects->ac->topology)) {
+ /*
+ * HPX->OFF: first disable HPX and then
+ * enable SA+
+ * HPX->ON: first disable SA+ and then
+ * enable HPX
+ */
+ bool hpx_state = (bool)values[1];
+
+ if (hpx_state)
+ msm_audio_effects_enable_extn(effects->ac,
+ &(effects->audio_effects),
+ false);
+ msm_dts_eagle_enable_asm(effects->ac,
+ hpx_state,
+ AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
+ msm_dts_eagle_enable_asm(effects->ac,
+ hpx_state,
+ AUDPROC_MODULE_ID_DTS_HPX_POSTMIX);
+ if (!hpx_state)
+ msm_audio_effects_enable_extn(effects->ac,
+ &(effects->audio_effects),
+ true);
+ }
+ break;
+ default:
+ pr_err("%s: Invalid effects config module\n", __func__);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static long audio_effects_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_effects *effects = file->private_data;
+ int rc = 0;
+ long argvalues[MAX_PP_PARAMS_SZ] = {0};
+
+ switch (cmd) {
+ case AUDIO_SET_EFFECTS_CONFIG: {
+ pr_debug("%s: AUDIO_SET_EFFECTS_CONFIG\n", __func__);
+ memset(&effects->config, 0, sizeof(effects->config));
+ if (copy_from_user(&effects->config, (void *)arg,
+ sizeof(effects->config))) {
+ pr_err("%s: copy from user for AUDIO_SET_EFFECTS_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ pr_debug("%s: write buf_size: %d, num_buf: %d, sample_rate: %d, channel: %d\n",
+ __func__, effects->config.output.buf_size,
+ effects->config.output.num_buf,
+ effects->config.output.sample_rate,
+ effects->config.output.num_channels);
+ pr_debug("%s: read buf_size: %d, num_buf: %d, sample_rate: %d, channel: %d\n",
+ __func__, effects->config.input.buf_size,
+ effects->config.input.num_buf,
+ effects->config.input.sample_rate,
+ effects->config.input.num_channels);
+ break;
+ }
+ case AUDIO_EFFECTS_SET_BUF_LEN: {
+ if (copy_from_user(&effects->config.buf_cfg, (void *)arg,
+ sizeof(effects->config.buf_cfg))) {
+ pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ pr_debug("%s: write buf len: %d, read buf len: %d\n",
+ __func__, effects->config.buf_cfg.output_len,
+ effects->config.buf_cfg.input_len);
+ break;
+ }
+ case AUDIO_EFFECTS_GET_BUF_AVAIL: {
+ struct msm_hwacc_buf_avail buf_avail;
+
+ buf_avail.input_num_avail = atomic_read(&effects->in_count);
+ buf_avail.output_num_avail = atomic_read(&effects->out_count);
+ pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
+ __func__, buf_avail.output_num_avail,
+ buf_avail.input_num_avail);
+ if (copy_to_user((void *)arg, &buf_avail,
+ sizeof(buf_avail))) {
+ pr_err("%s: copy to user for AUDIO_EFFECTS_GET_NUM_BUF_AVAIL failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_EFFECTS_SET_PP_PARAMS: {
+ if (copy_from_user(argvalues, (void *)arg,
+ MAX_PP_PARAMS_SZ*sizeof(long))) {
+ pr_err("%s: copy from user for pp params failed\n",
+ __func__);
+ return -EFAULT;
+ }
+ rc = audio_effects_set_pp_param(effects, argvalues);
+ break;
+ }
+ default:
+ pr_debug("%s: Calling shared ioctl\n", __func__);
+ rc = audio_effects_shared_ioctl(file, cmd, arg);
+ break;
+ }
+ if (rc)
+ pr_err("%s: cmd 0x%x failed\n", __func__, cmd);
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_hwacc_data_config32 {
+ __u32 buf_size;
+ __u32 num_buf;
+ __u32 num_channels;
+ __u8 channel_map[MAX_CHANNELS_SUPPORTED];
+ __u32 sample_rate;
+ __u32 bits_per_sample;
+};
+
+struct msm_hwacc_buf_cfg32 {
+ __u32 input_len;
+ __u32 output_len;
+};
+
+struct msm_hwacc_buf_avail32 {
+ __u32 input_num_avail;
+ __u32 output_num_avail;
+};
+
+struct msm_hwacc_effects_config32 {
+ struct msm_hwacc_data_config32 input;
+ struct msm_hwacc_data_config32 output;
+ struct msm_hwacc_buf_cfg32 buf_cfg;
+ __u32 meta_mode_enabled;
+ __u32 overwrite_topology;
+ __s32 topology;
+};
+
+enum {
+ AUDIO_SET_EFFECTS_CONFIG32 = _IOW(AUDIO_IOCTL_MAGIC, 99,
+ struct msm_hwacc_effects_config32),
+ AUDIO_EFFECTS_SET_BUF_LEN32 = _IOW(AUDIO_IOCTL_MAGIC, 100,
+ struct msm_hwacc_buf_cfg32),
+ AUDIO_EFFECTS_GET_BUF_AVAIL32 = _IOW(AUDIO_IOCTL_MAGIC, 101,
+ struct msm_hwacc_buf_avail32),
+ AUDIO_EFFECTS_WRITE32 = _IOW(AUDIO_IOCTL_MAGIC, 102, compat_uptr_t),
+ AUDIO_EFFECTS_READ32 = _IOWR(AUDIO_IOCTL_MAGIC, 103, compat_uptr_t),
+ AUDIO_EFFECTS_SET_PP_PARAMS32 = _IOW(AUDIO_IOCTL_MAGIC, 104,
+ compat_uptr_t),
+ AUDIO_START32 = _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned int),
+};
+
+static long audio_effects_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_effects *effects = file->private_data;
+ int rc = 0, i;
+
+ switch (cmd) {
+ case AUDIO_SET_EFFECTS_CONFIG32: {
+ struct msm_hwacc_effects_config32 config32;
+ struct msm_hwacc_effects_config *config = &effects->config;
+
+ memset(&effects->config, 0, sizeof(effects->config));
+ if (copy_from_user(&config32, (void *)arg,
+ sizeof(config32))) {
+ pr_err("%s: copy to user for AUDIO_SET_EFFECTS_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ config->input.buf_size = config32.input.buf_size;
+ config->input.num_buf = config32.input.num_buf;
+ config->input.num_channels = config32.input.num_channels;
+ config->input.sample_rate = config32.input.sample_rate;
+ config->input.bits_per_sample = config32.input.bits_per_sample;
+ config->input.buf_size = config32.input.buf_size;
+ for (i = 0; i < MAX_CHANNELS_SUPPORTED; i++)
+ config->input.channel_map[i] =
+ config32.input.channel_map[i];
+ config->output.buf_size = config32.output.buf_size;
+ config->output.num_buf = config32.output.num_buf;
+ config->output.num_channels = config32.output.num_channels;
+ config->output.sample_rate = config32.output.sample_rate;
+ config->output.bits_per_sample =
+ config32.output.bits_per_sample;
+ config->output.buf_size = config32.output.buf_size;
+ for (i = 0; i < MAX_CHANNELS_SUPPORTED; i++)
+ config->output.channel_map[i] =
+ config32.output.channel_map[i];
+ config->buf_cfg.input_len = config32.buf_cfg.input_len;
+ config->buf_cfg.output_len = config32.buf_cfg.output_len;
+ config->meta_mode_enabled = config32.meta_mode_enabled;
+ config->overwrite_topology = config32.overwrite_topology;
+ config->topology = config32.topology;
+ pr_debug("%s: write buf_size: %d, num_buf: %d, sample_rate: %d, channels: %d\n",
+ __func__, effects->config.output.buf_size,
+ effects->config.output.num_buf,
+ effects->config.output.sample_rate,
+ effects->config.output.num_channels);
+ pr_debug("%s: read buf_size: %d, num_buf: %d, sample_rate: %d, channels: %d\n",
+ __func__, effects->config.input.buf_size,
+ effects->config.input.num_buf,
+ effects->config.input.sample_rate,
+ effects->config.input.num_channels);
+ break;
+ }
+ case AUDIO_EFFECTS_SET_BUF_LEN32: {
+ struct msm_hwacc_buf_cfg32 buf_cfg32;
+ struct msm_hwacc_effects_config *config = &effects->config;
+
+ if (copy_from_user(&buf_cfg32, (void *)arg,
+ sizeof(buf_cfg32))) {
+ pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ config->buf_cfg.input_len = buf_cfg32.input_len;
+ config->buf_cfg.output_len = buf_cfg32.output_len;
+ pr_debug("%s: write buf len: %d, read buf len: %d\n",
+ __func__, effects->config.buf_cfg.output_len,
+ effects->config.buf_cfg.input_len);
+ break;
+ }
+ case AUDIO_EFFECTS_GET_BUF_AVAIL32: {
+ struct msm_hwacc_buf_avail32 buf_avail;
+
+ memset(&buf_avail, 0, sizeof(buf_avail));
+
+ buf_avail.input_num_avail = atomic_read(&effects->in_count);
+ buf_avail.output_num_avail = atomic_read(&effects->out_count);
+ pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
+ __func__, buf_avail.output_num_avail,
+ buf_avail.input_num_avail);
+ if (copy_to_user((void *)arg, &buf_avail,
+ sizeof(buf_avail))) {
+ pr_err("%s: copy to user for AUDIO_EFFECTS_GET_NUM_BUF_AVAIL failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_EFFECTS_SET_PP_PARAMS32: {
+ long argvalues[MAX_PP_PARAMS_SZ] = {0};
+ int argvalues32[MAX_PP_PARAMS_SZ] = {0};
+
+ if (copy_from_user(argvalues32, (void *)arg,
+ MAX_PP_PARAMS_SZ*sizeof(int))) {
+ pr_err("%s: copy from user failed for pp params\n",
+ __func__);
+ return -EFAULT;
+ }
+ for (i = 0; i < MAX_PP_PARAMS_SZ; i++)
+ argvalues[i] = argvalues32[i];
+
+ rc = audio_effects_set_pp_param(effects, argvalues);
+ break;
+ }
+ case AUDIO_START32: {
+ rc = audio_effects_shared_ioctl(file, AUDIO_START, arg);
+ break;
+ }
+ case AUDIO_EFFECTS_WRITE32: {
+ rc = audio_effects_shared_ioctl(file, AUDIO_EFFECTS_WRITE, arg);
+ break;
+ }
+ case AUDIO_EFFECTS_READ32: {
+ rc = audio_effects_shared_ioctl(file, AUDIO_EFFECTS_READ, arg);
+ break;
+ }
+ default:
+ pr_debug("%s: unhandled ioctl\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+#endif
+
+static int audio_effects_release(struct inode *inode, struct file *file)
+{
+ struct q6audio_effects *effects = file->private_data;
+ int rc = 0;
+
+ if (!effects) {
+ pr_err("%s: effect is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (effects->opened) {
+ rc = wait_event_timeout(effects->write_wait,
+ atomic_read(&effects->out_count),
+ WAIT_TIMEDOUT_DURATION_SECS * HZ);
+ if (!rc)
+ pr_err("%s: write wait_event_timeout failed\n",
+ __func__);
+ rc = wait_event_timeout(effects->read_wait,
+ atomic_read(&effects->in_count),
+ WAIT_TIMEDOUT_DURATION_SECS * HZ);
+ if (!rc)
+ pr_err("%s: read wait_event_timeout failed\n",
+ __func__);
+ rc = q6asm_cmd(effects->ac, CMD_CLOSE);
+ if (rc < 0)
+ pr_err("%s[%pK]:Failed to close the session rc=%d\n",
+ __func__, effects, rc);
+ effects->opened = 0;
+ effects->started = 0;
+
+ audio_effects_deinit_pp(effects->ac);
+ }
+
+ if (effects->buf_alloc) {
+ q6asm_audio_client_buf_free_contiguous(IN, effects->ac);
+ q6asm_audio_client_buf_free_contiguous(OUT, effects->ac);
+ }
+ q6asm_audio_client_free(effects->ac);
+
+ kfree(effects);
+
+ pr_debug("%s: close session success\n", __func__);
+ return rc;
+}
+
+static int audio_effects_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_effects *effects;
+ int rc = 0;
+
+ effects = kzalloc(sizeof(struct q6audio_effects), GFP_KERNEL);
+ if (!effects)
+ return -ENOMEM;
+
+ effects->ac = q6asm_audio_client_alloc(
+ (app_cb)audio_effects_event_handler,
+ (void *)effects);
+ if (!effects->ac) {
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
+ kfree(effects);
+ return -ENOMEM;
+ }
+
+ init_waitqueue_head(&effects->read_wait);
+ init_waitqueue_head(&effects->write_wait);
+
+ effects->opened = 0;
+ effects->started = 0;
+ effects->buf_alloc = 0;
+ file->private_data = effects;
+ pr_debug("%s: open session success\n", __func__);
+ return rc;
+}
+
+static const struct file_operations audio_effects_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_effects_open,
+ .release = audio_effects_release,
+ .unlocked_ioctl = audio_effects_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = audio_effects_compat_ioctl,
+#endif
+};
+
+struct miscdevice audio_effects_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_hweffects",
+ .fops = &audio_effects_fops,
+};
+
+static int __init audio_effects_init(void)
+{
+ return misc_register(&audio_effects_misc);
+}
+
+device_initcall(audio_effects_init);
+MODULE_DESCRIPTION("Audio hardware accelerated effects driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/qcom/qdsp6v2/audio_mp3.c b/drivers/misc/qcom/qdsp6v2/audio_mp3.c
new file mode 100644
index 0000000..0b10c7a
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_mp3.c
@@ -0,0 +1,188 @@
+/* mp3 audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_mp3_misc;
+static struct ws_mgr audio_mp3_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_mp3_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ rc = enable_volume_ramp(audio);
+ if (rc < 0) {
+ pr_err("%s: Failed to enable volume ramp\n",
+ __func__);
+ }
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_mp3_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_mp3_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_mp3_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_MP3);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open MP3 decoder, expected frames is always 1
+ * audio->buf_cfg.frames_per_buf = 0x01;
+ */
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_MP3);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_mp3_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_mp3_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:mp3dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_mp3_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+static struct miscdevice audio_mp3_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_mp3",
+ .fops = &audio_mp3_fops,
+};
+
+static int __init audio_mp3_init(void)
+{
+ int ret = misc_register(&audio_mp3_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_mp3_misc.this_device, true);
+ audio_mp3_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_mp3_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_mp3_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c b/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c
new file mode 100644
index 0000000..01c3dc5a
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c
@@ -0,0 +1,523 @@
+/* aac audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/msm_audio_aac.h>
+#include <linux/compat.h>
+#include <soc/qcom/socinfo.h>
+#include "audio_utils_aio.h"
+
+#define AUDIO_AAC_DUAL_MONO_INVALID -1
+
+
+/* Default number of pre-allocated event packets */
+#define PCM_BUFSZ_MIN_AACM ((8*1024) + sizeof(struct dec_meta_out))
+static struct miscdevice audio_multiaac_misc;
+static struct ws_mgr audio_multiaac_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_aac_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_aac_cfg aac_cfg;
+ struct msm_audio_aac_config *aac_config;
+ uint32_t sbr_ps = 0x00;
+
+ aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
+ if (audio->feedback == TUNNEL_MODE) {
+ aac_cfg.sample_rate = aac_config->sample_rate;
+ aac_cfg.ch_cfg = aac_config->channel_configuration;
+ } else {
+ aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
+ aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
+ }
+ pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
+ audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm_native(audio->ac,
+ aac_cfg.sample_rate,
+ aac_cfg.ch_cfg);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ /* turn on both sbr and ps */
+ rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
+ if (rc < 0)
+ pr_err("sbr-ps enable failed\n");
+ if (aac_config->sbr_ps_on_flag)
+ aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+ else if (aac_config->sbr_on_flag)
+ aac_cfg.aot = AAC_ENC_MODE_AAC_P;
+ else
+ aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
+
+ switch (aac_config->format) {
+ case AUDIO_AAC_FORMAT_ADTS:
+ aac_cfg.format = 0x00;
+ break;
+ case AUDIO_AAC_FORMAT_LOAS:
+ aac_cfg.format = 0x01;
+ break;
+ case AUDIO_AAC_FORMAT_ADIF:
+ aac_cfg.format = 0x02;
+ break;
+ default:
+ case AUDIO_AAC_FORMAT_RAW:
+ aac_cfg.format = 0x03;
+ }
+ aac_cfg.ep_config = aac_config->ep_config;
+ aac_cfg.section_data_resilience =
+ aac_config->aac_section_data_resilience_flag;
+ aac_cfg.scalefactor_data_resilience =
+ aac_config->aac_scalefactor_data_resilience_flag;
+ aac_cfg.spectral_data_resilience =
+ aac_config->aac_spectral_data_resilience_flag;
+
+ pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
+ __func__, aac_cfg.format,
+ aac_cfg.aot, aac_cfg.ch_cfg,
+ aac_cfg.sample_rate);
+
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_multi_aac(audio->ac, &aac_cfg);
+ if (rc < 0) {
+ pr_err("cmd media format block failed\n");
+ break;
+ }
+ rc = q6asm_set_encdec_chan_map(audio->ac, 2);
+ if (rc < 0) {
+ pr_err("%s: cmd set encdec_chan_map failed\n",
+ __func__);
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG: {
+ struct msm_audio_aac_config *aac_config;
+ uint16_t sce_left = 1, sce_right = 2;
+
+ if (arg == NULL) {
+ pr_err("%s: NULL config pointer\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ memcpy(audio->codec_cfg, arg,
+ sizeof(struct msm_audio_aac_config));
+ aac_config = audio->codec_cfg;
+ if (aac_config->dual_mono_mode >
+ AUDIO_AAC_DUAL_MONO_PL_SR) {
+ pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid dual_mono mode =%d\n",
+ __func__, aac_config->dual_mono_mode);
+ } else {
+ /* convert the data from user into sce_left
+ * and sce_right based on the definitions
+ */
+ pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify dual_mono mode =%d\n",
+ __func__, aac_config->dual_mono_mode);
+ switch (aac_config->dual_mono_mode) {
+ case AUDIO_AAC_DUAL_MONO_PL_PR:
+ sce_left = 1;
+ sce_right = 1;
+ break;
+ case AUDIO_AAC_DUAL_MONO_SL_SR:
+ sce_left = 2;
+ sce_right = 2;
+ break;
+ case AUDIO_AAC_DUAL_MONO_SL_PR:
+ sce_left = 2;
+ sce_right = 1;
+ break;
+ case AUDIO_AAC_DUAL_MONO_PL_SR:
+ default:
+ sce_left = 1;
+ sce_right = 2;
+ break;
+ }
+ rc = q6asm_cfg_dual_mono_aac(audio->ac,
+ sce_left, sce_right);
+ if (rc < 0)
+ pr_err("%s: asm cmd dualmono failed rc=%d\n",
+ __func__, rc);
+ } break;
+ break;
+ }
+ case AUDIO_SET_AAC_MIX_CONFIG: {
+ u32 *mix_coeff = (u32 *)arg;
+
+ if (!arg) {
+ pr_err("%s: Invalid param for %s\n",
+ __func__, "AUDIO_SET_AAC_MIX_CONFIG");
+ rc = -EINVAL;
+ break;
+ }
+ pr_debug("%s, AUDIO_SET_AAC_MIX_CONFIG", __func__);
+ pr_debug("%s, value of coeff = %d",
+ __func__, *mix_coeff);
+ q6asm_cfg_aac_sel_mix_coef(audio->ac, *mix_coeff);
+ if (rc < 0)
+ pr_err("%s asm aac_sel_mix_coef failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_AAC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_aac_config))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG failed\n"
+ , __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG: {
+ struct msm_audio_aac_config aac_config;
+
+ if (copy_from_user(&aac_config, (void *)arg,
+ sizeof(aac_config))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AAC_CONFIG failed\n"
+ , __func__);
+ rc = -EFAULT;
+ }
+ rc = audio_ioctl_shared(file, cmd, &aac_config);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ case AUDIO_SET_AAC_MIX_CONFIG: {
+ u32 mix_config;
+
+ pr_debug("%s, AUDIO_SET_AAC_MIX_CONFIG", __func__);
+ if (copy_from_user(&mix_config, (void *)arg,
+ sizeof(u32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AAC_MIX_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = audio_ioctl_shared(file, cmd, &mix_config);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default: {
+ pr_debug("Calling utils ioctl\n");
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_aac_config32 {
+ s16 format;
+ u16 audio_object;
+ u16 ep_config; /* 0 ~ 3 useful only obj = ERLC */
+ u16 aac_section_data_resilience_flag;
+ u16 aac_scalefactor_data_resilience_flag;
+ u16 aac_spectral_data_resilience_flag;
+ u16 sbr_on_flag;
+ u16 sbr_ps_on_flag;
+ u16 dual_mono_mode;
+ u16 channel_configuration;
+ u16 sample_rate;
+};
+
+enum {
+ AUDIO_SET_AAC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_aac_config32),
+ AUDIO_GET_AAC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_aac_config32),
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_AAC_CONFIG_32: {
+ struct msm_audio_aac_config *aac_config;
+ struct msm_audio_aac_config32 aac_config_32;
+
+ memset(&aac_config_32, 0, sizeof(aac_config_32));
+
+ aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
+ aac_config_32.format = aac_config->format;
+ aac_config_32.audio_object = aac_config->audio_object;
+ aac_config_32.ep_config = aac_config->ep_config;
+ aac_config_32.aac_section_data_resilience_flag =
+ aac_config->aac_section_data_resilience_flag;
+ aac_config_32.aac_scalefactor_data_resilience_flag =
+ aac_config->aac_scalefactor_data_resilience_flag;
+ aac_config_32.aac_spectral_data_resilience_flag =
+ aac_config->aac_spectral_data_resilience_flag;
+ aac_config_32.sbr_on_flag = aac_config->sbr_on_flag;
+ aac_config_32.sbr_ps_on_flag = aac_config->sbr_ps_on_flag;
+ aac_config_32.dual_mono_mode = aac_config->dual_mono_mode;
+ aac_config_32.channel_configuration =
+ aac_config->channel_configuration;
+ aac_config_32.sample_rate = aac_config->sample_rate;
+
+ if (copy_to_user((void *)arg, &aac_config_32,
+ sizeof(aac_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG_32: {
+ struct msm_audio_aac_config aac_config;
+ struct msm_audio_aac_config32 aac_config_32;
+
+ pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
+ if (copy_from_user(&aac_config_32, (void *)arg,
+ sizeof(aac_config_32))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_SET_AAC_CONFIG_32 failed",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ aac_config.format = aac_config_32.format;
+ aac_config.audio_object = aac_config_32.audio_object;
+ aac_config.ep_config = aac_config_32.ep_config;
+ aac_config.aac_section_data_resilience_flag =
+ aac_config_32.aac_section_data_resilience_flag;
+ aac_config.aac_scalefactor_data_resilience_flag =
+ aac_config_32.aac_scalefactor_data_resilience_flag;
+ aac_config.aac_spectral_data_resilience_flag =
+ aac_config_32.aac_spectral_data_resilience_flag;
+ aac_config.sbr_on_flag = aac_config_32.sbr_on_flag;
+ aac_config.sbr_ps_on_flag = aac_config_32.sbr_ps_on_flag;
+ aac_config.dual_mono_mode = aac_config_32.dual_mono_mode;
+ aac_config.channel_configuration =
+ aac_config_32.channel_configuration;
+ aac_config.sample_rate = aac_config_32.sample_rate;
+
+ cmd = AUDIO_SET_AAC_CONFIG;
+ rc = audio_ioctl_shared(file, cmd, &aac_config);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_CONFIG failed. rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ case AUDIO_SET_AAC_MIX_CONFIG: {
+ u32 mix_config;
+
+ pr_debug("%s, AUDIO_SET_AAC_MIX_CONFIG\n", __func__);
+ if (copy_from_user(&mix_config, (void *)arg,
+ sizeof(u32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_AAC_MIX_CONFIG failed\n"
+ , __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = audio_ioctl_shared(file, cmd, &mix_config);
+ if (rc)
+ pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default: {
+ pr_debug("Calling utils ioctl\n");
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+ struct msm_audio_aac_config *aac_config = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_multi_aac_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
+ GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ aac_config = audio->codec_cfg;
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
+ audio->miscdevice = &audio_multiaac_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_multiaac_ws_mgr;
+ aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_MPEG4_MULTI_AAC);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open AAC decoder, expected frames is always 1
+ * audio->buf_cfg.frames_per_buf = 0x01;
+ */
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_MULTI_AAC);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_multi_aac_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_aac_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
+ __func__, audio->feedback, audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_aac_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl
+};
+
+static struct miscdevice audio_multiaac_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_multi_aac",
+ .fops = &audio_aac_fops,
+};
+
+static int __init audio_aac_init(void)
+{
+ int ret = misc_register(&audio_multiaac_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_multiaac_misc.this_device, true);
+ audio_multiaac_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_multiaac_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_aac_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_qcelp.c b/drivers/misc/qcom/qdsp6v2/audio_qcelp.c
new file mode 100644
index 0000000..8f2511c
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_qcelp.c
@@ -0,0 +1,191 @@
+/* qcelp(v13k) audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+#define FRAME_SIZE_DEC_QCELP ((32) + sizeof(struct dec_meta_in))
+
+static struct miscdevice audio_qcelp_misc;
+static struct ws_mgr audio_qcelp_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_qcelp_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_qcelp_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE_DEC_QCELP;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->pcm_cfg.channel_count = 1;
+ audio->miscdevice = &audio_qcelp_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_qcelp_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_V13K);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_V13K);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_qcelp_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_qcelp_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_qcelp_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+static struct miscdevice audio_qcelp_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_qcelp",
+ .fops = &audio_qcelp_fops,
+};
+
+static int __init audio_qcelp_init(void)
+{
+ int ret = misc_register(&audio_qcelp_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_qcelp_misc.this_device, true);
+ audio_qcelp_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_qcelp_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_qcelp_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils.c b/drivers/misc/qcom/qdsp6v2/audio_utils.c
new file mode 100644
index 0000000..15ee9f5
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils.c
@@ -0,0 +1,954 @@
+/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/compat.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/*
+ * Define maximum buffer size. Below values are chosen considering the higher
+ * values used among all native drivers.
+ */
+#define MAX_FRAME_SIZE 1536
+#define MAX_FRAMES 5
+#define META_SIZE (sizeof(struct meta_out_dsp))
+#define MAX_BUFFER_SIZE (1 + ((MAX_FRAME_SIZE + META_SIZE) * MAX_FRAMES))
+
+static int audio_in_pause(struct q6audio_in *audio)
+{
+ int rc;
+
+ rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+ if (rc < 0)
+ pr_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
+ audio->ac->session, rc);
+
+ return rc;
+}
+
+static int audio_in_flush(struct q6audio_in *audio)
+{
+ int rc;
+
+ pr_debug("%s:session id %d: flush\n", __func__, audio->ac->session);
+ /* Flush if session running */
+ if (audio->enabled) {
+ /* Implicitly issue a pause to the encoder before flushing */
+ rc = audio_in_pause(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: pause cmd failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ return rc;
+ }
+
+ rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+ if (rc < 0) {
+ pr_err("%s:session id %d: flush cmd failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ return rc;
+ }
+ /* 2nd arg: 0 -> run immediately
+ * 3rd arg: 0 -> msw_ts,
+ * 4th arg: 0 ->lsw_ts
+ */
+ q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+ pr_debug("Rerun the session\n");
+ }
+ audio->rflush = 1;
+ audio->wflush = 1;
+ memset(audio->out_frame_info, 0, sizeof(audio->out_frame_info));
+ wake_up(&audio->read_wait);
+ /* get read_lock to ensure no more waiting read thread */
+ mutex_lock(&audio->read_lock);
+ audio->rflush = 0;
+ mutex_unlock(&audio->read_lock);
+ wake_up(&audio->write_wait);
+ /* get write_lock to ensure no more waiting write thread */
+ mutex_lock(&audio->write_lock);
+ audio->wflush = 0;
+ mutex_unlock(&audio->write_lock);
+ pr_debug("%s:session id %d: in_bytes %d\n", __func__,
+ audio->ac->session, atomic_read(&audio->in_bytes));
+ pr_debug("%s:session id %d: in_samples %d\n", __func__,
+ audio->ac->session, atomic_read(&audio->in_samples));
+ atomic_set(&audio->in_bytes, 0);
+ atomic_set(&audio->in_samples, 0);
+ atomic_set(&audio->out_count, 0);
+ return 0;
+}
+
+/* must be called with audio->lock held */
+int audio_in_enable(struct q6audio_in *audio)
+{
+ if (audio->enabled)
+ return 0;
+
+ /* 2nd arg: 0 -> run immediately
+ * 3rd arg: 0 -> msw_ts,
+ * 4th arg: 0 ->lsw_ts
+ */
+ return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+/* must be called with audio->lock held */
+int audio_in_disable(struct q6audio_in *audio)
+{
+ int rc = 0;
+
+ if (!audio->stopped) {
+ audio->enabled = 0;
+ audio->opened = 0;
+ pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
+ __func__, audio->ac->session,
+ atomic_read(&audio->in_bytes),
+ atomic_read(&audio->in_samples));
+
+ rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+ if (rc < 0)
+ pr_err("%s:session id %d: Failed to close the session rc=%d\n",
+ __func__, audio->ac->session,
+ rc);
+ audio->stopped = 1;
+ memset(audio->out_frame_info, 0,
+ sizeof(audio->out_frame_info));
+ wake_up(&audio->read_wait);
+ wake_up(&audio->write_wait);
+ }
+ pr_debug("%s:session id %d: enabled[%d]\n", __func__,
+ audio->ac->session, audio->enabled);
+ return rc;
+}
+
+int audio_in_buf_alloc(struct q6audio_in *audio)
+{
+ int rc = 0;
+
+ switch (audio->buf_alloc) {
+ case NO_BUF_ALLOC:
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_audio_client_buf_alloc(IN,
+ audio->ac,
+ ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+ audio->pcm_cfg.buffer_count);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Buffer Alloc failed\n",
+ __func__,
+ audio->ac->session);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_IN;
+ }
+ rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+ ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+ audio->str_cfg.buffer_count);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_OUT;
+ break;
+ case BUF_ALLOC_IN:
+ rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+ ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+ audio->str_cfg.buffer_count);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_OUT;
+ break;
+ case BUF_ALLOC_OUT:
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+ ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+ audio->pcm_cfg.buffer_count);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Buffer Alloc failed\n",
+ __func__,
+ audio->ac->session);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_IN;
+ }
+ break;
+ default:
+ pr_debug("%s:session id %d: buf[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ }
+
+ return rc;
+}
+
+int audio_in_set_config(struct file *file,
+ struct msm_audio_config *cfg)
+{
+ int rc = 0;
+ struct q6audio_in *audio = file->private_data;
+
+ if (audio->feedback != NON_TUNNEL_MODE) {
+ pr_err("%s:session id %d: Not sufficient permission to change the record mode\n",
+ __func__, audio->ac->session);
+ rc = -EACCES;
+ goto ret;
+ }
+ if ((cfg->buffer_count > PCM_BUF_COUNT) ||
+ (cfg->buffer_count == 1))
+ cfg->buffer_count = PCM_BUF_COUNT;
+
+ audio->pcm_cfg.buffer_count = cfg->buffer_count;
+ audio->pcm_cfg.buffer_size = cfg->buffer_size;
+ audio->pcm_cfg.channel_count = cfg->channel_count;
+ audio->pcm_cfg.sample_rate = cfg->sample_rate;
+ if (audio->opened && audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+ ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+ audio->pcm_cfg.buffer_count);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Buffer Alloc failed\n",
+ __func__, audio->ac->session);
+ rc = -ENOMEM;
+ goto ret;
+ }
+ }
+ audio->buf_alloc |= BUF_ALLOC_IN;
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_SET_CONFIG %d %d\n", __func__,
+ audio->ac->session, audio->pcm_cfg.buffer_count,
+ audio->pcm_cfg.buffer_size);
+ret:
+ return rc;
+}
+/* ------------------- device --------------------- */
+static long audio_in_ioctl_shared(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_FLUSH: {
+ /* Make sure we're stopped and we wake any threads
+ * that might be blocked holding the read_lock.
+ * While audio->stopped read threads will always
+ * exit immediately.
+ */
+ rc = audio_in_flush(audio);
+ if (rc < 0)
+ pr_err("%s:session id %d: Flush Fail rc=%d\n",
+ __func__, audio->ac->session, rc);
+ else { /* Register back the flushed read buffer with DSP */
+ int cnt = 0;
+
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ pr_debug("register the read buffer\n");
+ }
+ break;
+ }
+ case AUDIO_PAUSE: {
+ pr_debug("%s:session id %d: AUDIO_PAUSE\n", __func__,
+ audio->ac->session);
+ if (audio->enabled)
+ audio_in_pause(audio);
+ break;
+ }
+ case AUDIO_GET_SESSION_ID: {
+ if (copy_to_user((void *) arg, &audio->ac->session,
+ sizeof(u16))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_SESSION_ID failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+long audio_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ if (cmd == AUDIO_GET_STATS) {
+ struct msm_audio_stats stats;
+
+ memset(&stats, 0, sizeof(stats));
+ stats.byte_count = atomic_read(&audio->in_bytes);
+ stats.sample_count = atomic_read(&audio->in_samples);
+ if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+ return -EFAULT;
+ return rc;
+ }
+
+ mutex_lock(&audio->lock);
+ switch (cmd) {
+ case AUDIO_FLUSH:
+ case AUDIO_PAUSE:
+ case AUDIO_GET_SESSION_ID:
+ rc = audio_in_ioctl_shared(file, cmd, arg);
+ break;
+ case AUDIO_GET_STREAM_CONFIG: {
+ struct msm_audio_stream_config cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.buffer_size = audio->str_cfg.buffer_size;
+ cfg.buffer_count = audio->str_cfg.buffer_count;
+ if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+ rc = -EFAULT;
+ pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
+ __func__, audio->ac->session, cfg.buffer_size,
+ cfg.buffer_count);
+ break;
+ }
+ case AUDIO_SET_STREAM_CONFIG: {
+ struct msm_audio_stream_config cfg;
+
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_STREAM_CONFIG failed\n"
+ , __func__);
+ rc = -EFAULT;
+ break;
+ }
+ /* Minimum single frame size,
+ * but with in maximum frames number
+ */
+ if ((cfg.buffer_size < (audio->min_frame_size +
+ sizeof(struct meta_out_dsp))) ||
+ (cfg.buffer_count < FRAME_NUM)) {
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg.buffer_size > MAX_BUFFER_SIZE) {
+ rc = -EINVAL;
+ break;
+ }
+ audio->str_cfg.buffer_size = cfg.buffer_size;
+ audio->str_cfg.buffer_count = cfg.buffer_count;
+ if (audio->opened) {
+ rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+ ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+ audio->str_cfg.buffer_count);
+ if (rc < 0) {
+ pr_err("%s: session id %d: Buffer Alloc failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENOMEM;
+ break;
+ }
+ }
+ audio->buf_alloc |= BUF_ALLOC_OUT;
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
+ __func__, audio->ac->session,
+ audio->str_cfg.buffer_size,
+ audio->str_cfg.buffer_count);
+ break;
+ }
+ case AUDIO_SET_BUF_CFG: {
+ struct msm_audio_buf_cfg cfg;
+
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ rc = -EFAULT;
+ break;
+ }
+ if ((audio->feedback == NON_TUNNEL_MODE) &&
+ !cfg.meta_info_enable) {
+ rc = -EFAULT;
+ break;
+ }
+
+ /* Restrict the num of frames per buf to coincide with
+ * default buf size
+ */
+ if (cfg.frames_per_buf > audio->max_frames_per_buf) {
+ rc = -EFAULT;
+ break;
+ }
+ audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+ audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
+ pr_debug("%s:session id %d: Set-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__,
+ audio->ac->session, cfg.meta_info_enable,
+ cfg.frames_per_buf);
+ break;
+ }
+ case AUDIO_GET_BUF_CFG: {
+ pr_debug("%s:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__,
+ audio->ac->session, audio->buf_cfg.meta_info_enable,
+ audio->buf_cfg.frames_per_buf);
+
+ if (copy_to_user((void *)arg, &audio->buf_cfg,
+ sizeof(struct msm_audio_buf_cfg)))
+ rc = -EFAULT;
+ break;
+ }
+ case AUDIO_GET_CONFIG: {
+ if (copy_to_user((void *)arg, &audio->pcm_cfg,
+ sizeof(struct msm_audio_config)))
+ rc = -EFAULT;
+ break;
+
+ }
+ case AUDIO_SET_CONFIG: {
+ struct msm_audio_config cfg;
+
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = audio_in_set_config(file, &cfg);
+ break;
+ }
+ default:
+ /* call codec specific ioctl */
+ rc = audio->enc_ioctl(file, cmd, arg);
+ }
+ mutex_unlock(&audio->lock);
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_stats32 {
+ u32 byte_count;
+ u32 sample_count;
+ u32 unused[2];
+};
+
+struct msm_audio_stream_config32 {
+ u32 buffer_size;
+ u32 buffer_count;
+};
+
+struct msm_audio_config32 {
+ u32 buffer_size;
+ u32 buffer_count;
+ u32 channel_count;
+ u32 sample_rate;
+ u32 type;
+ u32 meta_field;
+ u32 bits;
+ u32 unused[3];
+};
+
+struct msm_audio_buf_cfg32 {
+ u32 meta_info_enable;
+ u32 frames_per_buf;
+};
+
+enum {
+ AUDIO_GET_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, 3,
+ struct msm_audio_config32),
+ AUDIO_SET_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, 4,
+ struct msm_audio_config32),
+ AUDIO_GET_STATS_32 = _IOR(AUDIO_IOCTL_MAGIC, 5,
+ struct msm_audio_stats32),
+ AUDIO_SET_STREAM_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, 80,
+ struct msm_audio_stream_config32),
+ AUDIO_GET_STREAM_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, 81,
+ struct msm_audio_stream_config32),
+ AUDIO_SET_BUF_CFG_32 = _IOW(AUDIO_IOCTL_MAGIC, 94,
+ struct msm_audio_buf_cfg32),
+ AUDIO_GET_BUF_CFG_32 = _IOW(AUDIO_IOCTL_MAGIC, 93,
+ struct msm_audio_buf_cfg32),
+};
+
+long audio_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ if (cmd == AUDIO_GET_STATS_32) {
+ struct msm_audio_stats32 stats_32;
+
+ memset(&stats_32, 0, sizeof(stats_32));
+ stats_32.byte_count = atomic_read(&audio->in_bytes);
+ stats_32.sample_count = atomic_read(&audio->in_samples);
+ if (copy_to_user((void *) arg, &stats_32, sizeof(stats_32))) {
+ pr_err("%s: copy_to_user failed for AUDIO_GET_STATS_32\n",
+ __func__);
+ return -EFAULT;
+ }
+ return rc;
+ }
+
+ mutex_lock(&audio->lock);
+ switch (cmd) {
+ case AUDIO_FLUSH:
+ case AUDIO_PAUSE:
+ case AUDIO_GET_SESSION_ID:
+ rc = audio_in_ioctl_shared(file, cmd, arg);
+ break;
+ case AUDIO_GET_STREAM_CONFIG_32: {
+ struct msm_audio_stream_config32 cfg_32;
+
+ memset(&cfg_32, 0, sizeof(cfg_32));
+ cfg_32.buffer_size = audio->str_cfg.buffer_size;
+ cfg_32.buffer_count = audio->str_cfg.buffer_count;
+ if (copy_to_user((void *)arg, &cfg_32, sizeof(cfg_32))) {
+ pr_err("%s: Copy to user failed\n", __func__);
+ rc = -EFAULT;
+ }
+ pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
+ __func__, audio->ac->session,
+ cfg_32.buffer_size,
+ cfg_32.buffer_count);
+ break;
+ }
+ case AUDIO_SET_STREAM_CONFIG_32: {
+ struct msm_audio_stream_config32 cfg_32;
+ struct msm_audio_stream_config cfg;
+
+ if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_STREAM_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.buffer_size = cfg_32.buffer_size;
+ cfg.buffer_count = cfg_32.buffer_count;
+ /* Minimum single frame size,
+ * but with in maximum frames number
+ */
+ if ((cfg.buffer_size < (audio->min_frame_size +
+ sizeof(struct meta_out_dsp))) ||
+ (cfg.buffer_count < FRAME_NUM)) {
+ rc = -EINVAL;
+ break;
+ }
+ audio->str_cfg.buffer_size = cfg.buffer_size;
+ audio->str_cfg.buffer_count = cfg.buffer_count;
+ if (audio->opened) {
+ rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+ ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+ audio->str_cfg.buffer_count);
+ if (rc < 0) {
+ pr_err("%s: session id %d:\n",
+ __func__, audio->ac->session);
+ pr_err("Buffer Alloc failed rc=%d\n", rc);
+ rc = -ENOMEM;
+ break;
+ }
+ }
+ audio->buf_alloc |= BUF_ALLOC_OUT;
+ pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
+ __func__, audio->ac->session,
+ audio->str_cfg.buffer_size,
+ audio->str_cfg.buffer_count);
+ break;
+ }
+ case AUDIO_SET_BUF_CFG_32: {
+ struct msm_audio_buf_cfg32 cfg_32;
+ struct msm_audio_buf_cfg cfg;
+
+ if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_BUG_CFG_32 failed",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.meta_info_enable = cfg_32.meta_info_enable;
+ cfg.frames_per_buf = cfg_32.frames_per_buf;
+
+ if ((audio->feedback == NON_TUNNEL_MODE) &&
+ !cfg.meta_info_enable) {
+ rc = -EFAULT;
+ break;
+ }
+
+ /* Restrict the num of frames per buf to coincide with
+ * default buf size
+ */
+ if (cfg.frames_per_buf > audio->max_frames_per_buf) {
+ rc = -EFAULT;
+ break;
+ }
+ audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+ audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
+ pr_debug("%s:session id %d: Set-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__, audio->ac->session, cfg.meta_info_enable,
+ cfg.frames_per_buf);
+ break;
+ }
+ case AUDIO_GET_BUF_CFG_32: {
+ struct msm_audio_buf_cfg32 cfg_32;
+
+ pr_debug("%s:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__,
+ audio->ac->session, audio->buf_cfg.meta_info_enable,
+ audio->buf_cfg.frames_per_buf);
+ cfg_32.meta_info_enable = audio->buf_cfg.meta_info_enable;
+ cfg_32.frames_per_buf = audio->buf_cfg.frames_per_buf;
+
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(struct msm_audio_buf_cfg32))) {
+ pr_err("%s: Copy to user failed\n", __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_GET_CONFIG_32: {
+ struct msm_audio_config32 cfg_32;
+
+ memset(&cfg_32, 0, sizeof(cfg_32));
+ cfg_32.buffer_size = audio->pcm_cfg.buffer_size;
+ cfg_32.buffer_count = audio->pcm_cfg.buffer_count;
+ cfg_32.channel_count = audio->pcm_cfg.channel_count;
+ cfg_32.sample_rate = audio->pcm_cfg.sample_rate;
+ cfg_32.type = audio->pcm_cfg.type;
+ cfg_32.meta_field = audio->pcm_cfg.meta_field;
+ cfg_32.bits = audio->pcm_cfg.bits;
+
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(struct msm_audio_config32))) {
+ pr_err("%s: Copy to user failed\n", __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_CONFIG_32: {
+ struct msm_audio_config32 cfg_32;
+ struct msm_audio_config cfg;
+
+ if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.buffer_size = cfg_32.buffer_size;
+ cfg.buffer_count = cfg_32.buffer_count;
+ cfg.channel_count = cfg_32.channel_count;
+ cfg.sample_rate = cfg_32.sample_rate;
+ cfg.type = cfg_32.type;
+ cfg.meta_field = cfg_32.meta_field;
+ cfg.bits = cfg_32.bits;
+ rc = audio_in_set_config(file, &cfg);
+ break;
+ }
+ default:
+ /* call codec specific ioctl */
+ rc = audio->enc_compat_ioctl(file, cmd, arg);
+ }
+ mutex_unlock(&audio->lock);
+ return rc;
+}
+#endif
+
+ssize_t audio_in_read(struct file *file,
+ char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct q6audio_in *audio = file->private_data;
+ const char __user *start = buf;
+ unsigned char *data;
+ uint32_t offset = 0;
+ uint32_t size = 0;
+ int rc = 0;
+ uint32_t idx;
+ struct meta_out_dsp meta;
+ uint32_t bytes_to_copy = 0;
+ uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
+ (sizeof(unsigned char) +
+ (sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
+
+ memset(&meta, 0, sizeof(meta));
+ pr_debug("%s:session id %d: read - %zd\n", __func__, audio->ac->session,
+ count);
+ if (audio->reset_event)
+ return -ENETRESET;
+
+ if (!audio->enabled)
+ return -EFAULT;
+ mutex_lock(&audio->read_lock);
+ while (count > 0) {
+ rc = wait_event_interruptible(
+ audio->read_wait,
+ ((atomic_read(&audio->out_count) > 0) ||
+ (audio->stopped) ||
+ audio->rflush || audio->eos_rsp ||
+ audio->event_abort));
+
+ if (audio->event_abort) {
+ rc = -EIO;
+ break;
+ }
+
+
+ if (rc < 0)
+ break;
+
+ if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
+ audio->rflush) {
+ pr_debug("%s:session id %d: driver in stop state or flush,No more buf to read",
+ __func__,
+ audio->ac->session);
+ rc = 0;/* End of File */
+ break;
+ }
+ if (!(atomic_read(&audio->out_count)) &&
+ (audio->eos_rsp == 1) &&
+ (count >= (sizeof(unsigned char) +
+ sizeof(struct meta_out_dsp)))) {
+ unsigned char num_of_frames;
+
+ pr_info("%s:session id %d: eos %d at output\n",
+ __func__, audio->ac->session, audio->eos_rsp);
+ if (buf != start)
+ break;
+ num_of_frames = 0xFF;
+ if (copy_to_user(buf, &num_of_frames,
+ sizeof(unsigned char))) {
+ rc = -EFAULT;
+ break;
+ }
+ buf += sizeof(unsigned char);
+ meta.frame_size = 0xFFFF;
+ meta.encoded_pcm_samples = 0xFFFF;
+ meta.msw_ts = 0x00;
+ meta.lsw_ts = 0x00;
+ meta.nflags = AUD_EOS_SET;
+ audio->eos_rsp = 0;
+ if (copy_to_user(buf, &meta, sizeof(meta))) {
+ rc = -EFAULT;
+ break;
+ }
+ buf += sizeof(meta);
+ break;
+ }
+ data = (unsigned char *)q6asm_is_cpu_buf_avail(OUT, audio->ac,
+ &size, &idx);
+ if ((count >= (size + mfield_size)) && data) {
+ if (audio->buf_cfg.meta_info_enable) {
+ if (copy_to_user(buf,
+ &audio->out_frame_info[idx][0],
+ sizeof(unsigned char))) {
+ rc = -EFAULT;
+ break;
+ }
+ bytes_to_copy =
+ (size + audio->out_frame_info[idx][1]);
+ /* Number of frames information copied */
+ buf += sizeof(unsigned char);
+ count -= sizeof(unsigned char);
+ } else {
+ offset = audio->out_frame_info[idx][1];
+ bytes_to_copy = size;
+ }
+
+ pr_debug("%s:session id %d: offset=%d nr of frames= %d\n",
+ __func__, audio->ac->session,
+ audio->out_frame_info[idx][1],
+ audio->out_frame_info[idx][0]);
+
+ if (copy_to_user(buf, &data[offset], bytes_to_copy)) {
+ rc = -EFAULT;
+ break;
+ }
+ count -= bytes_to_copy;
+ buf += bytes_to_copy;
+ } else {
+ pr_err("%s:session id %d: short read data[%pK] bytesavail[%d]bytesrequest[%zd]\n",
+ __func__,
+ audio->ac->session,
+ data, size, count);
+ }
+ atomic_dec(&audio->out_count);
+ q6asm_read(audio->ac);
+ break;
+ }
+ mutex_unlock(&audio->read_lock);
+
+ pr_debug("%s:session id %d: read: %zd bytes\n", __func__,
+ audio->ac->session, (buf-start));
+ if (buf > start)
+ return buf - start;
+ return rc;
+}
+
+static int extract_meta_info(char *buf, unsigned long *msw_ts,
+ unsigned long *lsw_ts, unsigned int *flags)
+{
+ struct meta_in *meta = (struct meta_in *)buf;
+ *msw_ts = meta->ntimestamp.highpart;
+ *lsw_ts = meta->ntimestamp.lowpart;
+ *flags = meta->nflags;
+ return 0;
+}
+
+ssize_t audio_in_write(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct q6audio_in *audio = file->private_data;
+ const char __user *start = buf;
+ size_t xfer = 0;
+ char *cpy_ptr;
+ int rc = 0;
+ unsigned char *data;
+ uint32_t size = 0;
+ uint32_t idx = 0;
+ uint32_t nflags = 0;
+ unsigned long msw_ts = 0;
+ unsigned long lsw_ts = 0;
+ uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
+ sizeof(struct meta_in);
+
+ pr_debug("%s:session id %d: to write[%zd]\n", __func__,
+ audio->ac->session, count);
+ if (audio->reset_event)
+ return -ENETRESET;
+
+ if (!audio->enabled)
+ return -EFAULT;
+ mutex_lock(&audio->write_lock);
+
+ while (count > 0) {
+ rc = wait_event_interruptible(audio->write_wait,
+ ((atomic_read(&audio->in_count) > 0) ||
+ (audio->stopped) ||
+ (audio->wflush) || (audio->event_abort)));
+
+ if (audio->event_abort) {
+ rc = -EIO;
+ break;
+ }
+
+ if (rc < 0)
+ break;
+ if (audio->stopped || audio->wflush) {
+ pr_debug("%s: session id %d: stop or flush\n", __func__,
+ audio->ac->session);
+ rc = -EBUSY;
+ break;
+ }
+ /* if no PCM data, might have only eos buffer
+ * such case do not hold cpu buffer
+ */
+ if ((buf == start) && (count == mfield_size)) {
+ char eos_buf[sizeof(struct meta_in)];
+ /* Processing beginning of user buffer */
+ if (copy_from_user(eos_buf, buf, mfield_size)) {
+ rc = -EFAULT;
+ break;
+ }
+ /* Check if EOS flag is set and buffer has
+ * contains just meta field
+ */
+ extract_meta_info(eos_buf, &msw_ts, &lsw_ts,
+ &nflags);
+ buf += mfield_size;
+ /* send the EOS and return */
+ pr_debug("%s:session id %d: send EOS 0x%8x\n",
+ __func__,
+ audio->ac->session, nflags);
+ break;
+ }
+ data = (unsigned char *)q6asm_is_cpu_buf_avail(IN, audio->ac,
+ &size, &idx);
+ if (!data) {
+ pr_debug("%s:session id %d: No buf available\n",
+ __func__, audio->ac->session);
+ continue;
+ }
+ cpy_ptr = data;
+ if (audio->buf_cfg.meta_info_enable) {
+ if (buf == start) {
+ /* Processing beginning of user buffer */
+ if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+ rc = -EFAULT;
+ break;
+ }
+ /* Check if EOS flag is set and buffer has
+ * contains just meta field
+ */
+ extract_meta_info(cpy_ptr, &msw_ts, &lsw_ts,
+ &nflags);
+ buf += mfield_size;
+ count -= mfield_size;
+ } else {
+ pr_debug("%s:session id %d: continuous buffer\n",
+ __func__, audio->ac->session);
+ }
+ }
+ xfer = (count > (audio->pcm_cfg.buffer_size)) ?
+ (audio->pcm_cfg.buffer_size) : count;
+
+ if (copy_from_user(cpy_ptr, buf, xfer)) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = q6asm_write(audio->ac, xfer, msw_ts, lsw_ts, 0x00);
+ if (rc < 0) {
+ rc = -EFAULT;
+ break;
+ }
+ atomic_dec(&audio->in_count);
+ count -= xfer;
+ buf += xfer;
+ }
+ mutex_unlock(&audio->write_lock);
+ pr_debug("%s:session id %d: eos_condition 0x%x buf[0x%pK] start[0x%pK]\n",
+ __func__, audio->ac->session,
+ nflags, buf, start);
+ if (nflags & AUD_EOS_SET) {
+ rc = q6asm_cmd(audio->ac, CMD_EOS);
+ pr_info("%s:session id %d: eos %d at input\n", __func__,
+ audio->ac->session, audio->eos_rsp);
+ }
+ pr_debug("%s:session id %d: Written %zd Avail Buf[%d]", __func__,
+ audio->ac->session, (buf - start - mfield_size),
+ atomic_read(&audio->in_count));
+ if (!rc) {
+ if (buf > start)
+ return buf - start;
+ }
+ return rc;
+}
+
+int audio_in_release(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = file->private_data;
+
+ pr_info("%s: session id %d\n", __func__, audio->ac->session);
+ mutex_lock(&audio->lock);
+ audio_in_disable(audio);
+ q6asm_audio_client_free(audio->ac);
+ mutex_unlock(&audio->lock);
+ kfree(audio->enc_cfg);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return 0;
+}
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils.h b/drivers/misc/qcom/qdsp6v2/audio_utils.h
new file mode 100644
index 0000000..f5517d8
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 2010-2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/msm_audio.h>
+#include <linux/compat.h>
+#include "q6audio_common.h"
+
+#define FRAME_NUM (8)
+
+#define PCM_BUF_COUNT (2)
+
+#define AUD_EOS_SET 0x01
+#define TUNNEL_MODE 0x0000
+#define NON_TUNNEL_MODE 0x0001
+
+#define NO_BUF_ALLOC 0x00
+#define BUF_ALLOC_IN 0x01
+#define BUF_ALLOC_OUT 0x02
+#define BUF_ALLOC_INOUT 0x03
+#define ALIGN_BUF_SIZE(size) ((size + 4095) & (~4095))
+
+struct timestamp {
+ u32 lowpart;
+ u32 highpart;
+} __packed;
+
+struct meta_in {
+ unsigned short offset;
+ struct timestamp ntimestamp;
+ unsigned int nflags;
+} __packed;
+
+struct meta_out_dsp {
+ u32 offset_to_frame;
+ u32 frame_size;
+ u32 encoded_pcm_samples;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 nflags;
+} __packed;
+
+struct meta_out {
+ unsigned char num_of_frames;
+ struct meta_out_dsp meta_out_dsp[];
+} __packed;
+
+struct q6audio_in {
+ spinlock_t dsp_lock;
+ atomic_t in_bytes;
+ atomic_t in_samples;
+
+ struct mutex lock;
+ struct mutex read_lock;
+ struct mutex write_lock;
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+
+ struct audio_client *ac;
+ struct msm_audio_stream_config str_cfg;
+ void *enc_cfg;
+ struct msm_audio_buf_cfg buf_cfg;
+ struct msm_audio_config pcm_cfg;
+ void *codec_cfg;
+
+ /* number of buffers available to read/write */
+ atomic_t in_count;
+ atomic_t out_count;
+
+ /* first idx: num of frames per buf, second idx: offset to frame */
+ uint32_t out_frame_info[FRAME_NUM][2];
+ int eos_rsp;
+ int opened;
+ int enabled;
+ int stopped;
+ int event_abort;
+ int feedback; /* Flag indicates whether used
+ * in Non Tunnel mode
+ */
+ int rflush;
+ int wflush;
+ int buf_alloc;
+ uint16_t min_frame_size;
+ uint16_t max_frames_per_buf;
+ bool reset_event;
+ long (*enc_ioctl)(struct file *, unsigned int, unsigned long);
+ long (*enc_compat_ioctl)(struct file *, unsigned int, unsigned long);
+};
+
+int audio_in_enable(struct q6audio_in *audio);
+int audio_in_disable(struct q6audio_in *audio);
+int audio_in_buf_alloc(struct q6audio_in *audio);
+long audio_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+long audio_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+#else
+#define audio_in_compat_ioctl NULL
+#endif
+ssize_t audio_in_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos);
+ssize_t audio_in_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos);
+int audio_in_release(struct inode *inode, struct file *file);
+int audio_in_set_config(struct file *file, struct msm_audio_config *cfg);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
new file mode 100644
index 0000000..dea063d
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -0,0 +1,2132 @@
+/* Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <asm/ioctls.h>
+#include <linux/debugfs.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+#ifdef CONFIG_USE_DEV_CTRL_VOLUME
+#include <linux/qdsp6v2/audio_dev_ctl.h>
+#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
+#ifdef CONFIG_DEBUG_FS
+int audio_aio_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ const int debug_bufmax = 4096;
+ static char buffer[4096];
+ int n = 0;
+ struct q6audio_aio *audio = file->private_data;
+
+ mutex_lock(&audio->lock);
+ n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "enabled %d\n", audio->enabled);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "stopped %d\n", audio->stopped);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "feedback %d\n", audio->feedback);
+ mutex_unlock(&audio->lock);
+ /* Following variables are only useful for debugging when
+ * when playback halts unexpectedly. Thus, no mutual exclusion
+ * enforced
+ */
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "wflush %d\n", audio->wflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "rflush %d\n", audio->rflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "inqueue empty %d\n", list_empty(&audio->in_queue));
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "outqueue empty %d\n", list_empty(&audio->out_queue));
+ buffer[n] = 0;
+ return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+#endif
+
+static long audio_aio_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long audio_aio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+#else
+#define audio_aio_compat_ioctl NULL
+#endif
+int insert_eos_buf(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node)
+{
+ struct dec_meta_out *eos_buf = buf_node->kvaddr;
+
+ pr_debug("%s[%pK]:insert_eos_buf\n", __func__, audio);
+ eos_buf->num_of_frames = 0xFFFFFFFF;
+ eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
+ eos_buf->meta_out_dsp[0].nflags = AUDIO_DEC_EOS_SET;
+ return sizeof(struct dec_meta_out) +
+ sizeof(eos_buf->meta_out_dsp[0]);
+}
+
+/* Routine which updates read buffers of driver/dsp,
+ * for flush operation as DSP output might not have proper
+ * value set
+ */
+static int insert_meta_data_flush(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node)
+{
+ struct dec_meta_out *meta_data = buf_node->kvaddr;
+
+ meta_data->num_of_frames = 0x0;
+ meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
+ meta_data->meta_out_dsp[0].nflags = 0x0;
+ return sizeof(struct dec_meta_out) +
+ sizeof(meta_data->meta_out_dsp[0]);
+}
+
+static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
+ unsigned long len,
+ struct audio_aio_ion_region **region)
+{
+ struct audio_aio_ion_region *region_elt;
+
+ int match_count = 0;
+
+ *region = NULL;
+
+ /* returns physical address or zero */
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
+ if (addr >= region_elt->vaddr &&
+ addr < region_elt->vaddr + region_elt->len &&
+ addr + len <= region_elt->vaddr + region_elt->len) {
+ /* offset since we could pass vaddr inside a registered
+ * ion buffer
+ */
+
+ match_count++;
+ if (!*region)
+ *region = region_elt;
+ }
+ }
+
+ if (match_count > 1) {
+ pr_err("%s[%pK]:multiple hits for vaddr %pK, len %ld\n",
+ __func__, audio, addr, len);
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
+ list) {
+ if (addr >= region_elt->vaddr &&
+ addr < region_elt->vaddr + region_elt->len &&
+ addr + len <= region_elt->vaddr + region_elt->len)
+ pr_err("\t%s[%pK]:%pK, %ld --> %pK\n",
+ __func__, audio,
+ region_elt->vaddr,
+ region_elt->len,
+ ®ion_elt->paddr);
+ }
+ }
+
+ return *region ? 0 : -1;
+}
+
+static phys_addr_t audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
+ unsigned long len, int ref_up, void **kvaddr)
+{
+ struct audio_aio_ion_region *region;
+ phys_addr_t paddr;
+ int ret;
+
+ ret = audio_aio_ion_lookup_vaddr(audio, addr, len, ®ion);
+ if (ret) {
+ pr_err("%s[%pK]:lookup (%pK, %ld) failed\n",
+ __func__, audio, addr, len);
+ return 0;
+ }
+ if (ref_up)
+ region->ref_cnt++;
+ else
+ region->ref_cnt--;
+ pr_debug("%s[%pK]:found region %pK ref_cnt %d\n",
+ __func__, audio, region, region->ref_cnt);
+ paddr = region->paddr + (addr - region->vaddr);
+ /* provide kernel virtual address for accessing meta information */
+ if (kvaddr)
+ *kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
+ return paddr;
+}
+
+static int audio_aio_pause(struct q6audio_aio *audio)
+{
+ int rc = -EINVAL;
+
+ pr_debug("%s[%pK], enabled = %d\n", __func__, audio,
+ audio->enabled);
+ if (audio->enabled) {
+ rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+ if (rc < 0)
+ pr_err("%s[%pK]: pause cmd failed rc=%d\n",
+ __func__, audio, rc);
+
+ if (rc == 0) {
+ /* Send suspend only if pause was successful */
+ rc = q6asm_cmd(audio->ac, CMD_SUSPEND);
+ if (rc < 0)
+ pr_err("%s[%pK]: suspend cmd failed rc=%d\n",
+ __func__, audio, rc);
+ } else
+ pr_err("%s[%pK]: not sending suspend since pause failed\n",
+ __func__, audio);
+
+ } else
+ pr_err("%s[%pK]: Driver not enabled\n", __func__, audio);
+ return rc;
+}
+
+static int audio_aio_flush(struct q6audio_aio *audio)
+{
+ int rc = 0;
+
+ if (audio->enabled) {
+ /* Implicitly issue a pause to the decoder before flushing if
+ * it is not in pause state
+ */
+ if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+ rc = audio_aio_pause(audio);
+ if (rc < 0)
+ pr_err("%s[%pK}: pause cmd failed rc=%d\n",
+ __func__, audio,
+ rc);
+ else
+ audio->drv_status |= ADRV_STATUS_PAUSE;
+ }
+ rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+ if (rc < 0)
+ pr_err("%s[%pK]: flush cmd failed rc=%d\n",
+ __func__, audio, rc);
+ /* Not in stop state, reenable the stream */
+ if (audio->stopped == 0) {
+ rc = audio_aio_enable(audio);
+ if (rc)
+ pr_err("%s[%pK]:audio re-enable failed\n",
+ __func__, audio);
+ else {
+ audio->enabled = 1;
+ if (audio->drv_status & ADRV_STATUS_PAUSE)
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+ }
+ }
+ }
+ pr_debug("%s[%pK]:in_bytes %d\n",
+ __func__, audio, atomic_read(&audio->in_bytes));
+ pr_debug("%s[%pK]:in_samples %d\n",
+ __func__, audio, atomic_read(&audio->in_samples));
+ atomic_set(&audio->in_bytes, 0);
+ atomic_set(&audio->in_samples, 0);
+ return rc;
+}
+
+static int audio_aio_outport_flush(struct q6audio_aio *audio)
+{
+ int rc;
+
+ rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
+ if (rc < 0)
+ pr_err("%s[%pK}: output port flush cmd failed rc=%d\n",
+ __func__, audio, rc);
+ return rc;
+}
+
+/* Write buffer to DSP / Handle Ack from DSP */
+void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
+ uint32_t *payload)
+{
+ unsigned long flags;
+ union msm_audio_event_payload event_payload;
+ struct audio_aio_buffer_node *used_buf;
+
+ /* No active flush in progress */
+ if (audio->wflush)
+ return;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ if (list_empty(&audio->out_queue)) {
+ pr_warn("%s: ignore unexpected event from dsp\n", __func__);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ return;
+ }
+ used_buf = list_first_entry(&audio->out_queue,
+ struct audio_aio_buffer_node, list);
+ if (token == used_buf->token) {
+ list_del(&used_buf->list);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ pr_debug("%s[%pK]:consumed buffer\n", __func__, audio);
+ event_payload.aio_buf = used_buf->buf;
+ audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+ event_payload);
+ kfree(used_buf);
+ if (list_empty(&audio->out_queue) &&
+ (audio->drv_status & ADRV_STATUS_FSYNC)) {
+ pr_debug("%s[%pK]: list is empty, reached EOS in Tunnel\n",
+ __func__, audio);
+ wake_up(&audio->write_wait);
+ }
+ } else {
+ pr_err("%s[%pK]:expected=%x ret=%x\n",
+ __func__, audio, used_buf->token, token);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ }
+}
+
+/* ------------------- device --------------------- */
+void audio_aio_async_out_flush(struct q6audio_aio *audio)
+{
+ struct audio_aio_buffer_node *buf_node;
+ struct list_head *ptr, *next;
+ union msm_audio_event_payload payload;
+ unsigned long flags;
+
+ pr_debug("%s[%pK}\n", __func__, audio);
+ /* EOS followed by flush, EOS response not guranteed, free EOS i/p
+ * buffer
+ */
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+
+ if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
+ pr_debug("%s[%pK]: EOS followed by flush received,acknowledge",
+ "eos i/p buffer immediately\n", __func__, audio);
+ audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+ audio->eos_write_payload);
+ memset(&audio->eos_write_payload, 0,
+ sizeof(union msm_audio_event_payload));
+ }
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ list_for_each_safe(ptr, next, &audio->out_queue) {
+ buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
+ list_del(&buf_node->list);
+ payload.aio_buf = buf_node->buf;
+ audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
+ kfree(buf_node);
+ pr_debug("%s[%pK]: Propagate WRITE_DONE during flush\n",
+ __func__, audio);
+ }
+}
+
+void audio_aio_async_in_flush(struct q6audio_aio *audio)
+{
+ struct audio_aio_buffer_node *buf_node;
+ struct list_head *ptr, *next;
+ union msm_audio_event_payload payload;
+
+ pr_debug("%s[%pK]\n", __func__, audio);
+ list_for_each_safe(ptr, next, &audio->in_queue) {
+ buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
+ list_del(&buf_node->list);
+ /* Forcefull send o/p eos buffer after flush, if no eos response
+ * received by dsp even after sending eos command
+ */
+ if ((audio->eos_rsp != 1) && audio->eos_flag) {
+ pr_debug("%s[%pK]: send eos on o/p buffer during flush\n",
+ __func__, audio);
+ payload.aio_buf = buf_node->buf;
+ payload.aio_buf.data_len =
+ insert_eos_buf(audio, buf_node);
+ audio->eos_flag = 0;
+ } else {
+ payload.aio_buf = buf_node->buf;
+ payload.aio_buf.data_len =
+ insert_meta_data_flush(audio, buf_node);
+ }
+ audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
+ kfree(buf_node);
+ pr_debug("%s[%pK]: Propagate READ_DONE during flush\n",
+ __func__, audio);
+ }
+}
+
+int audio_aio_enable(struct q6audio_aio *audio)
+{
+ /* 2nd arg: 0 -> run immediately
+ * 3rd arg: 0 -> msw_ts,
+ * 4th arg: 0 ->lsw_ts
+ */
+ return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+int audio_aio_disable(struct q6audio_aio *audio)
+{
+ int rc = 0;
+
+ if (audio->opened) {
+ audio->enabled = 0;
+ audio->opened = 0;
+ pr_debug("%s[%pK]: inbytes[%d] insamples[%d]\n", __func__,
+ audio, atomic_read(&audio->in_bytes),
+ atomic_read(&audio->in_samples));
+ /* Close the session */
+ rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+ if (rc < 0)
+ pr_err("%s[%pK]:Failed to close the session rc=%d\n",
+ __func__, audio, rc);
+ audio->stopped = 1;
+ wake_up(&audio->write_wait);
+ wake_up(&audio->cmd_wait);
+ }
+ pr_debug("%s[%pK]:enabled[%d]\n", __func__, audio, audio->enabled);
+ return rc;
+}
+
+void audio_aio_reset_ion_region(struct q6audio_aio *audio)
+{
+ struct audio_aio_ion_region *region;
+ struct list_head *ptr, *next;
+
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audio_aio_ion_region, list);
+ list_del(®ion->list);
+ msm_audio_ion_free_legacy(audio->client, region->handle);
+ kfree(region);
+ }
+}
+
+void audio_aio_reset_event_queue(struct q6audio_aio *audio)
+{
+ unsigned long flags;
+ struct audio_aio_event *drv_evt;
+ struct list_head *ptr, *next;
+
+ spin_lock_irqsave(&audio->event_queue_lock, flags);
+ list_for_each_safe(ptr, next, &audio->event_queue) {
+ drv_evt = list_first_entry(&audio->event_queue,
+ struct audio_aio_event, list);
+ list_del(&drv_evt->list);
+ kfree(drv_evt);
+ }
+ list_for_each_safe(ptr, next, &audio->free_event_queue) {
+ drv_evt = list_first_entry(&audio->free_event_queue,
+ struct audio_aio_event, list);
+ list_del(&drv_evt->list);
+ kfree(drv_evt);
+ }
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+}
+
+static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
+{
+ struct audio_aio_ion_region *region;
+ struct list_head *ptr, *next;
+ int rc = -EINVAL;
+
+ pr_debug("%s[%pK]:\n", __func__, audio);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audio_aio_ion_region, list);
+ if (region != NULL) {
+ pr_debug("%s[%pK]: phy_address = 0x%pK\n",
+ __func__, audio, ®ion->paddr);
+ rc = q6asm_memory_unmap(audio->ac,
+ region->paddr, IN);
+ if (rc < 0)
+ pr_err("%s[%pK]: memory unmap failed\n",
+ __func__, audio);
+ }
+ }
+}
+
+#ifdef CONFIG_USE_DEV_CTRL_VOLUME
+
+static void audio_aio_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+ void *private_data)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *) private_data;
+ int rc = 0;
+
+ switch (evt_id) {
+ case AUDDEV_EVT_STREAM_VOL_CHG:
+ audio->volume = evt_payload->session_vol;
+ pr_debug("%s[%pK]: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, enabled = %d\n",
+ __func__, audio, audio->volume, audio->enabled);
+ if (audio->enabled == 1) {
+ if (audio->ac) {
+ rc = q6asm_set_volume(audio->ac, audio->volume);
+ if (rc < 0) {
+ pr_err("%s[%pK]: Send Volume command failed rc=%d\n",
+ __func__, audio, rc);
+ }
+ }
+ }
+ break;
+ default:
+ pr_err("%s[%pK]:ERROR:wrong event\n", __func__, audio);
+ break;
+ }
+}
+
+int register_volume_listener(struct q6audio_aio *audio)
+{
+ int rc = 0;
+
+ audio->device_events = AUDDEV_EVT_STREAM_VOL_CHG;
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+
+ rc = auddev_register_evt_listner(audio->device_events,
+ AUDDEV_CLNT_DEC,
+ audio->ac->session,
+ audio_aio_listner,
+ (void *)audio);
+ if (rc < 0) {
+ pr_err("%s[%pK]: Event listener failed\n", __func__, audio);
+ rc = -EACCES;
+ }
+ return rc;
+}
+void unregister_volume_listener(struct q6audio_aio *audio)
+{
+ auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
+}
+
+int enable_volume_ramp(struct q6audio_aio *audio)
+{
+ int rc = 0;
+ struct asm_softpause_params softpause;
+ struct asm_softvolume_params softvol;
+
+ if (audio->ac == NULL)
+ return -EINVAL;
+ pr_debug("%s[%pK]\n", __func__, audio);
+ softpause.enable = SOFT_PAUSE_ENABLE;
+ softpause.period = SOFT_PAUSE_PERIOD;
+ softpause.step = SOFT_PAUSE_STEP;
+ softpause.rampingcurve = SOFT_PAUSE_CURVE_LINEAR;
+
+ softvol.period = SOFT_VOLUME_PERIOD;
+ softvol.step = SOFT_VOLUME_STEP;
+ softvol.rampingcurve = SOFT_VOLUME_CURVE_LINEAR;
+
+ if (softpause.rampingcurve == SOFT_PAUSE_CURVE_LINEAR)
+ softpause.step = SOFT_PAUSE_STEP_LINEAR;
+ if (softvol.rampingcurve == SOFT_VOLUME_CURVE_LINEAR)
+ softvol.step = SOFT_VOLUME_STEP_LINEAR;
+ rc = q6asm_set_volume(audio->ac, audio->volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ rc = q6asm_set_softpause(audio->ac, &softpause);
+ if (rc < 0) {
+ pr_err("%s: Send SoftPause Param failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ rc = q6asm_set_softvolume(audio->ac, &softvol);
+ if (rc < 0) {
+ pr_err("%s: Send SoftVolume Param failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ /* disable mute by default */
+ rc = q6asm_set_mute(audio->ac, 0);
+ if (rc < 0) {
+ pr_err("%s: Send mute command failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ return rc;
+}
+
+#else /*CONFIG_USE_DEV_CTRL_VOLUME*/
+int register_volume_listener(struct q6audio_aio *audio)
+{
+ return 0;/* do nothing */
+}
+void unregister_volume_listener(struct q6audio_aio *audio)
+{
+ return;/* do nothing */
+}
+int enable_volume_ramp(struct q6audio_aio *audio)
+{
+ return 0; /* do nothing */
+}
+#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
+
+int audio_aio_release(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = file->private_data;
+
+ pr_debug("%s[%pK]\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
+ audio->wflush = 1;
+ if (audio->wakelock_voted &&
+ (audio->audio_ws_mgr != NULL) &&
+ (audio->miscdevice != NULL)) {
+ audio->wakelock_voted = false;
+ mutex_lock(&audio->audio_ws_mgr->ws_lock);
+ if ((audio->audio_ws_mgr->ref_cnt > 0) &&
+ (--audio->audio_ws_mgr->ref_cnt == 0)) {
+ pm_relax(audio->miscdevice->this_device);
+ }
+ mutex_unlock(&audio->audio_ws_mgr->ws_lock);
+ }
+ if (audio->enabled)
+ audio_aio_flush(audio);
+ audio->wflush = 0;
+ audio->drv_ops.out_flush(audio);
+ audio->drv_ops.in_flush(audio);
+ audio_aio_disable(audio);
+ audio_aio_unmap_ion_region(audio);
+ audio_aio_reset_ion_region(audio);
+ msm_audio_ion_client_destroy(audio->client);
+ audio->event_abort = 1;
+ wake_up(&audio->event_wait);
+ audio_aio_reset_event_queue(audio);
+ q6asm_audio_client_free(audio->ac);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
+ mutex_unlock(&audio->lock);
+ mutex_destroy(&audio->lock);
+ mutex_destroy(&audio->read_lock);
+ mutex_destroy(&audio->write_lock);
+ mutex_destroy(&audio->get_event_lock);
+ unregister_volume_listener(audio);
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(audio->dentry);
+#endif
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return 0;
+}
+
+int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ int rc = 0;
+ struct q6audio_aio *audio = file->private_data;
+
+ if (!audio->enabled || audio->feedback)
+ return -EINVAL;
+
+ /* Blocking client sends more data */
+ mutex_lock(&audio->lock);
+ audio->drv_status |= ADRV_STATUS_FSYNC;
+ mutex_unlock(&audio->lock);
+
+ pr_debug("%s[%pK]:\n", __func__, audio);
+
+ audio->eos_rsp = 0;
+
+ pr_debug("%s[%pK]Wait for write done from DSP\n", __func__, audio);
+ rc = wait_event_interruptible(audio->write_wait,
+ (list_empty(&audio->out_queue)) ||
+ audio->wflush || audio->stopped);
+
+ if (audio->stopped || audio->wflush) {
+ pr_debug("%s[%pK]: Audio Flushed or Stopped,this is not EOS\n"
+ , __func__, audio);
+ audio->wflush = 0;
+ rc = -EBUSY;
+ }
+
+ if (rc < 0) {
+ pr_err("%s[%pK]: wait event for list_empty failed, rc = %d\n",
+ __func__, audio, rc);
+ goto done;
+ }
+
+ rc = q6asm_cmd(audio->ac, CMD_EOS);
+ pr_debug("%s[%pK]: EOS cmd sent to DSP\n", __func__, audio);
+
+ if (rc < 0)
+ pr_err("%s[%pK]: q6asm_cmd failed, rc = %d",
+ __func__, audio, rc);
+
+ pr_debug("%s[%pK]: wait for RENDERED_EOS from DSP\n"
+ , __func__, audio);
+ rc = wait_event_interruptible(audio->write_wait,
+ (audio->eos_rsp || audio->wflush ||
+ audio->stopped));
+
+ if (rc < 0) {
+ pr_err("%s[%pK]: wait event for eos_rsp failed, rc = %d\n",
+ __func__, audio, rc);
+ goto done;
+ }
+
+ if (audio->stopped || audio->wflush) {
+ audio->wflush = 0;
+ pr_debug("%s[%pK]: Audio Flushed or Stopped,this is not EOS\n"
+ , __func__, audio);
+ rc = -EBUSY;
+ }
+
+ if (audio->eos_rsp == 1)
+ pr_debug("%s[%pK]: EOS\n", __func__, audio);
+
+
+done:
+ mutex_lock(&audio->lock);
+ audio->drv_status &= ~ADRV_STATUS_FSYNC;
+ mutex_unlock(&audio->lock);
+
+ return rc;
+}
+
+static int audio_aio_events_pending(struct q6audio_aio *audio)
+{
+ unsigned long flags;
+ int empty;
+
+ spin_lock_irqsave(&audio->event_queue_lock, flags);
+ empty = !list_empty(&audio->event_queue);
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+ return empty || audio->event_abort || audio->reset_event;
+}
+
+static long audio_aio_process_event_req_common(struct q6audio_aio *audio,
+ struct msm_audio_event *usr_evt)
+{
+ long rc;
+ struct audio_aio_event *drv_evt = NULL;
+ int timeout;
+ unsigned long flags;
+
+ timeout = usr_evt->timeout_ms;
+
+ if (timeout > 0) {
+ rc = wait_event_interruptible_timeout(audio->event_wait,
+ audio_aio_events_pending
+ (audio),
+ msecs_to_jiffies
+ (timeout));
+ if (rc == 0)
+ return -ETIMEDOUT;
+ } else {
+ rc = wait_event_interruptible(audio->event_wait,
+ audio_aio_events_pending(audio));
+ }
+ if (rc < 0)
+ return rc;
+
+ if (audio->reset_event) {
+ audio->reset_event = false;
+ pr_err("In SSR, post ENETRESET err\n");
+ return -ENETRESET;
+ }
+
+ if (audio->event_abort) {
+ audio->event_abort = 0;
+ return -ENODEV;
+ }
+
+ rc = 0;
+
+ spin_lock_irqsave(&audio->event_queue_lock, flags);
+ if (!list_empty(&audio->event_queue)) {
+ drv_evt = list_first_entry(&audio->event_queue,
+ struct audio_aio_event, list);
+ list_del(&drv_evt->list);
+ }
+ if (drv_evt) {
+ usr_evt->event_type = drv_evt->event_type;
+ usr_evt->event_payload = drv_evt->payload;
+ list_add_tail(&drv_evt->list, &audio->free_event_queue);
+ } else {
+ pr_err("%s[%pK]:Unexpected path\n", __func__, audio);
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+ return -EPERM;
+ }
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+ if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+ pr_debug("%s[%pK]:posted AUDIO_EVENT_WRITE_DONE to user\n",
+ __func__, audio);
+ mutex_lock(&audio->write_lock);
+ audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ drv_evt->payload.aio_buf.buf_len, 0, 0);
+ mutex_unlock(&audio->write_lock);
+ } else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+ pr_debug("%s[%pK]:posted AUDIO_EVENT_READ_DONE to user\n",
+ __func__, audio);
+ mutex_lock(&audio->read_lock);
+ audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ drv_evt->payload.aio_buf.buf_len, 0, 0);
+ mutex_unlock(&audio->read_lock);
+ }
+
+ /* Some read buffer might be held up in DSP,release all
+ * Once EOS indicated
+ */
+ if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
+ pr_debug("%s[%pK]:Send flush command to release read buffers",
+ "held up in DSP\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ audio_aio_flush(audio);
+ mutex_unlock(&audio->lock);
+ }
+
+ return rc;
+}
+
+static long audio_aio_process_event_req(struct q6audio_aio *audio,
+ void __user *arg)
+{
+ long rc;
+ struct msm_audio_event usr_evt;
+
+ if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event))) {
+ pr_err("%s: copy_from_user failed\n", __func__);
+ return -EFAULT;
+ }
+
+ rc = audio_aio_process_event_req_common(audio, &usr_evt);
+
+ if (copy_to_user(arg, &usr_evt, sizeof(usr_evt))) {
+ pr_err("%s: copy_to_user failed\n", __func__);
+ rc = -EFAULT;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+
+struct msm_audio_aio_buf32 {
+ compat_uptr_t buf_addr;
+ u32 buf_len;
+ u32 data_len;
+ compat_uptr_t private_data;
+ u16 mfield_sz; /*only useful for data has meta field */
+};
+
+struct msm_audio_bitstream_info32 {
+ u32 codec_type;
+ u32 chan_info;
+ u32 sample_rate;
+ u32 bit_stream_info;
+ u32 bit_rate;
+ u32 unused[3];
+};
+
+struct msm_audio_bitstream_error_info32 {
+ u32 dec_id;
+ u32 err_msg_indicator;
+ u32 err_type;
+};
+
+union msm_audio_event_payload32 {
+ struct msm_audio_aio_buf32 aio_buf;
+ struct msm_audio_bitstream_info32 stream_info;
+ struct msm_audio_bitstream_error_info32 error_info;
+ s32 reserved;
+};
+
+struct msm_audio_event32 {
+ s32 event_type;
+ s32 timeout_ms;
+ union msm_audio_event_payload32 event_payload;
+};
+
+static long audio_aio_process_event_req_compat(struct q6audio_aio *audio,
+ void __user *arg)
+{
+ long rc;
+ struct msm_audio_event32 usr_evt_32;
+ struct msm_audio_event usr_evt;
+
+ if (copy_from_user(&usr_evt_32, arg,
+ sizeof(struct msm_audio_event32))) {
+ pr_err("%s: copy_from_user failed\n", __func__);
+ return -EFAULT;
+ }
+ usr_evt.timeout_ms = usr_evt_32.timeout_ms;
+
+ rc = audio_aio_process_event_req_common(audio, &usr_evt);
+
+ usr_evt_32.event_type = usr_evt.event_type;
+ switch (usr_evt_32.event_type) {
+ case AUDIO_EVENT_SUSPEND:
+ case AUDIO_EVENT_RESUME:
+ case AUDIO_EVENT_WRITE_DONE:
+ case AUDIO_EVENT_READ_DONE:
+ usr_evt_32.event_payload.aio_buf.buf_addr =
+ ptr_to_compat(usr_evt.event_payload.aio_buf.buf_addr);
+ usr_evt_32.event_payload.aio_buf.buf_len =
+ usr_evt.event_payload.aio_buf.buf_len;
+ usr_evt_32.event_payload.aio_buf.data_len =
+ usr_evt.event_payload.aio_buf.data_len;
+ usr_evt_32.event_payload.aio_buf.private_data =
+ ptr_to_compat(usr_evt.event_payload.aio_buf.private_data);
+ usr_evt_32.event_payload.aio_buf.mfield_sz =
+ usr_evt.event_payload.aio_buf.mfield_sz;
+ break;
+ case AUDIO_EVENT_STREAM_INFO:
+ usr_evt_32.event_payload.stream_info.codec_type =
+ usr_evt.event_payload.stream_info.codec_type;
+ usr_evt_32.event_payload.stream_info.chan_info =
+ usr_evt.event_payload.stream_info.chan_info;
+ usr_evt_32.event_payload.stream_info.sample_rate =
+ usr_evt.event_payload.stream_info.sample_rate;
+ usr_evt_32.event_payload.stream_info.bit_stream_info =
+ usr_evt.event_payload.stream_info.bit_stream_info;
+ usr_evt_32.event_payload.stream_info.bit_rate =
+ usr_evt.event_payload.stream_info.bit_rate;
+ break;
+ case AUDIO_EVENT_BITSTREAM_ERROR_INFO:
+ usr_evt_32.event_payload.error_info.dec_id =
+ usr_evt.event_payload.error_info.dec_id;
+ usr_evt_32.event_payload.error_info.err_msg_indicator =
+ usr_evt.event_payload.error_info.err_msg_indicator;
+ usr_evt_32.event_payload.error_info.err_type =
+ usr_evt.event_payload.error_info.err_type;
+ break;
+ default:
+ pr_debug("%s: unknown audio event type = %d rc = %ld",
+ __func__, usr_evt_32.event_type, rc);
+ return rc;
+ }
+ if (copy_to_user(arg, &usr_evt_32, sizeof(usr_evt_32))) {
+ pr_err("%s: copy_to_user failed\n", __func__);
+ rc = -EFAULT;
+ }
+ return rc;
+}
+#endif
+
+static int audio_aio_ion_check(struct q6audio_aio *audio,
+ void *vaddr, unsigned long len)
+{
+ struct audio_aio_ion_region *region_elt;
+ struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
+
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
+ if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+ OVERLAPS(region_elt, &t)) {
+ pr_err("%s[%pK]:region (vaddr %pK len %ld) clashes with registered region (vaddr %pK paddr %pK len %ld)\n",
+ __func__, audio, vaddr, len,
+ region_elt->vaddr,
+ ®ion_elt->paddr, region_elt->len);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int audio_aio_ion_add(struct q6audio_aio *audio,
+ struct msm_audio_ion_info *info)
+{
+ ion_phys_addr_t paddr = 0;
+ size_t len = 0;
+ struct audio_aio_ion_region *region;
+ int rc = -EINVAL;
+ struct ion_handle *handle = NULL;
+ unsigned long ionflag;
+ void *kvaddr = NULL;
+
+ pr_debug("%s[%pK]:\n", __func__, audio);
+ region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+ if (!region) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ rc = msm_audio_ion_import_legacy("Audio_Dec_Client", audio->client,
+ &handle, info->fd, &ionflag,
+ 0, &paddr, &len, &kvaddr);
+ if (rc) {
+ pr_err("%s: msm audio ion alloc failed\n", __func__);
+ goto import_error;
+ }
+
+ rc = audio_aio_ion_check(audio, info->vaddr, len);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_ion_check failed\n", __func__);
+ goto ion_error;
+ }
+
+ region->handle = handle;
+ region->vaddr = info->vaddr;
+ region->fd = info->fd;
+ region->paddr = paddr;
+ region->kvaddr = kvaddr;
+ region->len = len;
+ region->ref_cnt = 0;
+ pr_debug("%s[%pK]:add region paddr %pK vaddr %pK, len %lu kvaddr %pK\n",
+ __func__, audio,
+ ®ion->paddr, region->vaddr, region->len,
+ region->kvaddr);
+ list_add_tail(®ion->list, &audio->ion_region_queue);
+ rc = q6asm_memory_map(audio->ac, paddr, IN, len, 1);
+ if (rc < 0) {
+ pr_err("%s[%pK]: memory map failed\n", __func__, audio);
+ goto mmap_error;
+ } else {
+ goto end;
+ }
+mmap_error:
+ list_del(®ion->list);
+ion_error:
+ msm_audio_ion_free_legacy(audio->client, handle);
+import_error:
+ kfree(region);
+end:
+ return rc;
+}
+
+static int audio_aio_ion_remove(struct q6audio_aio *audio,
+ struct msm_audio_ion_info *info)
+{
+ struct audio_aio_ion_region *region;
+ struct list_head *ptr, *next;
+ int rc = -EINVAL;
+
+ pr_debug("%s[%pK]:info fd %d vaddr %pK\n",
+ __func__, audio, info->fd, info->vaddr);
+
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audio_aio_ion_region, list);
+
+ if ((region->fd == info->fd) &&
+ (region->vaddr == info->vaddr)) {
+ if (region->ref_cnt) {
+ pr_debug("%s[%pK]:region %pK in use ref_cnt %d\n",
+ __func__, audio, region,
+ region->ref_cnt);
+ break;
+ }
+ pr_debug("%s[%pK]:remove region fd %d vaddr %pK\n",
+ __func__, audio, info->fd, info->vaddr);
+ rc = q6asm_memory_unmap(audio->ac,
+ region->paddr, IN);
+ if (rc < 0)
+ pr_err("%s[%pK]: memory unmap failed\n",
+ __func__, audio);
+
+ list_del(®ion->list);
+ msm_audio_ion_free_legacy(audio->client,
+ region->handle);
+ kfree(region);
+ rc = 0;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static int audio_aio_async_write(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node)
+{
+ int rc;
+ struct audio_client *ac;
+ struct audio_aio_write_param param;
+
+ if (!audio || !buf_node) {
+ pr_err("%s NULL pointer audio=[0x%pK], buf_node=[0x%pK]\n",
+ __func__, audio, buf_node);
+ return -EINVAL;
+ }
+ pr_debug("%s[%pK]: Send write buff %pK phy %pK len %d meta_enable = %d\n",
+ __func__, audio, buf_node, &buf_node->paddr,
+ buf_node->buf.data_len,
+ audio->buf_cfg.meta_info_enable);
+ pr_debug("%s[%pK]: flags = 0x%x\n", __func__, audio,
+ buf_node->meta_info.meta_in.nflags);
+
+ ac = audio->ac;
+ /* Offset with appropriate meta */
+ if (audio->feedback) {
+ /* Non Tunnel mode */
+ param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
+ param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
+ } else {
+ /* Tunnel mode */
+ param.paddr = buf_node->paddr;
+ param.len = buf_node->buf.data_len;
+ }
+ param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
+ param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
+ param.flags = buf_node->meta_info.meta_in.nflags;
+ /* If no meta_info enaled, indicate no time stamp valid */
+ if (!audio->buf_cfg.meta_info_enable)
+ param.flags = 0xFF00;
+
+ if (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET)
+ param.flags |= AUDIO_DEC_EOF_SET;
+
+ param.uid = ac->session;
+ /* Read command will populate session id as token */
+ buf_node->token = ac->session;
+ rc = q6asm_async_write(ac, ¶m);
+ if (rc < 0)
+ pr_err("%s[%pK]:failed\n", __func__, audio);
+ return rc;
+}
+
+void audio_aio_post_event(struct q6audio_aio *audio, int type,
+ union msm_audio_event_payload payload)
+{
+ struct audio_aio_event *e_node = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+ if (!list_empty(&audio->free_event_queue)) {
+ e_node = list_first_entry(&audio->free_event_queue,
+ struct audio_aio_event, list);
+ list_del(&e_node->list);
+ } else {
+ e_node = kmalloc(sizeof(struct audio_aio_event), GFP_ATOMIC);
+ if (!e_node) {
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+ return;
+ }
+ }
+
+ e_node->event_type = type;
+ e_node->payload = payload;
+
+ list_add_tail(&e_node->list, &audio->event_queue);
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+ wake_up(&audio->event_wait);
+}
+
+static int audio_aio_async_read(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node)
+{
+ struct audio_client *ac;
+ struct audio_aio_read_param param;
+ int rc;
+
+ pr_debug("%s[%pK]: Send read buff %pK phy %pK len %d\n",
+ __func__, audio, buf_node,
+ &buf_node->paddr, buf_node->buf.buf_len);
+ ac = audio->ac;
+ /* Provide address so driver can append nr frames information */
+ param.paddr = buf_node->paddr +
+ sizeof(struct dec_meta_out);
+ param.len = buf_node->buf.buf_len -
+ sizeof(struct dec_meta_out);
+ param.uid = ac->session;
+ /* Write command will populate session_id as token */
+ buf_node->token = ac->session;
+ rc = q6asm_async_read(ac, ¶m);
+ if (rc < 0)
+ pr_err("%s[%pK]:failed\n", __func__, audio);
+ return rc;
+}
+
+static int audio_aio_buf_add_shared(struct q6audio_aio *audio, u32 dir,
+ struct audio_aio_buffer_node *buf_node)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ pr_debug("%s[%pK]:node %pK dir %x buf_addr %pK buf_len %d data_len %d\n",
+ __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
+ buf_node->buf.buf_len, buf_node->buf.data_len);
+ buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
+ buf_node->buf.buf_len, 1,
+ &buf_node->kvaddr);
+ if (dir) {
+ /* write */
+ if (!buf_node->paddr ||
+ (buf_node->paddr & 0x1) ||
+ (!audio->feedback && !buf_node->buf.data_len)) {
+ kfree(buf_node);
+ return -EINVAL;
+ }
+ extract_meta_out_info(audio, buf_node, 1);
+ /* Not a EOS buffer */
+ if (!(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOS_SET)) {
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ ret = audio_aio_async_write(audio, buf_node);
+ /* EOS buffer handled in driver */
+ list_add_tail(&buf_node->list, &audio->out_queue);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ } else if (buf_node->meta_info.meta_in.nflags
+ & AUDIO_DEC_EOS_SET) {
+ if (!audio->wflush) {
+ pr_debug("%s[%pK]:Send EOS cmd at i/p\n",
+ __func__, audio);
+ /* Driver will forcefully post writedone event
+ * once eos ack recived from DSP
+ */
+ audio->eos_write_payload.aio_buf =
+ buf_node->buf;
+ audio->eos_flag = 1;
+ audio->eos_rsp = 0;
+ q6asm_cmd(audio->ac, CMD_EOS);
+ kfree(buf_node);
+ } else { /* Flush in progress, send back i/p
+ * EOS buffer as is
+ */
+ union msm_audio_event_payload event_payload;
+
+ event_payload.aio_buf = buf_node->buf;
+ audio_aio_post_event(audio,
+ AUDIO_EVENT_WRITE_DONE,
+ event_payload);
+ kfree(buf_node);
+ }
+ }
+ } else {
+ /* read */
+ if (!buf_node->paddr ||
+ (buf_node->paddr & 0x1) ||
+ (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
+ kfree(buf_node);
+ return -EINVAL;
+ }
+ /* No EOS reached */
+ if (!audio->eos_rsp) {
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ ret = audio_aio_async_read(audio, buf_node);
+ /* EOS buffer handled in driver */
+ list_add_tail(&buf_node->list, &audio->in_queue);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ }
+ /* EOS reached at input side fake all upcoming read buffer to
+ * indicate the same
+ */
+ else {
+ union msm_audio_event_payload event_payload;
+
+ event_payload.aio_buf = buf_node->buf;
+ event_payload.aio_buf.data_len =
+ insert_eos_buf(audio, buf_node);
+ pr_debug("%s[%pK]: propagate READ_DONE as EOS done\n",
+ __func__, audio);
+ audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
+ event_payload);
+ kfree(buf_node);
+ }
+ }
+ return ret;
+}
+#ifdef CONFIG_COMPAT
+static int audio_aio_buf_add_compat(struct q6audio_aio *audio, u32 dir,
+ void __user *arg)
+{
+ struct audio_aio_buffer_node *buf_node;
+ struct msm_audio_aio_buf32 aio_buf_32;
+
+ buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
+
+ if (!buf_node)
+ return -ENOMEM;
+
+ if (copy_from_user(&aio_buf_32, arg, sizeof(aio_buf_32))) {
+ kfree(buf_node);
+ pr_err("%s: copy_from_user failed\n", __func__);
+ return -EFAULT;
+ }
+
+ buf_node->buf.buf_addr = compat_ptr(aio_buf_32.buf_addr);
+ buf_node->buf.buf_len = aio_buf_32.buf_len;
+ buf_node->buf.data_len = aio_buf_32.data_len;
+ buf_node->buf.private_data = compat_ptr(aio_buf_32.private_data);
+ buf_node->buf.mfield_sz = aio_buf_32.mfield_sz;
+
+ return audio_aio_buf_add_shared(audio, dir, buf_node);
+}
+#endif
+
+static int audio_aio_buf_add(struct q6audio_aio *audio, u32 dir,
+ void __user *arg)
+{
+ struct audio_aio_buffer_node *buf_node;
+
+ buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
+
+ if (!buf_node)
+ return -ENOMEM;
+
+ if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+ kfree(buf_node);
+ pr_err("%s: copy_from_user failed\n", __func__);
+ return -EFAULT;
+ }
+
+ return audio_aio_buf_add_shared(audio, dir, buf_node);
+}
+
+void audio_aio_ioport_reset(struct q6audio_aio *audio)
+{
+ if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+ /* If fsync is in progress, make sure
+ * return value of fsync indicates
+ * abort due to flush
+ */
+ if (audio->drv_status & ADRV_STATUS_FSYNC) {
+ pr_debug("%s[%pK]:fsync in progress\n",
+ __func__, audio);
+ audio->drv_ops.out_flush(audio);
+ } else
+ audio->drv_ops.out_flush(audio);
+ if (audio->feedback == NON_TUNNEL_MODE)
+ audio->drv_ops.in_flush(audio);
+ }
+}
+
+int audio_aio_open(struct q6audio_aio *audio, struct file *file)
+{
+ int rc = 0;
+ int i;
+ struct audio_aio_event *e_node = NULL;
+ struct list_head *ptr, *next;
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ audio->pcm_cfg.sample_rate = 48000;
+ audio->pcm_cfg.channel_count = 2;
+
+ /* Only AIO interface */
+ if (file->f_flags & O_NONBLOCK) {
+ pr_debug("%s[%pK]:set to aio interface\n", __func__, audio);
+ audio->drv_status |= ADRV_STATUS_AIO_INTF;
+ audio->drv_ops.out_flush = audio_aio_async_out_flush;
+ audio->drv_ops.in_flush = audio_aio_async_in_flush;
+ q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+ } else {
+ pr_err("%s[%pK]:SIO interface not supported\n",
+ __func__, audio);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ /* Initialize all locks of audio instance */
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ mutex_init(&audio->get_event_lock);
+ spin_lock_init(&audio->dsp_lock);
+ spin_lock_init(&audio->event_queue_lock);
+ init_waitqueue_head(&audio->cmd_wait);
+ init_waitqueue_head(&audio->write_wait);
+ init_waitqueue_head(&audio->event_wait);
+ INIT_LIST_HEAD(&audio->out_queue);
+ INIT_LIST_HEAD(&audio->in_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
+ INIT_LIST_HEAD(&audio->free_event_queue);
+ INIT_LIST_HEAD(&audio->event_queue);
+
+ audio->drv_ops.out_flush(audio);
+ audio->opened = 1;
+ audio->reset_event = false;
+ file->private_data = audio;
+ audio->codec_ioctl = audio_aio_ioctl;
+ audio->codec_compat_ioctl = audio_aio_compat_ioctl;
+ for (i = 0; i < AUDIO_EVENT_NUM; i++) {
+ e_node = kmalloc(sizeof(struct audio_aio_event), GFP_KERNEL);
+ if (e_node)
+ list_add_tail(&e_node->list, &audio->free_event_queue);
+ else {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+ }
+ audio->client = msm_audio_ion_client_create("Audio_Dec_Client");
+ if (IS_ERR_OR_NULL(audio->client)) {
+ pr_err("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+ pr_debug("Ion client create in audio_aio_open %pK", audio->client);
+
+ rc = register_volume_listener(audio);
+ if (rc < 0)
+ goto ion_cleanup;
+
+ return 0;
+ion_cleanup:
+ msm_audio_ion_client_destroy(audio->client);
+ audio->client = NULL;
+cleanup:
+ list_for_each_safe(ptr, next, &audio->free_event_queue) {
+ e_node = list_first_entry(&audio->free_event_queue,
+ struct audio_aio_event, list);
+ list_del(&e_node->list);
+ kfree(e_node);
+ }
+fail:
+ return rc;
+}
+
+static long audio_aio_shared_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_ABORT_GET_EVENT: {
+ audio->event_abort = 1;
+ wake_up(&audio->event_wait);
+ break;
+ }
+ case AUDIO_OUTPORT_FLUSH: {
+ pr_debug("%s[%pK]:AUDIO_OUTPORT_FLUSH\n", __func__, audio);
+ mutex_lock(&audio->read_lock);
+ rc = audio_aio_outport_flush(audio);
+ if (rc < 0) {
+ pr_err("%s[%pK]: AUDIO_OUTPORT_FLUSH failed\n",
+ __func__, audio);
+ rc = -EINTR;
+ }
+ mutex_unlock(&audio->read_lock);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s[%pK]: AUDIO_STOP session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ mutex_lock(&audio->lock);
+ audio->stopped = 1;
+ rc = audio_aio_flush(audio);
+ if (rc < 0) {
+ pr_err("%s[%pK]:Audio Stop procedure failed rc=%d\n",
+ __func__, audio, rc);
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ audio->enabled = 0;
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+ if (audio->drv_status & ADRV_STATUS_FSYNC) {
+ pr_debug("%s[%pK] Waking up the audio_aio_fsync\n",
+ __func__, audio);
+ wake_up(&audio->write_wait);
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_PAUSE: {
+ pr_debug("%s[%pK]:AUDIO_PAUSE %ld\n", __func__, audio, arg);
+ mutex_lock(&audio->lock);
+ if (arg == 1) {
+ rc = audio_aio_pause(audio);
+ if (rc < 0) {
+ pr_err("%s[%pK]: pause FAILED rc=%d\n",
+ __func__, audio, rc);
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ audio->drv_status |= ADRV_STATUS_PAUSE;
+ } else if (arg == 0) {
+ if (audio->drv_status & ADRV_STATUS_PAUSE) {
+ rc = audio_aio_enable(audio);
+ if (rc)
+ pr_err("%s[%pK]: audio enable failed\n",
+ __func__, audio);
+ else {
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+ audio->enabled = 1;
+ }
+ }
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_FLUSH: {
+ pr_debug("%s[%pK]: AUDIO_FLUSH sessionid[%d]\n", __func__,
+ audio, audio->ac->session);
+ mutex_lock(&audio->lock);
+ audio->rflush = 1;
+ audio->wflush = 1;
+ if (audio->drv_status & ADRV_STATUS_FSYNC) {
+ pr_debug("%s[%pK] Waking up the audio_aio_fsync\n",
+ __func__, audio);
+ wake_up(&audio->write_wait);
+ }
+ /* Flush DSP */
+ rc = audio_aio_flush(audio);
+ /* Flush input / Output buffer in software*/
+ audio_aio_ioport_reset(audio);
+ if (rc < 0) {
+ pr_err("%s[%pK]:AUDIO_FLUSH interrupted\n",
+ __func__, audio);
+ rc = -EINTR;
+ } else {
+ audio->rflush = 0;
+ if (audio->drv_status & ADRV_STATUS_FSYNC)
+ wake_up(&audio->write_wait);
+ else
+ audio->wflush = 0;
+
+ }
+ audio->eos_flag = 0;
+ audio->eos_rsp = 0;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_GET_SESSION_ID: {
+ mutex_lock(&audio->lock);
+ if (copy_to_user((void *)arg, &audio->ac->session,
+ sizeof(u16))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_SESSION_ID failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_PM_AWAKE: {
+ if ((audio->audio_ws_mgr == NULL) ||
+ (audio->miscdevice == NULL)) {
+ pr_err("%s[%pK]: invalid ws_mgr or miscdevice",
+ __func__, audio);
+ rc = -EACCES;
+ break;
+ }
+ pr_debug("%s[%pK]:AUDIO_PM_AWAKE\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ if (!audio->wakelock_voted) {
+ audio->wakelock_voted = true;
+ mutex_lock(&audio->audio_ws_mgr->ws_lock);
+ if (audio->audio_ws_mgr->ref_cnt++ == 0)
+ pm_stay_awake(audio->miscdevice->this_device);
+ mutex_unlock(&audio->audio_ws_mgr->ws_lock);
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_PM_RELAX: {
+ if ((audio->audio_ws_mgr == NULL) ||
+ (audio->miscdevice == NULL)) {
+ pr_err("%s[%pK]: invalid ws_mgr or miscdevice",
+ __func__, audio);
+ rc = -EACCES;
+ break;
+ }
+ pr_debug("%s[%pK]:AUDIO_PM_RELAX\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ if (audio->wakelock_voted) {
+ audio->wakelock_voted = false;
+ mutex_lock(&audio->audio_ws_mgr->ws_lock);
+ if ((audio->audio_ws_mgr->ref_cnt > 0) &&
+ (--audio->audio_ws_mgr->ref_cnt == 0)) {
+ pm_relax(audio->miscdevice->this_device);
+ }
+ mutex_unlock(&audio->audio_ws_mgr->ws_lock);
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+
+
+}
+
+static long audio_aio_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_ABORT_GET_EVENT:
+ case AUDIO_OUTPORT_FLUSH:
+ case AUDIO_STOP:
+ case AUDIO_PAUSE:
+ case AUDIO_FLUSH:
+ case AUDIO_GET_SESSION_ID:
+ case AUDIO_PM_AWAKE:
+ case AUDIO_PM_RELAX:
+ rc = audio_aio_shared_ioctl(file, cmd, arg);
+ break;
+ case AUDIO_GET_STATS: {
+ struct msm_audio_stats stats;
+ uint64_t timestamp;
+
+ memset(&stats, 0, sizeof(struct msm_audio_stats));
+ stats.byte_count = atomic_read(&audio->in_bytes);
+ stats.sample_count = atomic_read(&audio->in_samples);
+ rc = q6asm_get_session_time(audio->ac, ×tamp);
+ if (rc >= 0)
+ memcpy(&stats.unused[0], ×tamp, sizeof(timestamp));
+ else
+ pr_debug("Error while getting timestamp\n");
+ if (copy_to_user((void *)arg, &stats, sizeof(stats))) {
+ pr_err("%s: copy_frm_user for AUDIO_GET_STATS failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_GET_EVENT: {
+ pr_debug("%s[%pK]:AUDIO_GET_EVENT\n", __func__, audio);
+ if (mutex_trylock(&audio->get_event_lock)) {
+ rc = audio_aio_process_event_req(audio,
+ (void __user *)arg);
+ mutex_unlock(&audio->get_event_lock);
+ } else
+ rc = -EBUSY;
+ break;
+ }
+ case AUDIO_ASYNC_WRITE: {
+ mutex_lock(&audio->write_lock);
+ if (audio->drv_status & ADRV_STATUS_FSYNC)
+ rc = -EBUSY;
+ else {
+ if (audio->enabled)
+ rc = audio_aio_buf_add(audio, 1,
+ (void __user *)arg);
+ else
+ rc = -EPERM;
+ }
+ mutex_unlock(&audio->write_lock);
+ break;
+ }
+ case AUDIO_ASYNC_READ: {
+ mutex_lock(&audio->read_lock);
+ if (audio->feedback)
+ rc = audio_aio_buf_add(audio, 0,
+ (void __user *)arg);
+ else
+ rc = -EPERM;
+ mutex_unlock(&audio->read_lock);
+ break;
+ }
+
+ case AUDIO_GET_STREAM_CONFIG: {
+ struct msm_audio_stream_config cfg;
+
+ mutex_lock(&audio->lock);
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.buffer_size = audio->str_cfg.buffer_size;
+ cfg.buffer_count = audio->str_cfg.buffer_count;
+ pr_debug("%s[%pK]:GET STREAM CFG %d %d\n",
+ __func__, audio, cfg.buffer_size, cfg.buffer_count);
+ if (copy_to_user((void *)arg, &cfg, sizeof(cfg))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_STREAM_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_SET_STREAM_CONFIG: {
+ struct msm_audio_stream_config cfg;
+
+ pr_debug("%s[%pK]:SET STREAM CONFIG\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_SET_STREAM_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ rc = 0;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_GET_CONFIG: {
+ struct msm_audio_config cfg;
+
+ mutex_lock(&audio->lock);
+ if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_SET_CONFIG: {
+ struct msm_audio_config config;
+
+ pr_err("%s[%pK]:AUDIO_SET_CONFIG\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ if (copy_from_user(&config, (void *)arg, sizeof(config))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_SET_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ if (audio->feedback != NON_TUNNEL_MODE) {
+ pr_err("%s[%pK]:Not sufficient permission to change the playback mode\n",
+ __func__, audio);
+ rc = -EACCES;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ if ((config.buffer_count > PCM_BUF_COUNT) ||
+ (config.buffer_count == 1))
+ config.buffer_count = PCM_BUF_COUNT;
+
+ if (config.buffer_size < PCM_BUFSZ_MIN)
+ config.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->pcm_cfg.buffer_count = config.buffer_count;
+ audio->pcm_cfg.buffer_size = config.buffer_size;
+ audio->pcm_cfg.channel_count = config.channel_count;
+ audio->pcm_cfg.sample_rate = config.sample_rate;
+ rc = 0;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_SET_BUF_CFG: {
+ struct msm_audio_buf_cfg cfg;
+
+ mutex_lock(&audio->lock);
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_GET_BUF CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ if ((audio->feedback == NON_TUNNEL_MODE) &&
+ !cfg.meta_info_enable) {
+ rc = -EFAULT;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+
+ audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+ pr_debug("%s[%pK]:session id %d: Set-buf-cfg: meta[%d]",
+ __func__, audio,
+ audio->ac->session, cfg.meta_info_enable);
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_GET_BUF_CFG: {
+ pr_debug("%s[%pK]:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__, audio,
+ audio->ac->session, audio->buf_cfg.meta_info_enable,
+ audio->buf_cfg.frames_per_buf);
+
+ mutex_lock(&audio->lock);
+ if (copy_to_user((void *)arg, &audio->buf_cfg,
+ sizeof(struct msm_audio_buf_cfg))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_BUF_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+
+ pr_debug("%s[%pK]:AUDIO_REGISTER_ION\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ if (copy_from_user(&info, (void *)arg, sizeof(info))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_REGISTER_ION failed\n",
+ __func__);
+ rc = -EFAULT;
+ } else {
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
+ rc = audio_aio_ion_add(audio, &info);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
+
+ mutex_lock(&audio->lock);
+ pr_debug("%s[%pK]:AUDIO_DEREGISTER_ION\n", __func__, audio);
+ if (copy_from_user(&info, (void *)arg, sizeof(info))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_DEREGISTER_ION failed\n",
+ __func__);
+ rc = -EFAULT;
+ } else {
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
+ rc = audio_aio_ion_remove(audio, &info);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_stream_config32 {
+ u32 buffer_size;
+ u32 buffer_count;
+};
+
+struct msm_audio_stats32 {
+ u32 byte_count;
+ u32 sample_count;
+ u32 unused[2];
+};
+
+struct msm_audio_config32 {
+ u32 buffer_size;
+ u32 buffer_count;
+ u32 channel_count;
+ u32 sample_rate;
+ u32 type;
+ u32 meta_field;
+ u32 bits;
+ u32 unused[3];
+};
+
+struct msm_audio_buf_cfg32 {
+ u32 meta_info_enable;
+ u32 frames_per_buf;
+};
+
+struct msm_audio_ion_info32 {
+ int fd;
+ compat_uptr_t vaddr;
+};
+
+enum {
+ AUDIO_GET_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, 3,
+ struct msm_audio_config32),
+ AUDIO_SET_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, 4,
+ struct msm_audio_config32),
+ AUDIO_GET_STATS_32 = _IOR(AUDIO_IOCTL_MAGIC, 5,
+ struct msm_audio_stats32),
+ AUDIO_GET_EVENT_32 = _IOR(AUDIO_IOCTL_MAGIC, 13,
+ struct msm_audio_event32),
+ AUDIO_ASYNC_WRITE_32 = _IOW(AUDIO_IOCTL_MAGIC, 17,
+ struct msm_audio_aio_buf32),
+ AUDIO_ASYNC_READ_32 = _IOW(AUDIO_IOCTL_MAGIC, 18,
+ struct msm_audio_aio_buf32),
+ AUDIO_SET_STREAM_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, 80,
+ struct msm_audio_stream_config32),
+ AUDIO_GET_STREAM_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, 81,
+ struct msm_audio_stream_config32),
+ AUDIO_GET_BUF_CFG_32 = _IOW(AUDIO_IOCTL_MAGIC, 93,
+ struct msm_audio_buf_cfg32),
+ AUDIO_SET_BUF_CFG_32 = _IOW(AUDIO_IOCTL_MAGIC, 94,
+ struct msm_audio_buf_cfg32),
+ AUDIO_REGISTER_ION_32 = _IOW(AUDIO_IOCTL_MAGIC, 97,
+ struct msm_audio_ion_info32),
+ AUDIO_DEREGISTER_ION_32 = _IOW(AUDIO_IOCTL_MAGIC, 98,
+ struct msm_audio_ion_info32),
+};
+
+static long audio_aio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_ABORT_GET_EVENT:
+ case AUDIO_OUTPORT_FLUSH:
+ case AUDIO_STOP:
+ case AUDIO_PAUSE:
+ case AUDIO_FLUSH:
+ case AUDIO_GET_SESSION_ID:
+ case AUDIO_PM_AWAKE:
+ case AUDIO_PM_RELAX:
+ rc = audio_aio_shared_ioctl(file, cmd, arg);
+ break;
+ case AUDIO_GET_STATS_32: {
+ struct msm_audio_stats32 stats;
+ uint64_t timestamp;
+
+ memset(&stats, 0, sizeof(struct msm_audio_stats32));
+ stats.byte_count = atomic_read(&audio->in_bytes);
+ stats.sample_count = atomic_read(&audio->in_samples);
+ rc = q6asm_get_session_time(audio->ac, ×tamp);
+ if (rc >= 0)
+ memcpy(&stats.unused[0], ×tamp, sizeof(timestamp));
+ else
+ pr_debug("Error while getting timestamp\n");
+ if (copy_to_user((void *)arg, &stats, sizeof(stats))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_STATS_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_GET_EVENT_32: {
+ pr_debug("%s[%pK]:AUDIO_GET_EVENT\n", __func__, audio);
+ if (mutex_trylock(&audio->get_event_lock)) {
+ rc = audio_aio_process_event_req_compat(audio,
+ (void __user *)arg);
+ mutex_unlock(&audio->get_event_lock);
+ } else
+ rc = -EBUSY;
+ break;
+ }
+ case AUDIO_ASYNC_WRITE_32: {
+ mutex_lock(&audio->write_lock);
+ if (audio->drv_status & ADRV_STATUS_FSYNC)
+ rc = -EBUSY;
+ else {
+ if (audio->enabled)
+ rc = audio_aio_buf_add_compat(audio, 1,
+ (void __user *)arg);
+ else
+ rc = -EPERM;
+ }
+ mutex_unlock(&audio->write_lock);
+ break;
+ }
+ case AUDIO_ASYNC_READ_32: {
+ mutex_lock(&audio->read_lock);
+ if (audio->feedback)
+ rc = audio_aio_buf_add_compat(audio, 0,
+ (void __user *)arg);
+ else
+ rc = -EPERM;
+ mutex_unlock(&audio->read_lock);
+ break;
+ }
+
+ case AUDIO_GET_STREAM_CONFIG_32: {
+ struct msm_audio_stream_config32 cfg;
+
+ mutex_lock(&audio->lock);
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.buffer_size = audio->str_cfg.buffer_size;
+ cfg.buffer_count = audio->str_cfg.buffer_count;
+ pr_debug("%s[%pK]:GET STREAM CFG %d %d\n",
+ __func__, audio, cfg.buffer_size, cfg.buffer_count);
+ if (copy_to_user((void *)arg, &cfg, sizeof(cfg))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_STREAM_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_SET_STREAM_CONFIG_32: {
+ struct msm_audio_stream_config32 cfg_32;
+ struct msm_audio_stream_config cfg;
+
+ pr_debug("%s[%pK]:SET STREAM CONFIG\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_STREAM_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ cfg.buffer_size = cfg_32.buffer_size;
+ cfg.buffer_count = cfg_32.buffer_count;
+
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ rc = 0;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_GET_CONFIG_32: {
+ struct msm_audio_config32 cfg_32;
+
+ mutex_lock(&audio->lock);
+ memset(&cfg_32, 0, sizeof(cfg_32));
+ cfg_32.buffer_size = audio->pcm_cfg.buffer_size;
+ cfg_32.buffer_count = audio->pcm_cfg.buffer_count;
+ cfg_32.channel_count = audio->pcm_cfg.channel_count;
+ cfg_32.sample_rate = audio->pcm_cfg.sample_rate;
+ cfg_32.type = audio->pcm_cfg.type;
+ cfg_32.meta_field = audio->pcm_cfg.meta_field;
+ cfg_32.bits = audio->pcm_cfg.bits;
+
+ if (copy_to_user((void *)arg, &cfg_32, sizeof(cfg_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_SET_CONFIG_32: {
+ struct msm_audio_config config;
+ struct msm_audio_config32 config_32;
+
+ mutex_lock(&audio->lock);
+
+ if (audio->feedback != NON_TUNNEL_MODE) {
+ pr_err("%s[%pK]:Not sufficient permission to change the playback mode\n",
+ __func__, audio);
+ rc = -EACCES;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ pr_err("%s[%pK]:AUDIO_SET_CONFIG\n", __func__, audio);
+ if (copy_from_user(&config_32, (void *)arg,
+ sizeof(config_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ config.buffer_size = config_32.buffer_size;
+ config.buffer_count = config_32.buffer_count;
+ config.channel_count = config_32.channel_count;
+ config.sample_rate = config_32.sample_rate;
+ config.type = config_32.type;
+ config.meta_field = config_32.meta_field;
+ config.bits = config_32.bits;
+
+ if ((config.buffer_count > PCM_BUF_COUNT) ||
+ (config.buffer_count == 1))
+ config.buffer_count = PCM_BUF_COUNT;
+
+ if (config.buffer_size < PCM_BUFSZ_MIN)
+ config.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->pcm_cfg.buffer_count = config.buffer_count;
+ audio->pcm_cfg.buffer_size = config.buffer_size;
+ audio->pcm_cfg.channel_count = config.channel_count;
+ audio->pcm_cfg.sample_rate = config.sample_rate;
+ rc = 0;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_SET_BUF_CFG_32: {
+ struct msm_audio_buf_cfg cfg;
+ struct msm_audio_buf_cfg32 cfg_32;
+
+ mutex_lock(&audio->lock);
+ if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ cfg.meta_info_enable = cfg_32.meta_info_enable;
+ cfg.frames_per_buf = cfg_32.frames_per_buf;
+
+ if ((audio->feedback == NON_TUNNEL_MODE) &&
+ !cfg.meta_info_enable) {
+ rc = -EFAULT;
+ mutex_unlock(&audio->lock);
+ break;
+ }
+
+ audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+ pr_debug("%s[%pK]:session id %d: Set-buf-cfg: meta[%d]",
+ __func__, audio,
+ audio->ac->session, cfg.meta_info_enable);
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_GET_BUF_CFG_32: {
+ struct msm_audio_buf_cfg32 cfg_32;
+
+ pr_debug("%s[%pK]:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__, audio,
+ audio->ac->session, audio->buf_cfg.meta_info_enable,
+ audio->buf_cfg.frames_per_buf);
+ mutex_lock(&audio->lock);
+ memset(&cfg_32, 0, sizeof(cfg_32));
+ cfg_32.meta_info_enable = audio->buf_cfg.meta_info_enable;
+ cfg_32.frames_per_buf = audio->buf_cfg.frames_per_buf;
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(struct msm_audio_buf_cfg32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_BUF_CFG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_REGISTER_ION_32: {
+ struct msm_audio_ion_info32 info_32;
+ struct msm_audio_ion_info info;
+
+ pr_debug("%s[%pK]:AUDIO_REGISTER_ION\n", __func__, audio);
+ mutex_lock(&audio->lock);
+ if (copy_from_user(&info_32, (void *)arg, sizeof(info_32))) {
+ pr_err("%s: copy_from_user for AUDIO_REGISTER_ION_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ } else {
+ info.fd = info_32.fd;
+ info.vaddr = compat_ptr(info_32.vaddr);
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
+ rc = audio_aio_ion_add(audio, &info);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ case AUDIO_DEREGISTER_ION_32: {
+ struct msm_audio_ion_info32 info_32;
+ struct msm_audio_ion_info info;
+
+ mutex_lock(&audio->lock);
+ pr_debug("%s[%pK]:AUDIO_DEREGISTER_ION\n", __func__, audio);
+ if (copy_from_user(&info_32, (void *)arg, sizeof(info_32))) {
+ pr_err("%s: copy_from_user for AUDIO_DEREGISTER_ION_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ } else {
+ info.fd = info_32.fd;
+ info.vaddr = compat_ptr(info_32.vaddr);
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
+ rc = audio_aio_ion_remove(audio, &info);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
+ }
+ mutex_unlock(&audio->lock);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+#endif
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.h b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.h
new file mode 100644
index 0000000..82374f9
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.h
@@ -0,0 +1,232 @@
+/* Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/msm_audio.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/msm_ion.h>
+#include <asm/ioctls.h>
+#include <linux/atomic.h>
+#include "q6audio_common.h"
+
+#define TUNNEL_MODE 0x0000
+#define NON_TUNNEL_MODE 0x0001
+
+#define ADRV_STATUS_AIO_INTF 0x00000001 /* AIO interface */
+#define ADRV_STATUS_FSYNC 0x00000008
+#define ADRV_STATUS_PAUSE 0x00000010
+#define AUDIO_DEC_EOS_SET 0x00000001
+#define AUDIO_DEC_EOF_SET 0x00000010
+#define AUDIO_EVENT_NUM 10
+
+#define __CONTAINS(r, v, l) ({ \
+ typeof(r) __r = r; \
+ typeof(v) __v = v; \
+ typeof(v) __e = __v + l; \
+ int res = ((__v >= __r->vaddr) && \
+ (__e <= __r->vaddr + __r->len)); \
+ res; \
+})
+
+#define CONTAINS(r1, r2) ({ \
+ typeof(r2) __r2 = r2; \
+ __CONTAINS(r1, __r2->vaddr, __r2->len); \
+})
+
+#define IN_RANGE(r, v) ({ \
+ typeof(r) __r = r; \
+ typeof(v) __vv = v; \
+ int res = ((__vv >= __r->vaddr) && \
+ (__vv < (__r->vaddr + __r->len))); \
+ res; \
+})
+
+#define OVERLAPS(r1, r2) ({ \
+ typeof(r1) __r1 = r1; \
+ typeof(r2) __r2 = r2; \
+ typeof(__r2->vaddr) __v = __r2->vaddr; \
+ typeof(__v) __e = __v + __r2->len - 1; \
+ int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e)); \
+ res; \
+})
+
+struct timestamp {
+ u32 lowpart;
+ u32 highpart;
+} __packed;
+
+struct meta_out_dsp {
+ u32 offset_to_frame;
+ u32 frame_size;
+ u32 encoded_pcm_samples;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 nflags;
+} __packed;
+
+struct dec_meta_in {
+ unsigned char reserved[18];
+ unsigned short offset;
+ struct timestamp ntimestamp;
+ unsigned int nflags;
+} __packed;
+
+struct dec_meta_out {
+ unsigned int reserved[7];
+ unsigned int num_of_frames;
+ struct meta_out_dsp meta_out_dsp[];
+} __packed;
+
+/* General meta field to store meta info locally */
+union meta_data {
+ struct dec_meta_out meta_out;
+ struct dec_meta_in meta_in;
+} __packed;
+
+/* per device wakeup source manager */
+struct ws_mgr {
+ struct mutex ws_lock;
+ uint32_t ref_cnt;
+};
+
+#define PCM_BUF_COUNT (2)
+/* Buffer with meta */
+#define PCM_BUFSZ_MIN ((4*1024) + sizeof(struct dec_meta_out))
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM (2)
+#define FRAME_SIZE ((4*1536) + sizeof(struct dec_meta_in))
+
+struct audio_aio_ion_region {
+ struct list_head list;
+ struct ion_handle *handle;
+ int fd;
+ void *vaddr;
+ phys_addr_t paddr;
+ void *kvaddr;
+ unsigned long len;
+ unsigned int ref_cnt;
+};
+
+struct audio_aio_event {
+ struct list_head list;
+ int event_type;
+ union msm_audio_event_payload payload;
+};
+
+struct audio_aio_buffer_node {
+ struct list_head list;
+ struct msm_audio_aio_buf buf;
+ unsigned long paddr;
+ uint32_t token;
+ void *kvaddr;
+ union meta_data meta_info;
+};
+
+struct q6audio_aio;
+struct audio_aio_drv_operations {
+ void (*out_flush)(struct q6audio_aio *);
+ void (*in_flush)(struct q6audio_aio *);
+};
+
+struct q6audio_aio {
+ atomic_t in_bytes;
+ atomic_t in_samples;
+
+ struct msm_audio_stream_config str_cfg;
+ struct msm_audio_buf_cfg buf_cfg;
+ struct msm_audio_config pcm_cfg;
+ void *codec_cfg;
+
+ struct audio_client *ac;
+
+ struct mutex lock;
+ struct mutex read_lock;
+ struct mutex write_lock;
+ struct mutex get_event_lock;
+ wait_queue_head_t cmd_wait;
+ wait_queue_head_t write_wait;
+ wait_queue_head_t event_wait;
+ spinlock_t dsp_lock;
+ spinlock_t event_queue_lock;
+
+ struct miscdevice *miscdevice;
+ uint32_t wakelock_voted;
+ struct ws_mgr *audio_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+#endif
+ struct list_head out_queue; /* queue to retain output buffers */
+ struct list_head in_queue; /* queue to retain input buffers */
+ struct list_head free_event_queue;
+ struct list_head event_queue;
+ struct list_head ion_region_queue; /* protected by lock */
+ struct ion_client *client;
+ struct audio_aio_drv_operations drv_ops;
+ union msm_audio_event_payload eos_write_payload;
+ uint32_t device_events;
+ uint16_t volume;
+ uint32_t drv_status;
+ int event_abort;
+ int eos_rsp;
+ int eos_flag;
+ int opened;
+ int enabled;
+ int stopped;
+ int feedback;
+ int rflush; /* Read flush */
+ int wflush; /* Write flush */
+ bool reset_event;
+ long (*codec_ioctl)(struct file *, unsigned int, unsigned long);
+ long (*codec_compat_ioctl)(struct file *, unsigned int, unsigned long);
+};
+
+void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
+ uint32_t *payload);
+
+void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
+ uint32_t *payload);
+
+int insert_eos_buf(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node);
+
+void extract_meta_out_info(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node, int dir);
+
+int audio_aio_open(struct q6audio_aio *audio, struct file *file);
+int audio_aio_enable(struct q6audio_aio *audio);
+void audio_aio_post_event(struct q6audio_aio *audio, int type,
+ union msm_audio_event_payload payload);
+int audio_aio_release(struct inode *inode, struct file *file);
+int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync);
+void audio_aio_async_out_flush(struct q6audio_aio *audio);
+void audio_aio_async_in_flush(struct q6audio_aio *audio);
+void audio_aio_ioport_reset(struct q6audio_aio *audio);
+int enable_volume_ramp(struct q6audio_aio *audio);
+#ifdef CONFIG_DEBUG_FS
+int audio_aio_debug_open(struct inode *inode, struct file *file);
+ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos);
+#endif
diff --git a/drivers/misc/qcom/qdsp6v2/audio_wma.c b/drivers/misc/qcom/qdsp6v2/audio_wma.c
new file mode 100644
index 0000000..e35334a
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_wma.c
@@ -0,0 +1,345 @@
+/* wma audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/msm_audio_wma.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_wma_misc;
+static struct ws_mgr audio_wma_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_wma_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_wma_cfg wma_cfg;
+ struct msm_audio_wma_config_v2 *wma_config;
+
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ wma_config = (struct msm_audio_wma_config_v2 *)audio->codec_cfg;
+ wma_cfg.format_tag = wma_config->format_tag;
+ wma_cfg.ch_cfg = wma_config->numchannels;
+ wma_cfg.sample_rate = wma_config->samplingrate;
+ wma_cfg.avg_bytes_per_sec = wma_config->avgbytespersecond;
+ wma_cfg.block_align = wma_config->block_align;
+ wma_cfg.valid_bits_per_sample =
+ wma_config->validbitspersample;
+ wma_cfg.ch_mask = wma_config->channelmask;
+ wma_cfg.encode_opt = wma_config->encodeopt;
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_wma(audio->ac, &wma_cfg,
+ audio->ac->stream_id);
+ if (rc < 0) {
+ pr_err("cmd media format block failed\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_WMA_CONFIG_V2: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_wma_config_v2))) {
+ pr_err("%s:copy_to_user for AUDIO_SET_WMA_CONFIG_V2 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_WMA_CONFIG_V2: {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_wma_config_v2))) {
+ pr_err("%s:copy_from_user for AUDIO_SET_WMA_CONFIG_V2 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("Failed in utils_ioctl: %d\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_wma_config_v2_32 {
+ u16 format_tag;
+ u16 numchannels;
+ u32 samplingrate;
+ u32 avgbytespersecond;
+ u16 block_align;
+ u16 validbitspersample;
+ u32 channelmask;
+ u16 encodeopt;
+};
+
+enum {
+ AUDIO_GET_WMA_CONFIG_V2_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2), struct msm_audio_wma_config_v2_32),
+ AUDIO_SET_WMA_CONFIG_V2_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_wma_config_v2_32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_WMA_CONFIG_V2_32: {
+ struct msm_audio_wma_config_v2 *wma_config;
+ struct msm_audio_wma_config_v2_32 wma_config_32;
+
+ memset(&wma_config_32, 0, sizeof(wma_config_32));
+
+ wma_config = (struct msm_audio_wma_config_v2 *)audio->codec_cfg;
+ wma_config_32.format_tag = wma_config->format_tag;
+ wma_config_32.numchannels = wma_config->numchannels;
+ wma_config_32.samplingrate = wma_config->samplingrate;
+ wma_config_32.avgbytespersecond = wma_config->avgbytespersecond;
+ wma_config_32.block_align = wma_config->block_align;
+ wma_config_32.validbitspersample =
+ wma_config->validbitspersample;
+ wma_config_32.channelmask = wma_config->channelmask;
+ wma_config_32.encodeopt = wma_config->encodeopt;
+ if (copy_to_user((void *)arg, &wma_config_32,
+ sizeof(wma_config_32))) {
+ pr_err("%s: copy_to_user for GET_WMA_CONFIG_V2_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_WMA_CONFIG_V2_32: {
+ struct msm_audio_wma_config_v2 *wma_config;
+ struct msm_audio_wma_config_v2_32 wma_config_32;
+
+ if (copy_from_user(&wma_config_32, (void *)arg,
+ sizeof(wma_config_32))) {
+ pr_err("%s: copy_from_user for SET_WMA_CONFIG_V2_32 failed\n"
+ , __func__);
+ rc = -EFAULT;
+ break;
+ }
+ wma_config = (struct msm_audio_wma_config_v2 *)audio->codec_cfg;
+ wma_config->format_tag = wma_config_32.format_tag;
+ wma_config->numchannels = wma_config_32.numchannels;
+ wma_config->samplingrate = wma_config_32.samplingrate;
+ wma_config->avgbytespersecond = wma_config_32.avgbytespersecond;
+ wma_config->block_align = wma_config_32.block_align;
+ wma_config->validbitspersample =
+ wma_config_32.validbitspersample;
+ wma_config->channelmask = wma_config_32.channelmask;
+ wma_config->encodeopt = wma_config_32.encodeopt;
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("Failed in utils_ioctl: %d\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_wma_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wma_config_v2),
+ GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_wma_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_wma_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_WMA_V9);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open WMA decoder, expected frames is always 1*/
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_WMA_V9);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_wma_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_wma_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:wmadec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_wma_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl
+};
+
+static struct miscdevice audio_wma_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_wma",
+ .fops = &audio_wma_fops,
+};
+
+static int __init audio_wma_init(void)
+{
+ int ret = misc_register(&audio_wma_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_wma_misc.this_device, true);
+ audio_wma_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_wma_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_wma_init);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_wmapro.c b/drivers/misc/qcom/qdsp6v2/audio_wmapro.c
new file mode 100644
index 0000000..3cb9db1
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_wmapro.c
@@ -0,0 +1,418 @@
+/* wmapro audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/msm_audio_wmapro.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_wmapro_misc;
+static struct ws_mgr audio_wmapro_ws_mgr;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_wmapro_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_wmapro_cfg wmapro_cfg;
+ struct msm_audio_wmapro_config *wmapro_config;
+
+ pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
+ audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count,
+ 16, /* bits per sample */
+ true, /* use default channel map */
+ true, /* use back channel map flavor */
+ NULL);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ wmapro_config = (struct msm_audio_wmapro_config *)
+ audio->codec_cfg;
+ if ((wmapro_config->formattag == 0x162) ||
+ (wmapro_config->formattag == 0x163) ||
+ (wmapro_config->formattag == 0x166) ||
+ (wmapro_config->formattag == 0x167)) {
+ wmapro_cfg.format_tag = wmapro_config->formattag;
+ } else {
+ pr_err("%s:AUDIO_START failed: formattag = %d\n",
+ __func__, wmapro_config->formattag);
+ rc = -EINVAL;
+ break;
+ }
+ if (wmapro_config->numchannels > 0) {
+ wmapro_cfg.ch_cfg = wmapro_config->numchannels;
+ } else {
+ pr_err("%s:AUDIO_START failed: channels = %d\n",
+ __func__, wmapro_config->numchannels);
+ rc = -EINVAL;
+ break;
+ }
+ if (wmapro_config->samplingrate > 0) {
+ wmapro_cfg.sample_rate = wmapro_config->samplingrate;
+ } else {
+ pr_err("%s:AUDIO_START failed: sample_rate = %d\n",
+ __func__, wmapro_config->samplingrate);
+ rc = -EINVAL;
+ break;
+ }
+ wmapro_cfg.avg_bytes_per_sec =
+ wmapro_config->avgbytespersecond;
+ if ((wmapro_config->asfpacketlength <= 13376) ||
+ (wmapro_config->asfpacketlength > 0)) {
+ wmapro_cfg.block_align =
+ wmapro_config->asfpacketlength;
+ } else {
+ pr_err("%s:AUDIO_START failed: block_align = %d\n",
+ __func__, wmapro_config->asfpacketlength);
+ rc = -EINVAL;
+ break;
+ }
+ if ((wmapro_config->validbitspersample == 16) ||
+ (wmapro_config->validbitspersample == 24)) {
+ wmapro_cfg.valid_bits_per_sample =
+ wmapro_config->validbitspersample;
+ } else {
+ pr_err("%s:AUDIO_START failed: bitspersample = %d\n",
+ __func__, wmapro_config->validbitspersample);
+ rc = -EINVAL;
+ break;
+ }
+ wmapro_cfg.ch_mask = wmapro_config->channelmask;
+ wmapro_cfg.encode_opt = wmapro_config->encodeopt;
+ wmapro_cfg.adv_encode_opt =
+ wmapro_config->advancedencodeopt;
+ wmapro_cfg.adv_encode_opt2 =
+ wmapro_config->advancedencodeopt2;
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_wmapro(audio->ac, &wmapro_cfg,
+ audio->ac->stream_id);
+ if (rc < 0) {
+ pr_err("cmd media format block failed\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd %d\n", __func__, cmd);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_GET_WMAPRO_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_wmapro_config))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_WMAPRO_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_WMAPRO_CONFIG: {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_wmapro_config))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_WMAPRO_CONFIG_V2 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("Failed in utils_ioctl: %d\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+
+struct msm_audio_wmapro_config32 {
+ u16 armdatareqthr;
+ u8 validbitspersample;
+ u8 numchannels;
+ u16 formattag;
+ u32 samplingrate;
+ u32 avgbytespersecond;
+ u16 asfpacketlength;
+ u32 channelmask;
+ u16 encodeopt;
+ u16 advancedencodeopt;
+ u32 advancedencodeopt2;
+};
+
+enum {
+ AUDIO_GET_WMAPRO_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_wmapro_config32),
+ AUDIO_SET_WMAPRO_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_wmapro_config32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_GET_WMAPRO_CONFIG_32: {
+ struct msm_audio_wmapro_config *wmapro_config;
+ struct msm_audio_wmapro_config32 wmapro_config_32;
+
+ memset(&wmapro_config_32, 0, sizeof(wmapro_config_32));
+
+ wmapro_config =
+ (struct msm_audio_wmapro_config *)audio->codec_cfg;
+ wmapro_config_32.armdatareqthr = wmapro_config->armdatareqthr;
+ wmapro_config_32.validbitspersample =
+ wmapro_config->validbitspersample;
+ wmapro_config_32.numchannels = wmapro_config->numchannels;
+ wmapro_config_32.formattag = wmapro_config->formattag;
+ wmapro_config_32.samplingrate = wmapro_config->samplingrate;
+ wmapro_config_32.avgbytespersecond =
+ wmapro_config->avgbytespersecond;
+ wmapro_config_32.asfpacketlength =
+ wmapro_config->asfpacketlength;
+ wmapro_config_32.channelmask = wmapro_config->channelmask;
+ wmapro_config_32.encodeopt = wmapro_config->encodeopt;
+ wmapro_config_32.advancedencodeopt =
+ wmapro_config->advancedencodeopt;
+ wmapro_config_32.advancedencodeopt2 =
+ wmapro_config->advancedencodeopt2;
+
+ if (copy_to_user((void *)arg, &wmapro_config_32,
+ sizeof(struct msm_audio_wmapro_config32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_WMAPRO_CONFIG_V2_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_WMAPRO_CONFIG_32: {
+ struct msm_audio_wmapro_config *wmapro_config;
+ struct msm_audio_wmapro_config32 wmapro_config_32;
+
+ if (copy_from_user(&wmapro_config_32, (void *)arg,
+ sizeof(struct msm_audio_wmapro_config32))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_SET_WMAPRO_CONFG_V2_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ wmapro_config =
+ (struct msm_audio_wmapro_config *)audio->codec_cfg;
+ wmapro_config->armdatareqthr = wmapro_config_32.armdatareqthr;
+ wmapro_config->validbitspersample =
+ wmapro_config_32.validbitspersample;
+ wmapro_config->numchannels = wmapro_config_32.numchannels;
+ wmapro_config->formattag = wmapro_config_32.formattag;
+ wmapro_config->samplingrate = wmapro_config_32.samplingrate;
+ wmapro_config->avgbytespersecond =
+ wmapro_config_32.avgbytespersecond;
+ wmapro_config->asfpacketlength =
+ wmapro_config_32.asfpacketlength;
+ wmapro_config->channelmask = wmapro_config_32.channelmask;
+ wmapro_config->encodeopt = wmapro_config_32.encodeopt;
+ wmapro_config->advancedencodeopt =
+ wmapro_config_32.advancedencodeopt;
+ wmapro_config->advancedencodeopt2 =
+ wmapro_config_32.advancedencodeopt2;
+ break;
+ }
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ default: {
+ pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("Failed in utils_ioctl: %d\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_wmapro_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wmapro_config),
+ GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_wmapro_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_wmapro_ws_mgr;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_WMA_V10PRO);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open WMA decoder, expected frames is always 1*/
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_WMA_V10PRO);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof(name), "msm_wmapro_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
+ NULL, (void *)audio,
+ &audio_wmapro_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:wmapro decoder open success, session_id = %d\n", __func__,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_wmapro_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl
+};
+
+static struct miscdevice audio_wmapro_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_wmapro",
+ .fops = &audio_wmapro_fops,
+};
+
+static int __init audio_wmapro_init(void)
+{
+ int ret = misc_register(&audio_wmapro_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_wmapro_misc.this_device, true);
+ audio_wmapro_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_wmapro_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+device_initcall(audio_wmapro_init);
diff --git a/drivers/misc/qcom/qdsp6v2/evrc_in.c b/drivers/misc/qcom/qdsp6v2/evrc_in.c
new file mode 100644
index 0000000..e30271d
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/evrc_in.c
@@ -0,0 +1,410 @@
+/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_qcp.h>
+#include <linux/atomic.h>
+#include <linux/compat.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((23+sizeof(struct meta_out_dsp)) * 10))
+
+static long evrc_in_ioctl_shared(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_evrc_enc_config *enc_cfg;
+
+ enc_cfg = audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ pr_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+
+ /* rate_modulation_cmd set to zero
+ * currently not configurable from user space
+ */
+ rc = q6asm_enc_cfg_blk_evrc(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->min_bit_rate,
+ enc_cfg->max_bit_rate, 0);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd evrc media format block failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+ audio->ac->session);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_EVRC_ENC_CONFIG: {
+ struct msm_audio_evrc_enc_config *cfg;
+ struct msm_audio_evrc_enc_config *enc_cfg;
+
+ enc_cfg = audio->enc_cfg;
+ cfg = (struct msm_audio_evrc_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer for %s\n",
+ __func__, "AUDIO_SET_EVRC_ENC_CONFIG");
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg->min_bit_rate > 4 ||
+ cfg->min_bit_rate < 1 ||
+ (cfg->min_bit_rate == 2)) {
+ pr_err("%s:session id %d: invalid min bitrate\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg->max_bit_rate > 4 ||
+ cfg->max_bit_rate < 1 ||
+ (cfg->max_bit_rate == 2)) {
+ pr_err("%s:session id %d: invalid max bitrate\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg->min_bit_rate = cfg->min_bit_rate;
+ enc_cfg->max_bit_rate = cfg->max_bit_rate;
+ pr_debug("%s:session id %d: min_bit_rate= 0x%x max_bit_rate=0x%x\n",
+ __func__,
+ audio->ac->session, enc_cfg->min_bit_rate,
+ enc_cfg->max_bit_rate);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static long evrc_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = evrc_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_EVRC_ENC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_evrc_enc_config))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_EVRC_ENC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_EVRC_ENC_CONFIG: {
+ struct msm_audio_evrc_enc_config cfg;
+
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(struct msm_audio_evrc_enc_config))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_EVRC_ENC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = evrc_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_EVRC_ENC_CONFIG failed. rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_evrc_enc_config32 {
+ u32 cdma_rate;
+ u32 min_bit_rate;
+ u32 max_bit_rate;
+};
+
+enum {
+ AUDIO_SET_EVRC_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ 2, struct msm_audio_evrc_enc_config32),
+ AUDIO_GET_EVRC_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ 3, struct msm_audio_evrc_enc_config32)
+};
+
+static long evrc_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = evrc_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_EVRC_ENC_CONFIG_32: {
+ struct msm_audio_evrc_enc_config32 cfg_32;
+ struct msm_audio_evrc_enc_config *enc_cfg;
+
+ memset(&cfg_32, 0, sizeof(cfg_32));
+
+ enc_cfg = audio->enc_cfg;
+ cfg_32.cdma_rate = enc_cfg->cdma_rate;
+ cfg_32.min_bit_rate = enc_cfg->min_bit_rate;
+ cfg_32.max_bit_rate = enc_cfg->max_bit_rate;
+
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_EVRC_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_EVRC_ENC_CONFIG_32: {
+ struct msm_audio_evrc_enc_config cfg;
+ struct msm_audio_evrc_enc_config32 cfg_32;
+
+ if (copy_from_user(&cfg_32, (void *) arg,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_EVRC_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.cdma_rate = cfg_32.cdma_rate;
+ cfg.min_bit_rate = cfg_32.min_bit_rate;
+ cfg.max_bit_rate = cfg_32.max_bit_rate;
+ cmd = AUDIO_SET_EVRC_ENC_CONFIG;
+ rc = evrc_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_EVRC_ENC_CONFIG failed. rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+#else
+#define evrc_in_compat_ioctl NULL
+#endif
+
+static int evrc_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_evrc_enc_config *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_evrc_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 23;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->min_bit_rate = 4;
+ enc_cfg->max_bit_rate = 4;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->event_abort = 0;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open evrc encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_EVRC,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: NT mode encoder success\n",
+ __func__, audio->ac->session);
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_EVRC);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
+ __func__,
+ audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: T mode encoder success\n", __func__,
+ audio->ac->session);
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ audio->reset_event = false;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = evrc_in_compat_ioctl;
+ audio->enc_ioctl = evrc_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = evrc_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+ .compat_ioctl = audio_in_compat_ioctl
+};
+
+struct miscdevice audio_evrc_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_evrc_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init evrc_in_init(void)
+{
+ return misc_register(&audio_evrc_in_misc);
+}
+
+device_initcall(evrc_in_init);
diff --git a/drivers/misc/qcom/qdsp6v2/g711alaw_in.c b/drivers/misc/qcom/qdsp6v2/g711alaw_in.c
new file mode 100644
index 0000000..bc8c0a3
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/g711alaw_in.c
@@ -0,0 +1,382 @@
+/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_g711.h>
+#include <linux/atomic.h>
+#include <linux/compat.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10))
+static long g711_in_ioctl_shared(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_g711_enc_config *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate);
+ rc = q6asm_enc_cfg_blk_g711(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->sample_rate);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
+ audio->ac->session, audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+ audio->ac->session);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
+ __func__, audio->ac->session,
+ rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG: {
+ struct msm_audio_g711_enc_config *cfg;
+ struct msm_audio_g711_enc_config *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
+
+ cfg = (struct msm_audio_g711_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg->sample_rate != 8000 &&
+ cfg->sample_rate != 16000) {
+ pr_err("%s:session id %d: invalid sample rate\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg->sample_rate = cfg->sample_rate;
+ pr_debug("%s:session id %d: sample_rate= 0x%x",
+ __func__,
+ audio->ac->session, enc_cfg->sample_rate);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+
+static long g711_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = g711_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_G711_ENC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_g711_enc_config))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG: {
+ struct msm_audio_g711_enc_config cfg;
+
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(cfg))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_g711_enc_config32 {
+ uint32_t sample_rate;
+};
+
+enum {
+ AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32),
+ AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32)
+};
+
+static long g711_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = g711_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_G711_ENC_CONFIG_32: {
+ struct msm_audio_g711_enc_config32 cfg_32;
+ struct msm_audio_g711_enc_config32 *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg;
+ cfg_32.sample_rate = enc_cfg->sample_rate;
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG_32: {
+ struct msm_audio_g711_enc_config32 cfg_32;
+ struct msm_audio_g711_enc_config32 cfg;
+
+ if (copy_from_user(&cfg_32, (void *) arg,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.sample_rate = cfg_32.sample_rate;
+ cmd = AUDIO_SET_G711_ENC_CONFIG;
+ rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+#else
+#define g711_in_compat_ioctl NULL
+#endif
+
+static int g711_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_g711_enc_config *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /*
+ * Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 320;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->sample_rate = 8000;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->event_abort = 0;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open g711 encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_G711_ALAW_FS,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_G711_ALAW_FS);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ audio->reset_event = false;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = g711_in_compat_ioctl;
+ audio->enc_ioctl = g711_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = g711_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = audio_in_compat_ioctl,
+#endif
+};
+
+struct miscdevice audio_g711alaw_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_g711alaw_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init g711alaw_in_init(void)
+{
+ return misc_register(&audio_g711alaw_in_misc);
+}
+
+device_initcall(g711alaw_in_init);
diff --git a/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c b/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c
new file mode 100644
index 0000000..b92c449
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c
@@ -0,0 +1,385 @@
+/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_g711.h>
+#include <linux/atomic.h>
+#include <linux/compat.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+#ifdef CONFIG_COMPAT
+#undef PROC_ADD
+#endif
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10))
+static long g711_in_ioctl_shared(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_g711_enc_config *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate);
+ rc = q6asm_enc_cfg_blk_g711(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->sample_rate);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
+ audio->ac->session, audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+ audio->ac->session);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
+ __func__, audio->ac->session,
+ rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG: {
+ struct msm_audio_g711_enc_config *cfg;
+ struct msm_audio_g711_enc_config *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
+
+ cfg = (struct msm_audio_g711_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg->sample_rate != 8000 &&
+ cfg->sample_rate != 16000) {
+ pr_err("%s:session id %d: invalid sample rate\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg->sample_rate = cfg->sample_rate;
+ pr_debug("%s:session id %d: sample_rate= 0x%x",
+ __func__,
+ audio->ac->session, enc_cfg->sample_rate);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+
+static long g711_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = g711_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_G711_ENC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_g711_enc_config))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG: {
+ struct msm_audio_g711_enc_config cfg;
+
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(cfg))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_g711_enc_config32 {
+ uint32_t sample_rate;
+};
+
+enum {
+ AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32),
+ AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32)
+};
+
+static long g711_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = g711_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_G711_ENC_CONFIG_32: {
+ struct msm_audio_g711_enc_config32 cfg_32;
+ struct msm_audio_g711_enc_config32 *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg;
+ cfg_32.sample_rate = enc_cfg->sample_rate;
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG_32: {
+ struct msm_audio_g711_enc_config32 cfg_32;
+ struct msm_audio_g711_enc_config32 cfg;
+
+ if (copy_from_user(&cfg_32, (void *) arg,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.sample_rate = cfg_32.sample_rate;
+ cmd = AUDIO_SET_G711_ENC_CONFIG;
+ rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+#else
+#define g711_in_compat_ioctl NULL
+#endif
+
+static int g711_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_g711_enc_config *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /*
+ * Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 320;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->sample_rate = 8000;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->event_abort = 0;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open g711 encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_G711_MLAW_FS,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_G711_MLAW_FS);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ audio->reset_event = false;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = g711_in_compat_ioctl;
+ audio->enc_ioctl = g711_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = g711_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = audio_in_compat_ioctl,
+#endif
+};
+
+struct miscdevice audio_g711mlaw_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_g711mlaw_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init g711mlaw_in_init(void)
+{
+ return misc_register(&audio_g711mlaw_in_misc);
+}
+
+device_initcall(g711mlaw_in_init);
diff --git a/drivers/misc/qcom/qdsp6v2/q6audio_common.h b/drivers/misc/qcom/qdsp6v2/q6audio_common.h
new file mode 100644
index 0000000..49b88b7
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/q6audio_common.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+/* For Decoders */
+#ifndef __Q6_AUDIO_COMMON_H__
+#define __Q6_AUDIO_COMMON_H__
+
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv);
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *audio);
+
+
+/* For Encoders */
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv);
+
+void audio_in_get_dsp_frames(void *audio,
+ uint32_t token, uint32_t *payload);
+
+#endif /*__Q6_AUDIO_COMMON_H__*/
diff --git a/drivers/misc/qcom/qdsp6v2/q6audio_v2.c b/drivers/misc/qcom/qdsp6v2/q6audio_v2.c
new file mode 100644
index 0000000..6c05165
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/q6audio_v2.c
@@ -0,0 +1,107 @@
+/* Copyright (c) 2012-2013, 2015-2017, The Linux Foundation. All rights
+ * reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_in *audio = (struct q6audio_in *)priv;
+ unsigned long flags;
+
+ pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
+ audio->ac->session, opcode);
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ switch (opcode) {
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ audio_in_get_dsp_frames(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_WRITE_DONE_V2:
+ atomic_inc(&audio->in_count);
+ wake_up(&audio->write_wait);
+ break;
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ audio->eos_rsp = 1;
+ wake_up(&audio->read_wait);
+ break;
+ case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
+ break;
+ case ASM_SESSION_EVENTX_OVERFLOW:
+ pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+ __func__, audio->ac->session);
+ break;
+ case RESET_EVENTS:
+ pr_debug("%s:received RESET EVENTS\n", __func__);
+ audio->enabled = 0;
+ audio->stopped = 1;
+ audio->event_abort = 1;
+ audio->reset_event = true;
+ wake_up(&audio->read_wait);
+ wake_up(&audio->write_wait);
+ break;
+ default:
+ pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+ audio->ac->session, opcode);
+ break;
+ }
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+void audio_in_get_dsp_frames(void *priv,
+ uint32_t token, uint32_t *payload)
+{
+ struct q6audio_in *audio = (struct q6audio_in *)priv;
+ uint32_t index;
+
+ index = q6asm_get_buf_index_from_token(token);
+ pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
+ __func__, audio->ac->session, token, payload[9],
+ payload[5]);
+ pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
+ audio->ac->session, payload[7], payload[6]);
+ pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
+ audio->ac->session, payload[8], payload[10]);
+ pr_debug("%s:session id %d: enc_framesotal_size=0x%8x\n", __func__,
+ audio->ac->session, payload[4]);
+
+ /* Ensure the index is within max array size: FRAME_NUM */
+ if (index >= FRAME_NUM) {
+ pr_err("%s: Invalid index %d\n",
+ __func__, index);
+ return;
+ }
+
+ audio->out_frame_info[index][0] = payload[9];
+ audio->out_frame_info[index][1] = payload[5];
+
+ /* statistics of read */
+ atomic_add(payload[4], &audio->in_bytes);
+ atomic_add(payload[9], &audio->in_samples);
+
+ if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
+ atomic_inc(&audio->out_count);
+ wake_up(&audio->read_wait);
+ }
+}
diff --git a/drivers/misc/qcom/qdsp6v2/q6audio_v2_aio.c b/drivers/misc/qcom/qdsp6v2/q6audio_v2_aio.c
new file mode 100644
index 0000000..9f76458
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/q6audio_v2_aio.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils_aio.h"
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+ pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE_V2:
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+ case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+ case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+ case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+ case RESET_EVENTS:
+ audio_aio_cb(opcode, token, payload, audio);
+ break;
+ default:
+ pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+ break;
+ }
+}
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv/*struct q6audio_aio *audio*/)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+ union msm_audio_event_payload e_payload;
+
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE_V2:
+ pr_debug("%s[%pK]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+ __func__, audio, token);
+ audio_aio_async_write_ack(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ pr_debug("%s[%pK]:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+ __func__, audio, token);
+ audio_aio_async_read_ack(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ /* EOS Handle */
+ pr_debug("%s[%pK]:ASM_DATA_CMDRSP_EOS\n", __func__, audio);
+ if (audio->feedback) { /* Non-Tunnel mode */
+ audio->eos_rsp = 1;
+ /* propagate input EOS i/p buffer,
+ * after receiving DSP acknowledgment
+ */
+ if (audio->eos_flag &&
+ (audio->eos_write_payload.aio_buf.buf_addr)) {
+ audio_aio_post_event(audio,
+ AUDIO_EVENT_WRITE_DONE,
+ audio->eos_write_payload);
+ memset(&audio->eos_write_payload, 0,
+ sizeof(union msm_audio_event_payload));
+ audio->eos_flag = 0;
+ }
+ } else { /* Tunnel mode */
+ audio->eos_rsp = 1;
+ wake_up(&audio->write_wait);
+ wake_up(&audio->cmd_wait);
+ }
+ break;
+ case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+ case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+ pr_debug("%s[%pK]:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
+ __func__, audio, payload[0], payload[1], opcode);
+ break;
+ case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+ case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+ pr_debug("%s[%pK]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0]-sr = %d, payload[1]-chl = %d, payload[2] = %d, payload[3] = %d\n",
+ __func__, audio, payload[0],
+ payload[1], payload[2], payload[3]);
+
+ pr_debug("%s[%pK]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, sr(prev) = %d, chl(prev) = %d,",
+ __func__, audio, audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ audio->pcm_cfg.sample_rate = payload[0];
+ audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
+ e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
+ e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
+ audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+ break;
+ case RESET_EVENTS:
+ pr_err("%s: Received opcode:0x%x\n", __func__, opcode);
+ audio->stopped = 1;
+ audio->reset_event = true;
+ wake_up(&audio->event_wait);
+ break;
+ default:
+ break;
+ }
+}
+
+void extract_meta_out_info(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node, int dir)
+{
+ struct dec_meta_out *meta_data = buf_node->kvaddr;
+ uint32_t temp;
+
+ if (dir) { /* input buffer - Write */
+ if (audio->buf_cfg.meta_info_enable)
+ memcpy(&buf_node->meta_info.meta_in,
+ (char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
+ else
+ memset(&buf_node->meta_info.meta_in,
+ 0, sizeof(struct dec_meta_in));
+ pr_debug("%s[%pK]:i/p: msw_ts %d lsw_ts %d nflags 0x%8x\n",
+ __func__, audio,
+ buf_node->meta_info.meta_in.ntimestamp.highpart,
+ buf_node->meta_info.meta_in.ntimestamp.lowpart,
+ buf_node->meta_info.meta_in.nflags);
+ } else { /* output buffer - Read */
+ memcpy((char *)buf_node->kvaddr,
+ &buf_node->meta_info.meta_out,
+ sizeof(struct dec_meta_out));
+ meta_data->meta_out_dsp[0].nflags = 0x00000000;
+ temp = meta_data->meta_out_dsp[0].msw_ts;
+ meta_data->meta_out_dsp[0].msw_ts =
+ meta_data->meta_out_dsp[0].lsw_ts;
+ meta_data->meta_out_dsp[0].lsw_ts = temp;
+
+ pr_debug("%s[%pK]:o/p: msw_ts %d lsw_ts %d nflags 0x%8x, num_frames = %d\n",
+ __func__, audio,
+ ((struct dec_meta_out *)buf_node->kvaddr)->
+ meta_out_dsp[0].msw_ts,
+ ((struct dec_meta_out *)buf_node->kvaddr)->
+ meta_out_dsp[0].lsw_ts,
+ ((struct dec_meta_out *)buf_node->kvaddr)->
+ meta_out_dsp[0].nflags,
+ ((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
+ }
+}
+
+/* Read buffer from DSP / Handle Ack from DSP */
+void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
+ uint32_t *payload)
+{
+ unsigned long flags;
+ union msm_audio_event_payload event_payload;
+ struct audio_aio_buffer_node *filled_buf;
+
+ pr_debug("%s\n", __func__);
+
+ /* No active flush in progress */
+ if (audio->rflush)
+ return;
+
+ /* Statistics of read */
+ atomic_add(payload[4], &audio->in_bytes);
+ atomic_add(payload[9], &audio->in_samples);
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ if (list_empty(&audio->in_queue)) {
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ pr_warn("%s unexpected ack from dsp\n", __func__);
+ return;
+ }
+ filled_buf = list_first_entry(&audio->in_queue,
+ struct audio_aio_buffer_node, list);
+
+ pr_debug("%s token: 0x[%x], filled_buf->token: 0x[%x]",
+ __func__, token, filled_buf->token);
+ if (token == (filled_buf->token)) {
+ list_del(&filled_buf->list);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ event_payload.aio_buf = filled_buf->buf;
+ /* Read done Buffer due to flush/normal condition
+ * after EOS event, so append EOS buffer
+ */
+ if (audio->eos_rsp == 0x1) {
+ event_payload.aio_buf.data_len =
+ insert_eos_buf(audio, filled_buf);
+ /* Reset flag back to indicate eos intimated */
+ audio->eos_rsp = 0;
+ } else {
+ filled_buf->meta_info.meta_out.num_of_frames
+ = payload[9];
+ event_payload.aio_buf.data_len = payload[4]
+ + payload[5] + sizeof(struct dec_meta_out);
+ pr_debug("%s[%pK]:nr of frames 0x%8x len=%d\n",
+ __func__, audio,
+ filled_buf->meta_info.meta_out.num_of_frames,
+ event_payload.aio_buf.data_len);
+ extract_meta_out_info(audio, filled_buf, 0);
+ audio->eos_rsp = 0;
+ }
+ pr_debug("%s, posting read done to the app here\n", __func__);
+ audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
+ event_payload);
+ kfree(filled_buf);
+ } else {
+ pr_err("%s[%pK]:expected=%x ret=%x\n",
+ __func__, audio, filled_buf->token, token);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ }
+}
diff --git a/drivers/misc/qcom/qdsp6v2/qcelp_in.c b/drivers/misc/qcom/qdsp6v2/qcelp_in.c
new file mode 100644
index 0000000..da5520f
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/qcelp_in.c
@@ -0,0 +1,410 @@
+/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_qcp.h>
+#include <linux/atomic.h>
+#include <linux/compat.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((35+sizeof(struct meta_out_dsp)) * 10))
+
+static long qcelp_in_ioctl_shared(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_qcelp_enc_config *enc_cfg;
+
+ enc_cfg = audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ pr_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+
+ /* reduced_rate_level, rate_modulation_cmd set to zero
+ * currently not configurable from user space
+ */
+ rc = q6asm_enc_cfg_blk_qcelp(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->min_bit_rate,
+ enc_cfg->max_bit_rate, 0, 0);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd qcelp media format block failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
+ audio->ac->session, audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+ audio->ac->session);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
+ __func__, audio->ac->session,
+ rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_QCELP_ENC_CONFIG: {
+ struct msm_audio_qcelp_enc_config *cfg;
+ struct msm_audio_qcelp_enc_config *enc_cfg;
+
+ enc_cfg = audio->enc_cfg;
+ cfg = (struct msm_audio_qcelp_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg->min_bit_rate > 4 ||
+ cfg->min_bit_rate < 1) {
+ pr_err("%s:session id %d: invalid min bitrate\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg->max_bit_rate > 4 ||
+ cfg->max_bit_rate < 1) {
+ pr_err("%s:session id %d: invalid max bitrate\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg->cdma_rate = cfg->cdma_rate;
+ enc_cfg->min_bit_rate = cfg->min_bit_rate;
+ enc_cfg->max_bit_rate = cfg->max_bit_rate;
+ pr_debug("%s:session id %d: min_bit_rate= 0x%x max_bit_rate=0x%x\n",
+ __func__,
+ audio->ac->session, enc_cfg->min_bit_rate,
+ enc_cfg->max_bit_rate);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static long qcelp_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = qcelp_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_QCELP_ENC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_qcelp_enc_config))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_QCELP_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_QCELP_ENC_CONFIG: {
+ struct msm_audio_qcelp_enc_config cfg;
+
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(cfg))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_SET_QCELP_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = qcelp_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_QCELP_ENC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_qcelp_enc_config32 {
+ u32 cdma_rate;
+ u32 min_bit_rate;
+ u32 max_bit_rate;
+};
+
+enum {
+ AUDIO_SET_QCELP_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ 0, struct msm_audio_qcelp_enc_config32),
+ AUDIO_GET_QCELP_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ 1, struct msm_audio_qcelp_enc_config32)
+};
+
+static long qcelp_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = qcelp_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_QCELP_ENC_CONFIG_32: {
+ struct msm_audio_qcelp_enc_config32 cfg_32;
+ struct msm_audio_qcelp_enc_config *enc_cfg;
+
+ memset(&cfg_32, 0, sizeof(cfg_32));
+
+ enc_cfg = (struct msm_audio_qcelp_enc_config *)audio->enc_cfg;
+ cfg_32.cdma_rate = enc_cfg->cdma_rate;
+ cfg_32.min_bit_rate = enc_cfg->min_bit_rate;
+ cfg_32.max_bit_rate = enc_cfg->max_bit_rate;
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_QCELP_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+}
+ break;
+ }
+ case AUDIO_SET_QCELP_ENC_CONFIG_32: {
+ struct msm_audio_qcelp_enc_config32 cfg_32;
+ struct msm_audio_qcelp_enc_config cfg;
+
+ if (copy_from_user(&cfg_32, (void *) arg,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_QCELP_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.cdma_rate = cfg_32.cdma_rate;
+ cfg.min_bit_rate = cfg_32.min_bit_rate;
+ cfg.max_bit_rate = cfg_32.max_bit_rate;
+ cmd = AUDIO_SET_QCELP_ENC_CONFIG;
+ rc = qcelp_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_QCELP_ENC_CONFIG failed. rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+#else
+#define qcelp_in_compat_ioctl NULL
+#endif
+
+static int qcelp_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_qcelp_enc_config *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_qcelp_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 35;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->min_bit_rate = 4;
+ enc_cfg->max_bit_rate = 4;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->event_abort = 0;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open qcelp encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_V13K,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: NT mode encoder success\n", __func__,
+ audio->ac->session);
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_V13K);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: T mode encoder success\n", __func__,
+ audio->ac->session);
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ audio->reset_event = false;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = qcelp_in_compat_ioctl;
+ audio->enc_ioctl = qcelp_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = qcelp_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+ .compat_ioctl = audio_in_compat_ioctl
+};
+
+struct miscdevice audio_qcelp_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_qcelp_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init qcelp_in_init(void)
+{
+ return misc_register(&audio_qcelp_in_misc);
+}
+
+device_initcall(qcelp_in_init);
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/Makefile b/drivers/misc/qcom/qdsp6v2/ultrasound/Makefile
new file mode 100644
index 0000000..41f614a
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/Makefile
@@ -0,0 +1,2 @@
+ccflags-y := -I$(src)/..
+obj-$(CONFIG_MSM_ULTRASOUND) += usf.o usfcdev.o q6usm.o
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c
new file mode 100644
index 0000000..f20f335
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c
@@ -0,0 +1,1467 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <sound/apr_audio-v2.h>
+#include <linux/qdsp6v2/apr_us.h>
+#include "q6usm.h"
+
+#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3
+
+#define MEM_4K_OFFSET 4095
+#define MEM_4K_MASK 0xfffff000
+
+#define USM_SESSION_MAX 0x02 /* aDSP:USM limit */
+
+#define READDONE_IDX_STATUS 0
+
+#define WRITEDONE_IDX_STATUS 0
+
+/* Standard timeout in the asynchronous ops */
+#define Q6USM_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
+
+static DEFINE_MUTEX(session_lock);
+
+static struct us_client *session[USM_SESSION_MAX];
+static int32_t q6usm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6usm_callback(struct apr_client_data *data, void *priv);
+static void q6usm_add_hdr(struct us_client *usc, struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg);
+
+struct usm_mmap {
+ atomic_t ref_cnt;
+ atomic_t cmd_state;
+ wait_queue_head_t cmd_wait;
+ void *apr;
+ int mem_handle;
+};
+
+static struct usm_mmap this_mmap;
+
+static void q6usm_add_mmaphdr(struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg, u32 token)
+{
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr->src_port = 0;
+ hdr->dest_port = 0;
+ if (cmd_flg) {
+ hdr->token = token;
+ atomic_set(&this_mmap.cmd_state, 1);
+ }
+ hdr->pkt_size = pkt_size;
+}
+
+static int q6usm_memory_map(phys_addr_t buf_add, int dir, uint32_t bufsz,
+ uint32_t bufcnt, uint32_t session, uint32_t *mem_handle)
+{
+ struct usm_cmd_memory_map_region mem_region_map;
+ int rc = 0;
+
+ if (this_mmap.apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6usm_add_mmaphdr(&mem_region_map.hdr,
+ sizeof(struct usm_cmd_memory_map_region), true,
+ ((session << 8) | dir));
+
+ mem_region_map.hdr.opcode = USM_CMD_SHARED_MEM_MAP_REGION;
+ mem_region_map.mempool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+
+ mem_region_map.num_regions = 1;
+ mem_region_map.flags = 0;
+
+ mem_region_map.shm_addr_lsw = lower_32_bits(buf_add);
+ mem_region_map.shm_addr_msw =
+ msm_audio_populate_upper_32_bits(buf_add);
+ mem_region_map.mem_size_bytes = bufsz * bufcnt;
+
+ rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_region_map);
+ if (rc < 0) {
+ pr_err("%s: mem_map op[0x%x]rc[%d]\n",
+ __func__, mem_region_map.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(this_mmap.cmd_wait,
+ (atomic_read(&this_mmap.cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout. waited for memory_map\n", __func__);
+ } else {
+ *mem_handle = this_mmap.mem_handle;
+ rc = 0;
+ }
+fail_cmd:
+ return rc;
+}
+
+int q6usm_memory_unmap(phys_addr_t buf_add, int dir, uint32_t session,
+ uint32_t mem_handle)
+{
+ struct usm_cmd_memory_unmap_region mem_unmap;
+ int rc = 0;
+
+ if (this_mmap.apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6usm_add_mmaphdr(&mem_unmap.hdr,
+ sizeof(struct usm_cmd_memory_unmap_region), true,
+ ((session << 8) | dir));
+ mem_unmap.hdr.opcode = USM_CMD_SHARED_MEM_UNMAP_REGION;
+ mem_unmap.mem_map_handle = mem_handle;
+
+ rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_unmap);
+ if (rc < 0) {
+ pr_err("%s: mem_unmap op[0x%x] rc[%d]\n",
+ __func__, mem_unmap.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(this_mmap.cmd_wait,
+ (atomic_read(&this_mmap.cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout. waited for memory_unmap\n", __func__);
+ } else
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+static int q6usm_session_alloc(struct us_client *usc)
+{
+ int ind = 0;
+
+ mutex_lock(&session_lock);
+ for (ind = 0; ind < USM_SESSION_MAX; ++ind) {
+ if (!session[ind]) {
+ session[ind] = usc;
+ mutex_unlock(&session_lock);
+ ++ind; /* session id: 0 reserved */
+ pr_debug("%s: session[%d] was allocated\n",
+ __func__, ind);
+ return ind;
+ }
+ }
+ mutex_unlock(&session_lock);
+ return -ENOMEM;
+}
+
+static void q6usm_session_free(struct us_client *usc)
+{
+ /* Session index was incremented during allocation */
+ uint16_t ind = (uint16_t)usc->session - 1;
+
+ pr_debug("%s: to free session[%d]\n", __func__, ind);
+ if (ind < USM_SESSION_MAX) {
+ mutex_lock(&session_lock);
+ session[ind] = NULL;
+ mutex_unlock(&session_lock);
+ }
+}
+
+static int q6usm_us_client_buf_free(unsigned int dir,
+ struct us_client *usc)
+{
+ struct us_port_data *port;
+ int rc = 0;
+
+ if ((usc == NULL) ||
+ ((dir != IN) && (dir != OUT)))
+ return -EINVAL;
+
+ mutex_lock(&usc->cmd_lock);
+ port = &usc->port[dir];
+ if (port == NULL) {
+ mutex_unlock(&usc->cmd_lock);
+ return -EINVAL;
+ }
+
+ if (port->data == NULL) {
+ mutex_unlock(&usc->cmd_lock);
+ return 0;
+ }
+
+ rc = q6usm_memory_unmap(port->phys, dir, usc->session,
+ *((uint32_t *)port->ext));
+ pr_debug("%s: data[%pK]phys[%llx][%pK]\n", __func__,
+ (void *)port->data, (u64)port->phys, (void *)&port->phys);
+
+ msm_audio_ion_free(port->client, port->handle);
+
+ port->data = NULL;
+ port->phys = 0;
+ port->buf_size = 0;
+ port->buf_cnt = 0;
+ port->client = NULL;
+ port->handle = NULL;
+
+ mutex_unlock(&usc->cmd_lock);
+ return rc;
+}
+
+int q6usm_us_param_buf_free(unsigned int dir,
+ struct us_client *usc)
+{
+ struct us_port_data *port;
+ int rc = 0;
+
+ if ((usc == NULL) ||
+ ((dir != IN) && (dir != OUT)))
+ return -EINVAL;
+
+ mutex_lock(&usc->cmd_lock);
+ port = &usc->port[dir];
+ if (port == NULL) {
+ mutex_unlock(&usc->cmd_lock);
+ return -EINVAL;
+ }
+
+ if (port->param_buf == NULL) {
+ mutex_unlock(&usc->cmd_lock);
+ return 0;
+ }
+
+ rc = q6usm_memory_unmap(port->param_phys, dir, usc->session,
+ *((uint32_t *)port->param_buf_mem_handle));
+ pr_debug("%s: data[%pK]phys[%llx][%pK]\n", __func__,
+ (void *)port->param_buf, (u64)port->param_phys,
+ (void *)&port->param_phys);
+
+ msm_audio_ion_free(port->param_client, port->param_handle);
+
+ port->param_buf = NULL;
+ port->param_phys = 0;
+ port->param_buf_size = 0;
+ port->param_client = NULL;
+ port->param_handle = NULL;
+
+ mutex_unlock(&usc->cmd_lock);
+ return rc;
+}
+
+void q6usm_us_client_free(struct us_client *usc)
+{
+ int loopcnt = 0;
+ struct us_port_data *port;
+ uint32_t *p_mem_handle = NULL;
+
+ if ((usc == NULL) ||
+ !(usc->session))
+ return;
+
+ for (loopcnt = 0; loopcnt <= OUT; ++loopcnt) {
+ port = &usc->port[loopcnt];
+ if (port->data == NULL)
+ continue;
+ pr_debug("%s: loopcnt = %d\n", __func__, loopcnt);
+ q6usm_us_client_buf_free(loopcnt, usc);
+ q6usm_us_param_buf_free(loopcnt, usc);
+ }
+ q6usm_session_free(usc);
+ apr_deregister(usc->apr);
+
+ pr_debug("%s: APR De-Register\n", __func__);
+
+ if (atomic_read(&this_mmap.ref_cnt) <= 0) {
+ pr_err("%s: APR Common Port Already Closed\n", __func__);
+ goto done;
+ }
+
+ atomic_dec(&this_mmap.ref_cnt);
+ if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ apr_deregister(this_mmap.apr);
+ pr_debug("%s: APR De-Register common port\n", __func__);
+ }
+
+done:
+ p_mem_handle = (uint32_t *)usc->port[IN].ext;
+ kfree(p_mem_handle);
+ kfree(usc);
+ pr_debug("%s:\n", __func__);
+}
+
+struct us_client *q6usm_us_client_alloc(
+ void (*cb)(uint32_t, uint32_t, uint32_t *, void *),
+ void *priv)
+{
+ struct us_client *usc;
+ uint32_t *p_mem_handle = NULL;
+ int n;
+ int lcnt = 0;
+
+ usc = kzalloc(sizeof(struct us_client), GFP_KERNEL);
+ if (usc == NULL)
+ return NULL;
+
+ p_mem_handle = kzalloc(sizeof(uint32_t) * 4, GFP_KERNEL);
+ if (p_mem_handle == NULL) {
+ kfree(usc);
+ return NULL;
+ }
+
+ n = q6usm_session_alloc(usc);
+ if (n <= 0)
+ goto fail_session;
+ usc->session = n;
+ usc->cb = cb;
+ usc->priv = priv;
+ usc->apr = apr_register("ADSP", "USM",
+ (apr_fn)q6usm_callback,
+ ((usc->session) << 8 | 0x0001),
+ usc);
+
+ if (usc->apr == NULL) {
+ pr_err("%s: Registration with APR failed\n", __func__);
+ goto fail;
+ }
+ pr_debug("%s: Registering the common port with APR\n", __func__);
+ if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ this_mmap.apr = apr_register("ADSP", "USM",
+ (apr_fn)q6usm_mmapcallback,
+ 0x0FFFFFFFF, &this_mmap);
+ if (this_mmap.apr == NULL) {
+ pr_err("%s: USM port registration failed\n",
+ __func__);
+ goto fail;
+ }
+ }
+
+ atomic_inc(&this_mmap.ref_cnt);
+ init_waitqueue_head(&usc->cmd_wait);
+ mutex_init(&usc->cmd_lock);
+ for (lcnt = 0; lcnt <= OUT; ++lcnt) {
+ mutex_init(&usc->port[lcnt].lock);
+ spin_lock_init(&usc->port[lcnt].dsp_lock);
+ usc->port[lcnt].ext = (void *)p_mem_handle++;
+ usc->port[lcnt].param_buf_mem_handle = (void *)p_mem_handle++;
+ pr_err("%s: usc->port[%d].ext=%pK;\n",
+ __func__, lcnt, usc->port[lcnt].ext);
+ }
+ atomic_set(&usc->cmd_state, 0);
+
+ return usc;
+fail:
+ kfree(p_mem_handle);
+ q6usm_us_client_free(usc);
+ return NULL;
+fail_session:
+ kfree(p_mem_handle);
+ kfree(usc);
+ return NULL;
+}
+
+int q6usm_us_client_buf_alloc(unsigned int dir,
+ struct us_client *usc,
+ unsigned int bufsz,
+ unsigned int bufcnt)
+{
+ int rc = 0;
+ struct us_port_data *port = NULL;
+ unsigned int size = bufsz*bufcnt;
+ size_t len;
+
+ if ((usc == NULL) ||
+ ((dir != IN) && (dir != OUT)) || (size == 0) ||
+ (usc->session <= 0 || usc->session > USM_SESSION_MAX)) {
+ pr_err("%s: wrong parameters: size=%d; bufcnt=%d\n",
+ __func__, size, bufcnt);
+ return -EINVAL;
+ }
+
+ mutex_lock(&usc->cmd_lock);
+
+ port = &usc->port[dir];
+
+ /* The size to allocate should be multiple of 4K bytes */
+ size = PAGE_ALIGN(size);
+
+ rc = msm_audio_ion_alloc("ultrasound_client",
+ &port->client, &port->handle,
+ size, &port->phys,
+ &len, &port->data);
+
+ if (rc) {
+ pr_err("%s: US ION allocation failed, rc = %d\n",
+ __func__, rc);
+ mutex_unlock(&usc->cmd_lock);
+ return -ENOMEM;
+ }
+
+ port->buf_cnt = bufcnt;
+ port->buf_size = bufsz;
+ pr_debug("%s: data[%pK]; phys[%llx]; [%pK]\n", __func__,
+ (void *)port->data,
+ (u64)port->phys,
+ (void *)&port->phys);
+
+ rc = q6usm_memory_map(port->phys, dir, size, 1, usc->session,
+ (uint32_t *)port->ext);
+ if (rc < 0) {
+ pr_err("%s: CMD Memory_map failed\n", __func__);
+ mutex_unlock(&usc->cmd_lock);
+ q6usm_us_client_buf_free(dir, usc);
+ q6usm_us_param_buf_free(dir, usc);
+ } else {
+ mutex_unlock(&usc->cmd_lock);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int q6usm_us_param_buf_alloc(unsigned int dir,
+ struct us_client *usc,
+ unsigned int bufsz)
+{
+ int rc = 0;
+ struct us_port_data *port = NULL;
+ unsigned int size = bufsz;
+ size_t len;
+
+ if ((usc == NULL) ||
+ ((dir != IN) && (dir != OUT)) ||
+ (usc->session <= 0 || usc->session > USM_SESSION_MAX)) {
+ pr_err("%s: wrong parameters: direction=%d, bufsz=%d\n",
+ __func__, dir, bufsz);
+ return -EINVAL;
+ }
+
+ mutex_lock(&usc->cmd_lock);
+
+ port = &usc->port[dir];
+
+ if (bufsz == 0) {
+ pr_debug("%s: bufsz=0, get/set param commands are forbidden\n",
+ __func__);
+ port->param_buf = NULL;
+ mutex_unlock(&usc->cmd_lock);
+ return rc;
+ }
+
+ /* The size to allocate should be multiple of 4K bytes */
+ size = PAGE_ALIGN(size);
+
+ rc = msm_audio_ion_alloc("ultrasound_client",
+ &port->param_client, &port->param_handle,
+ size, &port->param_phys,
+ &len, &port->param_buf);
+
+ if (rc) {
+ pr_err("%s: US ION allocation failed, rc = %d\n",
+ __func__, rc);
+ mutex_unlock(&usc->cmd_lock);
+ return -ENOMEM;
+ }
+
+ port->param_buf_size = bufsz;
+ pr_debug("%s: param_buf[%pK]; param_phys[%llx]; [%pK]\n", __func__,
+ (void *)port->param_buf,
+ (u64)port->param_phys,
+ (void *)&port->param_phys);
+
+ rc = q6usm_memory_map(port->param_phys, (IN | OUT), size, 1,
+ usc->session, (uint32_t *)port->param_buf_mem_handle);
+ if (rc < 0) {
+ pr_err("%s: CMD Memory_map failed\n", __func__);
+ mutex_unlock(&usc->cmd_lock);
+ q6usm_us_client_buf_free(dir, usc);
+ q6usm_us_param_buf_free(dir, usc);
+ } else {
+ mutex_unlock(&usc->cmd_lock);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static int32_t q6usm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+ uint32_t token;
+ uint32_t *payload = data->payload;
+
+ pr_debug("%s: ptr0[0x%x]; ptr1[0x%x]; opcode[0x%x]\n",
+ __func__, payload[0], payload[1], data->opcode);
+ pr_debug("%s: token[0x%x]; payload_size[%d]; src[%d]; dest[%d];\n",
+ __func__, data->token, data->payload_size,
+ data->src_port, data->dest_port);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ /* status field check */
+ if (payload[1]) {
+ pr_err("%s: wrong response[%d] on cmd [%d]\n",
+ __func__, payload[1], payload[0]);
+ } else {
+ token = data->token;
+ switch (payload[0]) {
+ case USM_CMD_SHARED_MEM_UNMAP_REGION:
+ if (atomic_read(&this_mmap.cmd_state)) {
+ atomic_set(&this_mmap.cmd_state, 0);
+ wake_up(&this_mmap.cmd_wait);
+ }
+ /* fallthrough */
+ case USM_CMD_SHARED_MEM_MAP_REGION:
+ /* For MEM_MAP, additional answer is waited, */
+ /* therfore, no wake-up here */
+ pr_debug("%s: cmd[0x%x]; result[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ break;
+ default:
+ pr_debug("%s: wrong command[0x%x]\n",
+ __func__, payload[0]);
+ break;
+ }
+ }
+ } else {
+ if (data->opcode == USM_CMDRSP_SHARED_MEM_MAP_REGION) {
+ this_mmap.mem_handle = payload[0];
+ pr_debug("%s: memory map handle = 0x%x",
+ __func__, payload[0]);
+ if (atomic_read(&this_mmap.cmd_state)) {
+ atomic_set(&this_mmap.cmd_state, 0);
+ wake_up(&this_mmap.cmd_wait);
+ }
+ }
+ }
+ return 0;
+}
+
+
+static int32_t q6usm_callback(struct apr_client_data *data, void *priv)
+{
+ struct us_client *usc = (struct us_client *)priv;
+ unsigned long dsp_flags;
+ uint32_t *payload = data->payload;
+ uint32_t token = data->token;
+ uint32_t opcode = Q6USM_EVENT_UNDEF;
+
+ if (usc == NULL) {
+ pr_err("%s: client info is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ /* status field check */
+ if (payload[1]) {
+ pr_err("%s: wrong response[%d] on cmd [%d]\n",
+ __func__, payload[1], payload[0]);
+ if (usc->cb)
+ usc->cb(data->opcode, token,
+ (uint32_t *)data->payload, usc->priv);
+ } else {
+ switch (payload[0]) {
+ case USM_SESSION_CMD_RUN:
+ case USM_STREAM_CMD_CLOSE:
+ if (token != usc->session) {
+ pr_err("%s: wrong token[%d]",
+ __func__, token);
+ break;
+ }
+ case USM_STREAM_CMD_OPEN_READ:
+ case USM_STREAM_CMD_OPEN_WRITE:
+ case USM_STREAM_CMD_SET_ENC_PARAM:
+ case USM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+ case USM_SESSION_CMD_SIGNAL_DETECT_MODE:
+ case USM_STREAM_CMD_SET_PARAM:
+ case USM_STREAM_CMD_GET_PARAM:
+ if (atomic_read(&usc->cmd_state)) {
+ atomic_set(&usc->cmd_state, 0);
+ wake_up(&usc->cmd_wait);
+ }
+ if (usc->cb)
+ usc->cb(data->opcode, token,
+ (uint32_t *)data->payload,
+ usc->priv);
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case RESET_EVENTS: {
+ pr_err("%s: Reset event is received: %d %d\n",
+ __func__,
+ data->reset_event,
+ data->reset_proc);
+
+ opcode = RESET_EVENTS;
+
+ apr_reset(this_mmap.apr);
+ this_mmap.apr = NULL;
+
+ apr_reset(usc->apr);
+ usc->apr = NULL;
+
+ break;
+ }
+
+
+ case USM_DATA_EVENT_READ_DONE: {
+ struct us_port_data *port = &usc->port[OUT];
+
+ opcode = Q6USM_EVENT_READ_DONE;
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ if (payload[READDONE_IDX_STATUS]) {
+ pr_err("%s: wrong READDONE[%d]; token[%d]\n",
+ __func__,
+ payload[READDONE_IDX_STATUS],
+ token);
+ token = USM_WRONG_TOKEN;
+ spin_unlock_irqrestore(&port->dsp_lock,
+ dsp_flags);
+ break;
+ }
+
+ if (port->expected_token != token) {
+ u32 cpu_buf = port->cpu_buf;
+
+ pr_err("%s: expected[%d] != token[%d]\n",
+ __func__, port->expected_token, token);
+ pr_debug("%s: dsp_buf=%d; cpu_buf=%d;\n",
+ __func__, port->dsp_buf, cpu_buf);
+
+ token = USM_WRONG_TOKEN;
+ /* To prevent data handle continiue */
+ port->expected_token = USM_WRONG_TOKEN;
+ spin_unlock_irqrestore(&port->dsp_lock,
+ dsp_flags);
+ break;
+ } /* port->expected_token != data->token */
+
+ port->expected_token = token + 1;
+ if (port->expected_token == port->buf_cnt)
+ port->expected_token = 0;
+
+ /* gap support */
+ if (port->expected_token != port->cpu_buf) {
+ port->dsp_buf = port->expected_token;
+ token = port->dsp_buf; /* for callback */
+ } else
+ port->dsp_buf = token;
+
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+ break;
+ } /* case USM_DATA_EVENT_READ_DONE */
+
+ case USM_DATA_EVENT_WRITE_DONE: {
+ struct us_port_data *port = &usc->port[IN];
+
+ opcode = Q6USM_EVENT_WRITE_DONE;
+ if (payload[WRITEDONE_IDX_STATUS]) {
+ pr_err("%s: wrong WRITEDONE_IDX_STATUS[%d]\n",
+ __func__,
+ payload[WRITEDONE_IDX_STATUS]);
+ break;
+ }
+
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ port->dsp_buf = token + 1;
+ if (port->dsp_buf == port->buf_cnt)
+ port->dsp_buf = 0;
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+
+ break;
+ } /* case USM_DATA_EVENT_WRITE_DONE */
+
+ case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT: {
+ pr_debug("%s: US detect result: result=%d",
+ __func__,
+ payload[0]);
+ opcode = Q6USM_EVENT_SIGNAL_DETECT_RESULT;
+
+ break;
+ } /* case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT */
+
+ default:
+ return 0;
+
+ } /* switch */
+
+ if (usc->cb)
+ usc->cb(opcode, token,
+ data->payload, usc->priv);
+
+ return 0;
+}
+
+uint32_t q6usm_get_virtual_address(int dir,
+ struct us_client *usc,
+ struct vm_area_struct *vms)
+{
+ uint32_t ret = 0xffffffff;
+
+ if (vms && (usc != NULL) && ((dir == IN) || (dir == OUT))) {
+ struct us_port_data *port = &usc->port[dir];
+ int size = PAGE_ALIGN(port->buf_size * port->buf_cnt);
+ struct audio_buffer ab;
+
+ ab.phys = port->phys;
+ ab.data = port->data;
+ ab.used = 1;
+ ab.size = size;
+ ab.actual_size = size;
+ ab.handle = port->handle;
+ ab.client = port->client;
+
+ ret = msm_audio_ion_mmap(&ab, vms);
+
+ }
+ return ret;
+}
+
+static void q6usm_add_hdr(struct us_client *usc, struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg)
+{
+ mutex_lock(&usc->cmd_lock);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+ hdr->src_svc = ((struct apr_svc *)usc->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_USM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = (usc->session << 8) | 0x0001;
+ hdr->dest_port = (usc->session << 8) | 0x0001;
+ if (cmd_flg) {
+ hdr->token = usc->session;
+ atomic_set(&usc->cmd_state, 1);
+ }
+ hdr->pkt_size = pkt_size;
+ mutex_unlock(&usc->cmd_lock);
+}
+
+static uint32_t q6usm_ext2int_format(uint32_t ext_format)
+{
+ uint32_t int_format = INVALID_FORMAT;
+
+ switch (ext_format) {
+ case FORMAT_USPS_EPOS:
+ int_format = US_POINT_EPOS_FORMAT_V2;
+ break;
+ case FORMAT_USRAW:
+ int_format = US_RAW_FORMAT_V2;
+ break;
+ case FORMAT_USPROX:
+ int_format = US_PROX_FORMAT_V4;
+ break;
+ case FORMAT_USGES_SYNC:
+ int_format = US_GES_SYNC_FORMAT;
+ break;
+ case FORMAT_USRAW_SYNC:
+ int_format = US_RAW_SYNC_FORMAT;
+ break;
+ default:
+ pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
+ break;
+ }
+
+ return int_format;
+}
+
+int q6usm_open_read(struct us_client *usc,
+ uint32_t format)
+{
+ uint32_t int_format = INVALID_FORMAT;
+ int rc = 0x00;
+ struct usm_stream_cmd_open_read open;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: client or its apr is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: session[%d]", __func__, usc->session);
+
+ q6usm_add_hdr(usc, &open.hdr, sizeof(open), true);
+ open.hdr.opcode = USM_STREAM_CMD_OPEN_READ;
+ open.src_endpoint = 0; /* AFE */
+ open.pre_proc_top = 0; /* No preprocessing required */
+
+ int_format = q6usm_ext2int_format(format);
+ if (int_format == INVALID_FORMAT)
+ return -EINVAL;
+
+ open.uMode = STREAM_PRIORITY_NORMAL;
+ open.format = int_format;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s: open failed op[0x%x]rc[%d]\n",
+ __func__, open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout, waited for OPEN_READ rc[%d]\n",
+ __func__, rc);
+ goto fail_cmd;
+ } else
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+
+int q6usm_enc_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg)
+{
+ uint32_t int_format = INVALID_FORMAT;
+ struct usm_stream_cmd_encdec_cfg_blk enc_cfg_obj;
+ struct usm_stream_cmd_encdec_cfg_blk *enc_cfg = &enc_cfg_obj;
+ int rc = 0;
+ uint32_t total_cfg_size =
+ sizeof(struct usm_stream_cmd_encdec_cfg_blk);
+ uint32_t round_params_size = 0;
+ uint8_t is_allocated = 0;
+
+
+ if ((usc == NULL) || (us_cfg == NULL)) {
+ pr_err("%s: wrong input", __func__);
+ return -EINVAL;
+ }
+
+ int_format = q6usm_ext2int_format(us_cfg->format_id);
+ if (int_format == INVALID_FORMAT) {
+ pr_err("%s: wrong input format[%d]",
+ __func__, us_cfg->format_id);
+ return -EINVAL;
+ }
+
+ /* Transparent configuration data is after enc_cfg */
+ /* Integer number of u32s is required */
+ round_params_size = ((us_cfg->params_size + 3)/4) * 4;
+ if (round_params_size > USM_MAX_CFG_DATA_SIZE) {
+ /* Dynamic allocated encdec_cfg_blk is required */
+ /* static part use */
+ round_params_size -= USM_MAX_CFG_DATA_SIZE;
+ total_cfg_size += round_params_size;
+ enc_cfg = kzalloc(total_cfg_size, GFP_KERNEL);
+ if (enc_cfg == NULL) {
+ pr_err("%s: enc_cfg[%d] allocation failed\n",
+ __func__, total_cfg_size);
+ return -ENOMEM;
+ }
+ is_allocated = 1;
+ } else
+ round_params_size = 0;
+
+ q6usm_add_hdr(usc, &enc_cfg->hdr, total_cfg_size, true);
+
+ enc_cfg->hdr.opcode = USM_STREAM_CMD_SET_ENC_PARAM;
+ enc_cfg->param_id = USM_PARAM_ID_ENCDEC_ENC_CFG_BLK;
+ enc_cfg->param_size = sizeof(struct usm_encode_cfg_blk)+
+ round_params_size;
+ enc_cfg->enc_blk.frames_per_buf = 1;
+ enc_cfg->enc_blk.format_id = int_format;
+ enc_cfg->enc_blk.cfg_size = sizeof(struct usm_cfg_common)+
+ USM_MAX_CFG_DATA_SIZE +
+ round_params_size;
+ memcpy(&(enc_cfg->enc_blk.cfg_common), &(us_cfg->cfg_common),
+ sizeof(struct usm_cfg_common));
+
+ /* Transparent data copy */
+ memcpy(enc_cfg->enc_blk.transp_data, us_cfg->params,
+ us_cfg->params_size);
+ pr_debug("%s: cfg_size[%d], params_size[%d]\n",
+ __func__,
+ enc_cfg->enc_blk.cfg_size,
+ us_cfg->params_size);
+ pr_debug("%s: params[%d,%d,%d,%d, %d,%d,%d,%d]\n",
+ __func__,
+ enc_cfg->enc_blk.transp_data[0],
+ enc_cfg->enc_blk.transp_data[1],
+ enc_cfg->enc_blk.transp_data[2],
+ enc_cfg->enc_blk.transp_data[3],
+ enc_cfg->enc_blk.transp_data[4],
+ enc_cfg->enc_blk.transp_data[5],
+ enc_cfg->enc_blk.transp_data[6],
+ enc_cfg->enc_blk.transp_data[7]
+ );
+ pr_debug("%s: srate:%d, ch=%d, bps= %d;\n",
+ __func__, enc_cfg->enc_blk.cfg_common.sample_rate,
+ enc_cfg->enc_blk.cfg_common.ch_cfg,
+ enc_cfg->enc_blk.cfg_common.bits_per_sample);
+ pr_debug("dmap:[0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x]; dev_id=0x%x\n",
+ enc_cfg->enc_blk.cfg_common.data_map[0],
+ enc_cfg->enc_blk.cfg_common.data_map[1],
+ enc_cfg->enc_blk.cfg_common.data_map[2],
+ enc_cfg->enc_blk.cfg_common.data_map[3],
+ enc_cfg->enc_blk.cfg_common.data_map[4],
+ enc_cfg->enc_blk.cfg_common.data_map[5],
+ enc_cfg->enc_blk.cfg_common.data_map[6],
+ enc_cfg->enc_blk.cfg_common.data_map[7],
+ enc_cfg->enc_blk.cfg_common.dev_id);
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) enc_cfg);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, enc_cfg->hdr.opcode);
+ } else
+ rc = 0;
+
+fail_cmd:
+ if (is_allocated == 1)
+ kfree(enc_cfg);
+
+ return rc;
+}
+
+int q6usm_dec_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg)
+{
+
+ uint32_t int_format = INVALID_FORMAT;
+ struct usm_stream_media_format_update dec_cfg_obj;
+ struct usm_stream_media_format_update *dec_cfg = &dec_cfg_obj;
+
+ int rc = 0;
+ uint32_t total_cfg_size = sizeof(struct usm_stream_media_format_update);
+ uint32_t round_params_size = 0;
+ uint8_t is_allocated = 0;
+
+
+ if ((usc == NULL) || (us_cfg == NULL)) {
+ pr_err("%s: wrong input", __func__);
+ return -EINVAL;
+ }
+
+ int_format = q6usm_ext2int_format(us_cfg->format_id);
+ if (int_format == INVALID_FORMAT) {
+ pr_err("%s: wrong input format[%d]",
+ __func__, us_cfg->format_id);
+ return -EINVAL;
+ }
+
+ /* Transparent configuration data is after enc_cfg */
+ /* Integer number of u32s is required */
+ round_params_size = ((us_cfg->params_size + 3)/4) * 4;
+ if (round_params_size > USM_MAX_CFG_DATA_SIZE) {
+ /* Dynamic allocated encdec_cfg_blk is required */
+ /* static part use */
+ round_params_size -= USM_MAX_CFG_DATA_SIZE;
+ total_cfg_size += round_params_size;
+ dec_cfg = kzalloc(total_cfg_size, GFP_KERNEL);
+ if (dec_cfg == NULL) {
+ pr_err("%s:dec_cfg[%d] allocation failed\n",
+ __func__, total_cfg_size);
+ return -ENOMEM;
+ }
+ is_allocated = 1;
+ } else { /* static transp_data is enough */
+ round_params_size = 0;
+ }
+
+ q6usm_add_hdr(usc, &dec_cfg->hdr, total_cfg_size, true);
+
+ dec_cfg->hdr.opcode = USM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+ dec_cfg->format_id = int_format;
+ dec_cfg->cfg_size = sizeof(struct usm_cfg_common) +
+ USM_MAX_CFG_DATA_SIZE +
+ round_params_size;
+ memcpy(&(dec_cfg->cfg_common), &(us_cfg->cfg_common),
+ sizeof(struct usm_cfg_common));
+ /* Transparent data copy */
+ memcpy(dec_cfg->transp_data, us_cfg->params, us_cfg->params_size);
+ pr_debug("%s: cfg_size[%d], params_size[%d]; parambytes[%d,%d,%d,%d]\n",
+ __func__,
+ dec_cfg->cfg_size,
+ us_cfg->params_size,
+ dec_cfg->transp_data[0],
+ dec_cfg->transp_data[1],
+ dec_cfg->transp_data[2],
+ dec_cfg->transp_data[3]
+ );
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) dec_cfg);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, dec_cfg->hdr.opcode);
+ } else
+ rc = 0;
+
+fail_cmd:
+ if (is_allocated == 1)
+ kfree(dec_cfg);
+
+ return rc;
+}
+
+int q6usm_open_write(struct us_client *usc,
+ uint32_t format)
+{
+ int rc = 0;
+ uint32_t int_format = INVALID_FORMAT;
+ struct usm_stream_cmd_open_write open;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: session[%d]", __func__, usc->session);
+
+ q6usm_add_hdr(usc, &open.hdr, sizeof(open), true);
+ open.hdr.opcode = USM_STREAM_CMD_OPEN_WRITE;
+
+ int_format = q6usm_ext2int_format(format);
+ if (int_format == INVALID_FORMAT) {
+ pr_err("%s: wrong format[%d]", __func__, format);
+ return -EINVAL;
+ }
+
+ open.format = int_format;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s:open failed op[0x%x]rc[%d]\n",
+ __func__, open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s:timeout. waited for OPEN_WRITR rc[%d]\n",
+ __func__, rc);
+ goto fail_cmd;
+ } else
+ rc = 0;
+
+fail_cmd:
+ return rc;
+}
+
+int q6usm_run(struct us_client *usc, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts)
+{
+ struct usm_stream_cmd_run run;
+ int rc = 0;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ q6usm_add_hdr(usc, &run.hdr, sizeof(run), true);
+
+ run.hdr.opcode = USM_SESSION_CMD_RUN;
+ run.flags = flags;
+ run.msw_ts = msw_ts;
+ run.lsw_ts = lsw_ts;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &run);
+ if (rc < 0) {
+ pr_err("%s: Commmand run failed[%d]\n", __func__, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout. waited for run success rc[%d]\n",
+ __func__, rc);
+ } else
+ rc = 0;
+
+fail_cmd:
+ return rc;
+}
+
+
+
+int q6usm_read(struct us_client *usc, uint32_t read_ind)
+{
+ struct usm_stream_cmd_read read;
+ struct us_port_data *port = NULL;
+ int rc = 0;
+ u32 read_counter = 0;
+ u32 loop_ind = 0;
+ u64 buf_addr = 0;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ port = &usc->port[OUT];
+
+ if (read_ind > port->buf_cnt) {
+ pr_err("%s: wrong read_ind[%d]\n",
+ __func__, read_ind);
+ return -EINVAL;
+ }
+ if (read_ind == port->cpu_buf) {
+ pr_err("%s: no free region\n", __func__);
+ return 0;
+ }
+
+ if (read_ind > port->cpu_buf) { /* 1 range */
+ read_counter = read_ind - port->cpu_buf;
+ } else { /* 2 ranges */
+ read_counter = (port->buf_cnt - port->cpu_buf) + read_ind;
+ }
+
+ q6usm_add_hdr(usc, &read.hdr, sizeof(read), false);
+
+ read.hdr.opcode = USM_DATA_CMD_READ;
+ read.buf_size = port->buf_size;
+ buf_addr = (u64)(port->phys) + port->buf_size * (port->cpu_buf);
+ read.buf_addr_lsw = lower_32_bits(buf_addr);
+ read.buf_addr_msw = msm_audio_populate_upper_32_bits(buf_addr);
+ read.mem_map_handle = *((uint32_t *)(port->ext));
+
+ for (loop_ind = 0; loop_ind < read_counter; ++loop_ind) {
+ u32 temp_cpu_buf = port->cpu_buf;
+
+ buf_addr = (u64)(port->phys) +
+ port->buf_size * (port->cpu_buf);
+ read.buf_addr_lsw = lower_32_bits(buf_addr);
+ read.buf_addr_msw = msm_audio_populate_upper_32_bits(buf_addr);
+ read.seq_id = port->cpu_buf;
+ read.hdr.token = port->cpu_buf;
+ read.counter = 1;
+
+ ++(port->cpu_buf);
+ if (port->cpu_buf == port->buf_cnt)
+ port->cpu_buf = 0;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &read);
+
+ if (rc < 0) {
+ port->cpu_buf = temp_cpu_buf;
+
+ pr_err("%s:read op[0x%x]rc[%d]\n",
+ __func__, read.hdr.opcode, rc);
+ break;
+ }
+
+ rc = 0;
+ } /* bufs loop */
+
+ return rc;
+}
+
+int q6usm_write(struct us_client *usc, uint32_t write_ind)
+{
+ int rc = 0;
+ struct usm_stream_cmd_write cmd_write;
+ struct us_port_data *port = NULL;
+ u32 current_dsp_buf = 0;
+ u64 buf_addr = 0;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ port = &usc->port[IN];
+
+ current_dsp_buf = port->dsp_buf;
+ /* free region, caused by new dsp_buf report from DSP, */
+ /* can be only extended */
+ if (port->cpu_buf >= current_dsp_buf) {
+ /* 2 -part free region, including empty buffer */
+ if ((write_ind <= port->cpu_buf) &&
+ (write_ind > current_dsp_buf)) {
+ pr_err("%s: wrong w_ind[%d]; d_buf=%d; c_buf=%d\n",
+ __func__, write_ind,
+ current_dsp_buf, port->cpu_buf);
+ return -EINVAL;
+ }
+ } else {
+ /* 1 -part free region */
+ if ((write_ind <= port->cpu_buf) ||
+ (write_ind > current_dsp_buf)) {
+ pr_err("%s: wrong w_ind[%d]; d_buf=%d; c_buf=%d\n",
+ __func__, write_ind,
+ current_dsp_buf, port->cpu_buf);
+ return -EINVAL;
+ }
+ }
+
+ q6usm_add_hdr(usc, &cmd_write.hdr, sizeof(cmd_write), false);
+
+ cmd_write.hdr.opcode = USM_DATA_CMD_WRITE;
+ cmd_write.buf_size = port->buf_size;
+ buf_addr = (u64)(port->phys) + port->buf_size * (port->cpu_buf);
+ cmd_write.buf_addr_lsw = lower_32_bits(buf_addr);
+ cmd_write.buf_addr_msw = msm_audio_populate_upper_32_bits(buf_addr);
+ cmd_write.mem_map_handle = *((uint32_t *)(port->ext));
+ cmd_write.res0 = 0;
+ cmd_write.res1 = 0;
+ cmd_write.res2 = 0;
+
+ while (port->cpu_buf != write_ind) {
+ u32 temp_cpu_buf = port->cpu_buf;
+
+ buf_addr = (u64)(port->phys) +
+ port->buf_size * (port->cpu_buf);
+ cmd_write.buf_addr_lsw = lower_32_bits(buf_addr);
+ cmd_write.buf_addr_msw =
+ msm_audio_populate_upper_32_bits(buf_addr);
+ cmd_write.seq_id = port->cpu_buf;
+ cmd_write.hdr.token = port->cpu_buf;
+
+ ++(port->cpu_buf);
+ if (port->cpu_buf == port->buf_cnt)
+ port->cpu_buf = 0;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &cmd_write);
+
+ if (rc < 0) {
+ port->cpu_buf = temp_cpu_buf;
+ pr_err("%s:write op[0x%x];rc[%d];cpu_buf[%d]\n",
+ __func__, cmd_write.hdr.opcode,
+ rc, port->cpu_buf);
+ break;
+ }
+
+ rc = 0;
+ }
+
+ return rc;
+}
+
+bool q6usm_is_write_buf_full(struct us_client *usc, uint32_t *free_region)
+{
+ struct us_port_data *port = NULL;
+ u32 cpu_buf = 0;
+
+ if ((usc == NULL) || !free_region) {
+ pr_err("%s: input data wrong\n", __func__);
+ return false;
+ }
+ port = &usc->port[IN];
+ cpu_buf = port->cpu_buf + 1;
+ if (cpu_buf == port->buf_cnt)
+ cpu_buf = 0;
+
+ *free_region = port->dsp_buf;
+
+ return cpu_buf == *free_region;
+}
+
+int q6usm_cmd(struct us_client *usc, int cmd)
+{
+ struct apr_hdr hdr;
+ int rc = 0;
+ atomic_t *state;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ q6usm_add_hdr(usc, &hdr, sizeof(hdr), true);
+ switch (cmd) {
+ case CMD_CLOSE:
+ hdr.opcode = USM_STREAM_CMD_CLOSE;
+ state = &usc->cmd_state;
+ break;
+
+ default:
+ pr_err("%s:Invalid format[%d]\n", __func__, cmd);
+ goto fail_cmd;
+ }
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("%s: Command 0x%x failed\n", __func__, hdr.opcode);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait, (atomic_read(state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s:timeout. waited for response opcode[0x%x]\n",
+ __func__, hdr.opcode);
+ } else
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int q6usm_set_us_detection(struct us_client *usc,
+ struct usm_session_cmd_detect_info *detect_info,
+ uint16_t detect_info_size)
+{
+ int rc = 0;
+
+ if ((usc == NULL) ||
+ (detect_info_size == 0) ||
+ (detect_info == NULL)) {
+ pr_err("%s: wrong input: usc=0x%pK, inf_size=%d; info=0x%pK",
+ __func__,
+ usc,
+ detect_info_size,
+ detect_info);
+ return -EINVAL;
+ }
+
+ q6usm_add_hdr(usc, &detect_info->hdr, detect_info_size, true);
+
+ detect_info->hdr.opcode = USM_SESSION_CMD_SIGNAL_DETECT_MODE;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *)detect_info);
+ if (rc < 0) {
+ pr_err("%s:Comamnd signal detect failed\n", __func__);
+ return -EINVAL;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: CMD_SIGNAL_DETECT_MODE: timeout=%d\n",
+ __func__, Q6USM_TIMEOUT_JIFFIES);
+ } else
+ rc = 0;
+
+ return rc;
+}
+
+int q6usm_set_us_stream_param(int dir, struct us_client *usc,
+ uint32_t module_id, uint32_t param_id, uint32_t buf_size)
+{
+ int rc = 0;
+ struct usm_stream_cmd_set_param cmd_set_param;
+ struct us_port_data *port = NULL;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ port = &usc->port[dir];
+
+ q6usm_add_hdr(usc, &cmd_set_param.hdr, sizeof(cmd_set_param), true);
+
+ cmd_set_param.hdr.opcode = USM_STREAM_CMD_SET_PARAM;
+ cmd_set_param.buf_size = buf_size;
+ cmd_set_param.buf_addr_msw =
+ msm_audio_populate_upper_32_bits(port->param_phys);
+ cmd_set_param.buf_addr_lsw = lower_32_bits(port->param_phys);
+ cmd_set_param.mem_map_handle =
+ *((uint32_t *)(port->param_buf_mem_handle));
+ cmd_set_param.module_id = module_id;
+ cmd_set_param.param_id = param_id;
+ cmd_set_param.hdr.token = 0;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &cmd_set_param);
+
+ if (rc < 0) {
+ pr_err("%s:write op[0x%x];rc[%d]\n",
+ __func__, cmd_set_param.hdr.opcode, rc);
+ }
+
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: CMD_SET_PARAM: timeout=%d\n",
+ __func__, Q6USM_TIMEOUT_JIFFIES);
+ } else
+ rc = 0;
+
+ return rc;
+}
+
+int q6usm_get_us_stream_param(int dir, struct us_client *usc,
+ uint32_t module_id, uint32_t param_id, uint32_t buf_size)
+{
+ int rc = 0;
+ struct usm_stream_cmd_get_param cmd_get_param;
+ struct us_port_data *port = NULL;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ port = &usc->port[dir];
+
+ q6usm_add_hdr(usc, &cmd_get_param.hdr, sizeof(cmd_get_param), true);
+
+ cmd_get_param.hdr.opcode = USM_STREAM_CMD_GET_PARAM;
+ cmd_get_param.buf_size = buf_size;
+ cmd_get_param.buf_addr_msw =
+ msm_audio_populate_upper_32_bits(port->param_phys);
+ cmd_get_param.buf_addr_lsw = lower_32_bits(port->param_phys);
+ cmd_get_param.mem_map_handle =
+ *((uint32_t *)(port->param_buf_mem_handle));
+ cmd_get_param.module_id = module_id;
+ cmd_get_param.param_id = param_id;
+ cmd_get_param.hdr.token = 0;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &cmd_get_param);
+
+ if (rc < 0) {
+ pr_err("%s:write op[0x%x];rc[%d]\n",
+ __func__, cmd_get_param.hdr.opcode, rc);
+ }
+
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: CMD_GET_PARAM: timeout=%d\n",
+ __func__, Q6USM_TIMEOUT_JIFFIES);
+ } else
+ rc = 0;
+
+ return rc;
+}
+
+static int __init q6usm_init(void)
+{
+ pr_debug("%s\n", __func__);
+ init_waitqueue_head(&this_mmap.cmd_wait);
+ memset(session, 0, sizeof(session));
+ return 0;
+}
+
+device_initcall(q6usm_init);
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.h b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.h
new file mode 100644
index 0000000..d45d165
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.h
@@ -0,0 +1,130 @@
+/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __Q6_USM_H__
+#define __Q6_USM_H__
+
+#include <linux/qdsp6v2/apr_us.h>
+
+#define Q6USM_EVENT_UNDEF 0
+#define Q6USM_EVENT_READ_DONE 1
+#define Q6USM_EVENT_WRITE_DONE 2
+#define Q6USM_EVENT_SIGNAL_DETECT_RESULT 3
+
+/* cyclic buffer with 1 gap support */
+#define USM_MIN_BUF_CNT 3
+
+#define FORMAT_USPS_EPOS 0x00000000
+#define FORMAT_USRAW 0x00000001
+#define FORMAT_USPROX 0x00000002
+#define FORMAT_USGES_SYNC 0x00000003
+#define FORMAT_USRAW_SYNC 0x00000004
+#define INVALID_FORMAT 0xffffffff
+
+#define IN 0x000
+#define OUT 0x001
+
+#define USM_WRONG_TOKEN 0xffffffff
+#define USM_UNDEF_TOKEN 0xfffffffe
+
+#define CMD_CLOSE 0x0004
+
+/* bit 0:1 represents priority of stream */
+#define STREAM_PRIORITY_NORMAL 0x0000
+#define STREAM_PRIORITY_LOW 0x0001
+#define STREAM_PRIORITY_HIGH 0x0002
+
+/* bit 4 represents META enable of encoded data buffer */
+#define BUFFER_META_ENABLE 0x0010
+
+struct us_port_data {
+ dma_addr_t phys;
+ /* cyclic region of buffers with 1 gap */
+ void *data;
+ /* number of buffers in the region */
+ uint32_t buf_cnt;
+ /* size of buffer */
+ size_t buf_size;
+ /* write index */
+ uint32_t dsp_buf;
+ /* read index */
+ uint32_t cpu_buf;
+ /* expected token from dsp */
+ uint32_t expected_token;
+ /* read or write locks */
+ struct mutex lock;
+ spinlock_t dsp_lock;
+ /* ION memory handle */
+ struct ion_handle *handle;
+ /* ION memory client */
+ struct ion_client *client;
+ /* extended parameters, related to q6 variants */
+ void *ext;
+ /* physical address of parameter buffer */
+ dma_addr_t param_phys;
+ /* buffer which stores the parameter data */
+ void *param_buf;
+ /* size of parameter buffer */
+ uint32_t param_buf_size;
+ /* parameter buffer memory handle */
+ void *param_buf_mem_handle;
+ /* ION memory handle for parameter buffer */
+ struct ion_handle *param_handle;
+ /* ION memory client for parameter buffer */
+ struct ion_client *param_client;
+};
+
+struct us_client {
+ int session;
+ /* idx:1 out port, 0: in port*/
+ struct us_port_data port[2];
+
+ struct apr_svc *apr;
+ struct mutex cmd_lock;
+
+ atomic_t cmd_state;
+ atomic_t eos_state;
+ wait_queue_head_t cmd_wait;
+
+ void (*cb)(uint32_t, uint32_t, uint32_t *, void *);
+ void *priv;
+};
+
+int q6usm_run(struct us_client *usc, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts);
+int q6usm_cmd(struct us_client *usc, int cmd);
+int q6usm_us_client_buf_alloc(unsigned int dir, struct us_client *usc,
+ unsigned int bufsz, unsigned int bufcnt);
+int q6usm_us_param_buf_alloc(unsigned int dir, struct us_client *usc,
+ unsigned int bufsz);
+int q6usm_enc_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg);
+int q6usm_dec_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg);
+int q6usm_read(struct us_client *usc, uint32_t read_ind);
+struct us_client *q6usm_us_client_alloc(
+ void (*cb)(uint32_t, uint32_t, uint32_t *, void *),
+ void *priv);
+int q6usm_open_read(struct us_client *usc, uint32_t format);
+void q6usm_us_client_free(struct us_client *usc);
+uint32_t q6usm_get_virtual_address(int dir, struct us_client *usc,
+ struct vm_area_struct *vms);
+int q6usm_open_write(struct us_client *usc, uint32_t format);
+int q6usm_write(struct us_client *usc, uint32_t write_ind);
+bool q6usm_is_write_buf_full(struct us_client *usc, uint32_t *free_region);
+int q6usm_set_us_detection(struct us_client *usc,
+ struct usm_session_cmd_detect_info *detect_info,
+ uint16_t detect_info_size);
+int q6usm_set_us_stream_param(int dir, struct us_client *usc,
+ uint32_t module_id, uint32_t param_id, uint32_t buf_size);
+int q6usm_get_us_stream_param(int dir, struct us_client *usc,
+ uint32_t module_id, uint32_t param_id, uint32_t buf_size);
+
+#endif /* __Q6_USM_H__ */
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
new file mode 100644
index 0000000..c964dcb
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
@@ -0,0 +1,2468 @@
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/compat.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/input.h>
+#include <linux/uaccess.h>
+#include <linux/time.h>
+#include <linux/kmemleak.h>
+#include <linux/wakelock.h>
+#include <linux/mutex.h>
+#include <sound/apr_audio.h>
+#include <linux/qdsp6v2/usf.h>
+#include "q6usm.h"
+#include "usfcdev.h"
+
+/* The driver version*/
+#define DRV_VERSION "1.7.1"
+#define USF_VERSION_ID 0x0171
+
+/* Standard timeout in the asynchronous ops */
+#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
+
+/* Undefined USF device */
+#define USF_UNDEF_DEV_ID 0xffff
+
+/* TX memory mapping flag */
+#define USF_VM_READ 1
+/* RX memory mapping flag */
+#define USF_VM_WRITE 2
+
+/* Number of events, copied from the user space to kernel one */
+#define USF_EVENTS_PORTION_SIZE 20
+
+/* Indexes in range definitions */
+#define MIN_IND 0
+#define MAX_IND 1
+
+/* The coordinates indexes */
+#define X_IND 0
+#define Y_IND 1
+#define Z_IND 2
+
+/* Shared memory limits */
+/* max_buf_size = (port_size(65535*2) * port_num(8) * group_size(3) */
+#define USF_MAX_BUF_SIZE 3145680
+#define USF_MAX_BUF_NUM 32
+
+/* max size for buffer set from user space */
+#define USF_MAX_USER_BUF_SIZE 100000
+
+/* Place for opreation result, received from QDSP6 */
+#define APR_RESULT_IND 1
+
+/* Place for US detection result, received from QDSP6 */
+#define APR_US_DETECT_RESULT_IND 0
+
+#define BITS_IN_BYTE 8
+
+/* Time to stay awake after tx read event (e.g., proximity) */
+#define STAY_AWAKE_AFTER_READ_MSECS 3000
+
+/* The driver states */
+enum usf_state_type {
+ USF_IDLE_STATE,
+ USF_OPENED_STATE,
+ USF_CONFIGURED_STATE,
+ USF_WORK_STATE,
+ USF_ADSP_RESTART_STATE,
+ USF_ERROR_STATE
+};
+
+/* The US detection status upon FW/HW based US detection results */
+enum usf_us_detect_type {
+ USF_US_DETECT_UNDEF,
+ USF_US_DETECT_YES,
+ USF_US_DETECT_NO
+};
+
+struct usf_xx_type {
+ /* Name of the client - event calculator */
+ char client_name[USF_MAX_CLIENT_NAME_SIZE];
+ /* The driver state in TX or RX direction */
+ enum usf_state_type usf_state;
+ /* wait for q6 events mechanism */
+ wait_queue_head_t wait;
+ /* IF with q6usm info */
+ struct us_client *usc;
+ /* Q6:USM' Encoder/decoder configuration */
+ struct us_encdec_cfg encdec_cfg;
+ /* Shared buffer (with Q6:USM) size */
+ uint32_t buffer_size;
+ /* Number of the shared buffers (with Q6:USM) */
+ uint32_t buffer_count;
+ /* Shared memory (Cyclic buffer with 1 gap) control */
+ uint32_t new_region;
+ uint32_t prev_region;
+ /* Q6:USM's events handler */
+ void (*cb)(uint32_t, uint32_t, uint32_t *, void *);
+ /* US detection result */
+ enum usf_us_detect_type us_detect_type;
+ /* User's update info isn't acceptable */
+ u8 user_upd_info_na;
+};
+
+struct usf_type {
+ /* TX device component configuration & control */
+ struct usf_xx_type usf_tx;
+ /* RX device component configuration & control */
+ struct usf_xx_type usf_rx;
+ /* Index into the opened device container */
+ /* To prevent mutual usage of the same device */
+ uint16_t dev_ind;
+ /* Event types, supported by device */
+ uint16_t event_types;
+ /* The input devices are "input" module registered clients */
+ struct input_dev *input_ifs[USF_MAX_EVENT_IND];
+ /* Bitmap of types of events, conflicting to USF's ones */
+ uint16_t conflicting_event_types;
+ /* Bitmap of types of events from devs, conflicting with USF */
+ uint16_t conflicting_event_filters;
+ /* The requested buttons bitmap */
+ uint16_t req_buttons_bitmap;
+ /* Mutex for exclusive operations (all public APIs) */
+ struct mutex mutex;
+};
+
+struct usf_input_dev_type {
+ /* Input event type, supported by the input device */
+ uint16_t event_type;
+ /* Input device name */
+ const char *input_dev_name;
+ /* Input device registration function */
+ int (*prepare_dev)(uint16_t, struct usf_type *,
+ struct us_input_info_type *,
+ const char *);
+ /* Input event notification function */
+ void (*notify_event)(struct usf_type *,
+ uint16_t,
+ struct usf_event_type *
+ );
+};
+
+
+/* The MAX number of the supported devices */
+#define MAX_DEVS_NUMBER 1
+
+/*
+ * code for a special button that is used to show/hide a
+ * hovering cursor in the input framework. Must be in
+ * sync with the button code definition in the framework
+ * (EventHub.h)
+ */
+#define BTN_USF_HOVERING_CURSOR 0x230
+
+/* Supported buttons container */
+static const int s_button_map[] = {
+ BTN_STYLUS,
+ BTN_STYLUS2,
+ BTN_TOOL_PEN,
+ BTN_TOOL_RUBBER,
+ BTN_TOOL_FINGER,
+ BTN_USF_HOVERING_CURSOR
+};
+
+/* The opened devices container */
+static int s_opened_devs[MAX_DEVS_NUMBER];
+
+static struct wakeup_source usf_wakeup_source;
+
+#define USF_NAME_PREFIX "usf_"
+#define USF_NAME_PREFIX_SIZE 4
+
+
+static struct input_dev *allocate_dev(uint16_t ind, const char *name)
+{
+ struct input_dev *in_dev = input_allocate_device();
+
+ if (in_dev == NULL) {
+ pr_err("%s: input_allocate_device() failed\n", __func__);
+ } else {
+ /* Common part configuration */
+ in_dev->name = name;
+ in_dev->phys = NULL;
+ in_dev->id.bustype = BUS_HOST;
+ in_dev->id.vendor = 0x0001;
+ in_dev->id.product = 0x0001;
+ in_dev->id.version = USF_VERSION_ID;
+ }
+ return in_dev;
+}
+
+static int prepare_tsc_input_device(uint16_t ind,
+ struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ int i = 0;
+
+ int num_buttons = min(ARRAY_SIZE(s_button_map),
+ sizeof(input_info->req_buttons_bitmap) *
+ BITS_IN_BYTE);
+ uint16_t max_buttons_bitmap = ((1 << ARRAY_SIZE(s_button_map)) - 1);
+
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ if (input_info->req_buttons_bitmap > max_buttons_bitmap) {
+ pr_err("%s: Requested buttons[%d] exceeds max buttons available[%d]\n",
+ __func__,
+ input_info->req_buttons_bitmap,
+ max_buttons_bitmap);
+ input_free_device(in_dev);
+ return -EINVAL;
+ }
+
+ usf_info->input_ifs[ind] = in_dev;
+ usf_info->req_buttons_bitmap =
+ input_info->req_buttons_bitmap;
+ in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ for (i = 0; i < num_buttons; i++)
+ if (input_info->req_buttons_bitmap & (1 << i))
+ in_dev->keybit[BIT_WORD(s_button_map[i])] |=
+ BIT_MASK(s_button_map[i]);
+
+ input_set_abs_params(in_dev, ABS_X,
+ input_info->tsc_x_dim[MIN_IND],
+ input_info->tsc_x_dim[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_Y,
+ input_info->tsc_y_dim[MIN_IND],
+ input_info->tsc_y_dim[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_DISTANCE,
+ input_info->tsc_z_dim[MIN_IND],
+ input_info->tsc_z_dim[MAX_IND],
+ 0, 0);
+
+ input_set_abs_params(in_dev, ABS_PRESSURE,
+ input_info->tsc_pressure[MIN_IND],
+ input_info->tsc_pressure[MAX_IND],
+ 0, 0);
+
+ input_set_abs_params(in_dev, ABS_TILT_X,
+ input_info->tsc_x_tilt[MIN_IND],
+ input_info->tsc_x_tilt[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_TILT_Y,
+ input_info->tsc_y_tilt[MIN_IND],
+ input_info->tsc_y_tilt[MAX_IND],
+ 0, 0);
+
+ return 0;
+}
+
+static int prepare_mouse_input_device(uint16_t ind, struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ usf_info->input_ifs[ind] = in_dev;
+ in_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+
+ in_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) |
+ BIT_MASK(BTN_MIDDLE);
+ in_dev->relbit[0] = BIT_MASK(REL_X) |
+ BIT_MASK(REL_Y) |
+ BIT_MASK(REL_Z);
+
+ return 0;
+}
+
+static int prepare_keyboard_input_device(
+ uint16_t ind,
+ struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ usf_info->input_ifs[ind] = in_dev;
+ in_dev->evbit[0] |= BIT_MASK(EV_KEY);
+ /* All keys are permitted */
+ memset(in_dev->keybit, 0xff, sizeof(in_dev->keybit));
+
+ return 0;
+}
+
+static void notify_tsc_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+
+{
+ int i = 0;
+ int num_buttons = min(ARRAY_SIZE(s_button_map),
+ sizeof(usf_info->req_buttons_bitmap) *
+ BITS_IN_BYTE);
+
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct point_event_type *pe = &(event->event_data.point_event);
+
+ input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
+ input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
+ input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
+
+ input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
+ input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
+
+ input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
+ input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
+
+ for (i = 0; i < num_buttons; i++) {
+ uint16_t mask = (1 << i),
+ btn_state = !!(pe->buttons_state_bitmap & mask);
+ if (usf_info->req_buttons_bitmap & mask)
+ input_report_key(input_if, s_button_map[i], btn_state);
+ }
+
+ input_sync(input_if);
+
+ pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d], buttons[%d]\n",
+ __func__,
+ pe->coordinates[X_IND],
+ pe->coordinates[Y_IND],
+ pe->coordinates[Z_IND],
+ pe->inclinations[X_IND],
+ pe->inclinations[Y_IND],
+ pe->pressure,
+ pe->buttons_state_bitmap);
+}
+
+static void notify_mouse_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+{
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct mouse_event_type *me = &(event->event_data.mouse_event);
+
+ input_report_rel(input_if, REL_X, me->rels[X_IND]);
+ input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
+ input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
+
+ input_report_key(input_if, BTN_LEFT,
+ me->buttons_states & USF_BUTTON_LEFT_MASK);
+ input_report_key(input_if, BTN_MIDDLE,
+ me->buttons_states & USF_BUTTON_MIDDLE_MASK);
+ input_report_key(input_if, BTN_RIGHT,
+ me->buttons_states & USF_BUTTON_RIGHT_MASK);
+
+ input_sync(input_if);
+
+ pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
+ __func__, me->rels[X_IND],
+ me->rels[Y_IND], me->buttons_states);
+}
+
+static void notify_key_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+{
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct key_event_type *ke = &(event->event_data.key_event);
+
+ input_report_key(input_if, ke->key, ke->key_state);
+ input_sync(input_if);
+ pr_debug("%s: key event: key[%d], state[%d]\n",
+ __func__,
+ ke->key,
+ ke->key_state);
+
+}
+
+static struct usf_input_dev_type s_usf_input_devs[] = {
+ {USF_TSC_EVENT, "usf_tsc",
+ prepare_tsc_input_device, notify_tsc_event},
+ {USF_TSC_PTR_EVENT, "usf_tsc_ptr",
+ prepare_tsc_input_device, notify_tsc_event},
+ {USF_MOUSE_EVENT, "usf_mouse",
+ prepare_mouse_input_device, notify_mouse_event},
+ {USF_KEYBOARD_EVENT, "usf_kb",
+ prepare_keyboard_input_device, notify_key_event},
+ {USF_TSC_EXT_EVENT, "usf_tsc_ext",
+ prepare_tsc_input_device, notify_tsc_event},
+};
+
+static void usf_rx_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct usf_xx_type *usf_xx = (struct usf_xx_type *) priv;
+
+ if (usf_xx == NULL) {
+ pr_err("%s: the private data is NULL\n", __func__);
+ return;
+ }
+
+ switch (opcode) {
+ case Q6USM_EVENT_WRITE_DONE:
+ wake_up(&usf_xx->wait);
+ break;
+
+ case RESET_EVENTS:
+ pr_err("%s: received RESET_EVENTS\n", __func__);
+ usf_xx->usf_state = USF_ADSP_RESTART_STATE;
+ wake_up(&usf_xx->wait);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void usf_tx_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct usf_xx_type *usf_xx = (struct usf_xx_type *) priv;
+
+ if (usf_xx == NULL) {
+ pr_err("%s: the private data is NULL\n", __func__);
+ return;
+ }
+
+ switch (opcode) {
+ case Q6USM_EVENT_READ_DONE:
+ pr_debug("%s: acquiring %d msec wake lock\n", __func__,
+ STAY_AWAKE_AFTER_READ_MSECS);
+ __pm_wakeup_event(&usf_wakeup_source,
+ STAY_AWAKE_AFTER_READ_MSECS);
+ if (token == USM_WRONG_TOKEN)
+ usf_xx->usf_state = USF_ERROR_STATE;
+ usf_xx->new_region = token;
+ wake_up(&usf_xx->wait);
+ break;
+
+ case Q6USM_EVENT_SIGNAL_DETECT_RESULT:
+ usf_xx->us_detect_type = (payload[APR_US_DETECT_RESULT_IND]) ?
+ USF_US_DETECT_YES :
+ USF_US_DETECT_NO;
+
+ wake_up(&usf_xx->wait);
+ break;
+
+ case APR_BASIC_RSP_RESULT:
+ if (payload[APR_RESULT_IND]) {
+ usf_xx->usf_state = USF_ERROR_STATE;
+ usf_xx->new_region = USM_WRONG_TOKEN;
+ wake_up(&usf_xx->wait);
+ }
+ break;
+
+ case RESET_EVENTS:
+ pr_err("%s: received RESET_EVENTS\n", __func__);
+ usf_xx->usf_state = USF_ADSP_RESTART_STATE;
+ wake_up(&usf_xx->wait);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void release_xx(struct usf_xx_type *usf_xx)
+{
+ if (usf_xx != NULL) {
+ if (usf_xx->usc) {
+ q6usm_us_client_free(usf_xx->usc);
+ usf_xx->usc = NULL;
+ }
+
+ if (usf_xx->encdec_cfg.params != NULL) {
+ kfree(usf_xx->encdec_cfg.params);
+ usf_xx->encdec_cfg.params = NULL;
+ }
+ }
+}
+
+static void usf_disable(struct usf_xx_type *usf_xx)
+{
+ if (usf_xx != NULL) {
+ if ((usf_xx->usf_state != USF_IDLE_STATE) &&
+ (usf_xx->usf_state != USF_OPENED_STATE)) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ usf_xx->usf_state = USF_OPENED_STATE;
+ wake_up(&usf_xx->wait);
+ }
+ release_xx(usf_xx);
+ }
+}
+
+static int config_xx(struct usf_xx_type *usf_xx, struct us_xx_info_type *config)
+{
+ int rc = 0;
+ uint16_t data_map_size = 0;
+ uint16_t min_map_size = 0;
+
+ if ((usf_xx == NULL) ||
+ (config == NULL))
+ return -EINVAL;
+
+ if ((config->buf_size == 0) ||
+ (config->buf_size > USF_MAX_BUF_SIZE) ||
+ (config->buf_num == 0) ||
+ (config->buf_num > USF_MAX_BUF_NUM)) {
+ pr_err("%s: wrong params: buf_size=%d; buf_num=%d\n",
+ __func__, config->buf_size, config->buf_num);
+ return -EINVAL;
+ }
+
+ data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
+ min_map_size = min(data_map_size, config->port_cnt);
+
+ if (config->client_name != NULL) {
+ if (strncpy_from_user(usf_xx->client_name,
+ (char __user *)config->client_name,
+ sizeof(usf_xx->client_name) - 1) < 0) {
+ pr_err("%s: get client name failed\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ pr_debug("%s: name=%s; buf_size:%d; dev_id:0x%x; sample_rate:%d\n",
+ __func__, usf_xx->client_name, config->buf_size,
+ config->dev_id, config->sample_rate);
+
+ pr_debug("%s: buf_num:%d; format:%d; port_cnt:%d; data_size=%d\n",
+ __func__, config->buf_num, config->stream_format,
+ config->port_cnt, config->params_data_size);
+
+ pr_debug("%s: id[0]=%d, id[1]=%d, id[2]=%d, id[3]=%d, id[4]=%d,\n",
+ __func__,
+ config->port_id[0],
+ config->port_id[1],
+ config->port_id[2],
+ config->port_id[3],
+ config->port_id[4]);
+
+ pr_debug("id[5]=%d, id[6]=%d, id[7]=%d\n",
+ config->port_id[5],
+ config->port_id[6],
+ config->port_id[7]);
+
+ /* q6usm allocation & configuration */
+ usf_xx->buffer_size = config->buf_size;
+ usf_xx->buffer_count = config->buf_num;
+ usf_xx->encdec_cfg.cfg_common.bits_per_sample =
+ config->bits_per_sample;
+ usf_xx->encdec_cfg.cfg_common.sample_rate = config->sample_rate;
+ /* AFE port e.g. AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX */
+ usf_xx->encdec_cfg.cfg_common.dev_id = config->dev_id;
+
+ usf_xx->encdec_cfg.cfg_common.ch_cfg = config->port_cnt;
+ memcpy((void *)&usf_xx->encdec_cfg.cfg_common.data_map,
+ (void *)config->port_id,
+ min_map_size);
+
+ usf_xx->encdec_cfg.format_id = config->stream_format;
+ usf_xx->encdec_cfg.params_size = config->params_data_size;
+ usf_xx->user_upd_info_na = 1; /* it's used in US_GET_TX_UPDATE */
+
+ if (config->params_data_size > 0) { /* transparent data copy */
+ usf_xx->encdec_cfg.params = kzalloc(config->params_data_size,
+ GFP_KERNEL);
+ /* False memory leak here - pointer in packed struct
+ * is undetected by kmemleak tool
+ */
+ kmemleak_ignore(usf_xx->encdec_cfg.params);
+ if (usf_xx->encdec_cfg.params == NULL) {
+ pr_err("%s: params memory alloc[%d] failure\n",
+ __func__,
+ config->params_data_size);
+ return -ENOMEM;
+ }
+ rc = copy_from_user(usf_xx->encdec_cfg.params,
+ (uint8_t __user *)config->params_data,
+ config->params_data_size);
+ if (rc) {
+ pr_err("%s: transparent data copy failure\n",
+ __func__);
+ kfree(usf_xx->encdec_cfg.params);
+ usf_xx->encdec_cfg.params = NULL;
+ return -EFAULT;
+ }
+ pr_debug("%s: params_size[%d]; params[%d,%d,%d,%d, %d]\n",
+ __func__,
+ config->params_data_size,
+ usf_xx->encdec_cfg.params[0],
+ usf_xx->encdec_cfg.params[1],
+ usf_xx->encdec_cfg.params[2],
+ usf_xx->encdec_cfg.params[3],
+ usf_xx->encdec_cfg.params[4]
+ );
+ }
+
+ usf_xx->usc = q6usm_us_client_alloc(usf_xx->cb, (void *)usf_xx);
+ if (!usf_xx->usc) {
+ pr_err("%s: Could not allocate q6usm client\n", __func__);
+ rc = -EFAULT;
+ }
+
+ return rc;
+}
+
+static bool usf_match(uint16_t event_type_ind, struct input_dev *dev)
+{
+ bool rc = false;
+
+ rc = (event_type_ind < MAX_EVENT_TYPE_NUM) &&
+ ((dev->name == NULL) ||
+ strcmp(dev->name, USF_NAME_PREFIX));
+ pr_debug("%s: name=[%s]; rc=%d\n",
+ __func__, dev->name, rc);
+
+ return rc;
+}
+
+static bool usf_register_conflicting_events(uint16_t event_types)
+{
+ bool rc = true;
+ uint16_t ind = 0;
+ uint16_t mask = 1;
+
+ for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+ if (event_types & mask) {
+ rc = usfcdev_register(ind, usf_match);
+ if (!rc)
+ break;
+ }
+ mask = mask << 1;
+ }
+
+ return rc;
+}
+
+static void usf_unregister_conflicting_events(uint16_t event_types)
+{
+ uint16_t ind = 0;
+ uint16_t mask = 1;
+
+ for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+ if (event_types & mask)
+ usfcdev_unregister(ind);
+ mask = mask << 1;
+ }
+}
+
+static void usf_set_event_filters(struct usf_type *usf, uint16_t event_filters)
+{
+ uint16_t ind = 0;
+ uint16_t mask = 1;
+
+ if (usf->conflicting_event_filters != event_filters) {
+ for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+ if (usf->conflicting_event_types & mask)
+ usfcdev_set_filter(ind, event_filters&mask);
+ mask = mask << 1;
+ }
+ usf->conflicting_event_filters = event_filters;
+ }
+}
+
+static int register_input_device(struct usf_type *usf_info,
+ struct us_input_info_type *input_info)
+{
+ int rc = 0;
+ bool ret = true;
+ uint16_t ind = 0;
+
+ if ((usf_info == NULL) ||
+ (input_info == NULL) ||
+ !(input_info->event_types & USF_ALL_EVENTS)) {
+ pr_err("%s: wrong input parameter(s)\n", __func__);
+ return -EINVAL;
+ }
+
+ for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
+ if (usf_info->input_ifs[ind] != NULL) {
+ pr_err("%s: input_if[%d] is already allocated\n",
+ __func__, ind);
+ return -EFAULT;
+ }
+ if ((input_info->event_types &
+ s_usf_input_devs[ind].event_type) &&
+ s_usf_input_devs[ind].prepare_dev) {
+ rc = (*s_usf_input_devs[ind].prepare_dev)(
+ ind,
+ usf_info,
+ input_info,
+ s_usf_input_devs[ind].input_dev_name);
+ if (rc)
+ return rc;
+
+ rc = input_register_device(usf_info->input_ifs[ind]);
+ if (rc) {
+ pr_err("%s: input_reg_dev() failed; rc=%d\n",
+ __func__, rc);
+ input_free_device(usf_info->input_ifs[ind]);
+ usf_info->input_ifs[ind] = NULL;
+ } else {
+ usf_info->event_types |=
+ s_usf_input_devs[ind].event_type;
+ pr_debug("%s: input device[%s] was registered\n",
+ __func__,
+ s_usf_input_devs[ind].input_dev_name);
+ }
+ } /* supported event */
+ } /* event types loop */
+
+ ret = usf_register_conflicting_events(
+ input_info->conflicting_event_types);
+ if (ret)
+ usf_info->conflicting_event_types =
+ input_info->conflicting_event_types;
+
+ return 0;
+}
+
+
+static void handle_input_event(struct usf_type *usf_info,
+ uint16_t event_counter,
+ struct usf_event_type __user *event)
+{
+ uint16_t ind = 0;
+ uint16_t events_num = 0;
+ struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
+ int rc = 0;
+
+ if ((usf_info == NULL) ||
+ (event == NULL) || (!event_counter)) {
+ return;
+ }
+
+ while (event_counter > 0) {
+ if (event_counter > USF_EVENTS_PORTION_SIZE) {
+ events_num = USF_EVENTS_PORTION_SIZE;
+ event_counter -= USF_EVENTS_PORTION_SIZE;
+ } else {
+ events_num = event_counter;
+ event_counter = 0;
+ }
+ rc = copy_from_user(usf_events,
+ (struct usf_event_type __user *)event,
+ events_num * sizeof(struct usf_event_type));
+ if (rc) {
+ pr_err("%s: copy upd_rx_info from user; rc=%d\n",
+ __func__, rc);
+ return;
+ }
+ for (ind = 0; ind < events_num; ++ind) {
+ struct usf_event_type *p_event = &usf_events[ind];
+ uint16_t if_ind = p_event->event_type_ind;
+
+ if ((if_ind >= USF_MAX_EVENT_IND) ||
+ (usf_info->input_ifs[if_ind] == NULL))
+ continue; /* event isn't supported */
+
+ if (s_usf_input_devs[if_ind].notify_event)
+ (*s_usf_input_devs[if_ind].notify_event)(
+ usf_info,
+ if_ind,
+ p_event);
+ } /* loop in the portion */
+ } /* all events loop */
+}
+
+static int usf_start_tx(struct usf_xx_type *usf_xx)
+{
+ int rc = q6usm_run(usf_xx->usc, 0, 0, 0);
+
+ pr_debug("%s: tx: q6usm_run; rc=%d\n", __func__, rc);
+ if (!rc) {
+ if (usf_xx->buffer_count >= USM_MIN_BUF_CNT) {
+ /* supply all buffers */
+ rc = q6usm_read(usf_xx->usc,
+ usf_xx->buffer_count);
+ pr_debug("%s: q6usm_read[%d]\n",
+ __func__, rc);
+
+ if (rc)
+ pr_err("%s: buf read failed",
+ __func__);
+ else
+ usf_xx->usf_state =
+ USF_WORK_STATE;
+ } else
+ usf_xx->usf_state =
+ USF_WORK_STATE;
+ }
+
+ return rc;
+} /* usf_start_tx */
+
+static int usf_start_rx(struct usf_xx_type *usf_xx)
+{
+ int rc = q6usm_run(usf_xx->usc, 0, 0, 0);
+
+ pr_debug("%s: rx: q6usm_run; rc=%d\n",
+ __func__, rc);
+ if (!rc)
+ usf_xx->usf_state = USF_WORK_STATE;
+
+ return rc;
+} /* usf_start_rx */
+
+static int __usf_set_us_detection(struct usf_type *usf,
+ struct us_detect_info_type *detect_info)
+{
+ uint32_t timeout = 0;
+ struct usm_session_cmd_detect_info *p_allocated_memory = NULL;
+ struct usm_session_cmd_detect_info usm_detect_info;
+ struct usm_session_cmd_detect_info *p_usm_detect_info =
+ &usm_detect_info;
+ uint32_t detect_info_size = sizeof(struct usm_session_cmd_detect_info);
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+ int rc = 0;
+
+ if (detect_info->us_detector != US_DETECT_FW) {
+ pr_err("%s: unsupported detector: %d\n",
+ __func__, detect_info->us_detector);
+ return -EINVAL;
+ }
+
+ if ((detect_info->params_data_size != 0) &&
+ (detect_info->params_data != NULL)) {
+ uint8_t *p_data = NULL;
+
+ detect_info_size += detect_info->params_data_size;
+ p_allocated_memory = kzalloc(detect_info_size, GFP_KERNEL);
+ if (p_allocated_memory == NULL) {
+ pr_err("%s: detect_info[%d] allocation failed\n",
+ __func__, detect_info_size);
+ return -ENOMEM;
+ }
+ p_usm_detect_info = p_allocated_memory;
+ p_data = (uint8_t *)p_usm_detect_info +
+ sizeof(struct usm_session_cmd_detect_info);
+
+ rc = copy_from_user(p_data,
+ (uint8_t __user *)(detect_info->params_data),
+ detect_info->params_data_size);
+ if (rc) {
+ pr_err("%s: copy params from user; rc=%d\n",
+ __func__, rc);
+ kfree(p_allocated_memory);
+ return -EFAULT;
+ }
+ p_usm_detect_info->algorithm_cfg_size =
+ detect_info->params_data_size;
+ } else
+ usm_detect_info.algorithm_cfg_size = 0;
+
+ p_usm_detect_info->detect_mode = detect_info->us_detect_mode;
+ p_usm_detect_info->skip_interval = detect_info->skip_time;
+
+ usf_xx->us_detect_type = USF_US_DETECT_UNDEF;
+
+ rc = q6usm_set_us_detection(usf_xx->usc,
+ p_usm_detect_info,
+ detect_info_size);
+ if (rc || (detect_info->detect_timeout == USF_NO_WAIT_TIMEOUT)) {
+ kfree(p_allocated_memory);
+ return rc;
+ }
+
+ /* Get US detection result */
+ if (detect_info->detect_timeout == USF_INFINITIVE_TIMEOUT) {
+ rc = wait_event_interruptible(usf_xx->wait,
+ (usf_xx->us_detect_type !=
+ USF_US_DETECT_UNDEF) ||
+ (usf_xx->usf_state ==
+ USF_ADSP_RESTART_STATE));
+ } else {
+ if (detect_info->detect_timeout == USF_DEFAULT_TIMEOUT)
+ timeout = USF_TIMEOUT_JIFFIES;
+ else
+ timeout = detect_info->detect_timeout * HZ;
+ }
+ rc = wait_event_interruptible_timeout(usf_xx->wait,
+ (usf_xx->us_detect_type !=
+ USF_US_DETECT_UNDEF) ||
+ (usf_xx->usf_state ==
+ USF_ADSP_RESTART_STATE), timeout);
+
+ /* In the case of aDSP restart, "no US" is assumed */
+ if (usf_xx->usf_state == USF_ADSP_RESTART_STATE)
+ rc = -EFAULT;
+
+ /* In the case of timeout, "no US" is assumed */
+ if (rc < 0)
+ pr_err("%s: Getting US detection failed rc[%d]\n",
+ __func__, rc);
+ else {
+ usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
+ detect_info->is_us =
+ (usf_xx->us_detect_type == USF_US_DETECT_YES);
+ }
+
+ kfree(p_allocated_memory);
+
+ return rc;
+} /* __usf_set_us_detection */
+
+static int usf_set_us_detection(struct usf_type *usf, unsigned long arg)
+{
+ struct us_detect_info_type detect_info;
+
+ int rc = copy_from_user(&detect_info,
+ (struct us_detect_info_type __user *) arg,
+ sizeof(detect_info));
+
+ if (rc) {
+ pr_err("%s: copy detect_info from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ if (detect_info.params_data_size > USF_MAX_USER_BUF_SIZE) {
+ pr_err("%s: user buffer size exceeds maximum\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ rc = __usf_set_us_detection(usf, &detect_info);
+ if (rc < 0) {
+ pr_err("%s: set us detection failed; rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = copy_to_user((void __user *)arg,
+ &detect_info,
+ sizeof(detect_info));
+ if (rc) {
+ pr_err("%s: copy detect_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* usf_set_us_detection */
+
+static int __usf_set_tx_info(struct usf_type *usf,
+ struct us_tx_info_type *config_tx)
+{
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+ int rc = 0;
+
+ usf_xx->new_region = USM_UNDEF_TOKEN;
+ usf_xx->prev_region = USM_UNDEF_TOKEN;
+ usf_xx->cb = usf_tx_cb;
+
+ init_waitqueue_head(&usf_xx->wait);
+
+ if (config_tx->us_xx_info.client_name != NULL) {
+ int res = strncpy_from_user(
+ usf_xx->client_name,
+ (char __user *)(config_tx->us_xx_info.client_name),
+ sizeof(usf_xx->client_name)-1);
+ if (res < 0) {
+ pr_err("%s: get client name failed\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ rc = config_xx(usf_xx, &(config_tx->us_xx_info));
+ if (rc)
+ return rc;
+
+ rc = q6usm_open_read(usf_xx->usc,
+ usf_xx->encdec_cfg.format_id);
+ if (rc)
+ return rc;
+
+ rc = q6usm_us_client_buf_alloc(OUT, usf_xx->usc,
+ usf_xx->buffer_size,
+ usf_xx->buffer_count);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
+ }
+
+ rc = q6usm_us_param_buf_alloc(OUT, usf_xx->usc,
+ config_tx->us_xx_info.max_get_set_param_buf_size);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
+ }
+
+ rc = q6usm_enc_cfg_blk(usf_xx->usc,
+ &usf_xx->encdec_cfg);
+ if (!rc &&
+ (config_tx->input_info.event_types != USF_NO_EVENT)) {
+ rc = register_input_device(usf,
+ &(config_tx->input_info));
+ }
+
+ if (rc)
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ else
+ usf_xx->usf_state = USF_CONFIGURED_STATE;
+
+ return rc;
+} /* __usf_set_tx_info */
+
+static int usf_set_tx_info(struct usf_type *usf, unsigned long arg)
+{
+ struct us_tx_info_type config_tx;
+
+ int rc = copy_from_user(&config_tx,
+ (struct us_tx_info_type __user *) arg,
+ sizeof(config_tx));
+
+ if (rc) {
+ pr_err("%s: copy config_tx from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ if (config_tx.us_xx_info.params_data_size > USF_MAX_USER_BUF_SIZE) {
+ pr_err("%s: user buffer size exceeds maximum\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ return __usf_set_tx_info(usf, &config_tx);
+} /* usf_set_tx_info */
+
+static int __usf_set_rx_info(struct usf_type *usf,
+ struct us_rx_info_type *config_rx)
+{
+ struct usf_xx_type *usf_xx = &usf->usf_rx;
+ int rc = 0;
+
+ usf_xx->new_region = USM_UNDEF_TOKEN;
+ usf_xx->prev_region = USM_UNDEF_TOKEN;
+
+ usf_xx->cb = usf_rx_cb;
+
+ rc = config_xx(usf_xx, &(config_rx->us_xx_info));
+ if (rc)
+ return rc;
+
+ rc = q6usm_open_write(usf_xx->usc,
+ usf_xx->encdec_cfg.format_id);
+ if (rc)
+ return rc;
+
+ rc = q6usm_us_client_buf_alloc(
+ IN,
+ usf_xx->usc,
+ usf_xx->buffer_size,
+ usf_xx->buffer_count);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
+ }
+
+ rc = q6usm_us_param_buf_alloc(IN, usf_xx->usc,
+ config_rx->us_xx_info.max_get_set_param_buf_size);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
+ }
+
+ rc = q6usm_dec_cfg_blk(usf_xx->usc,
+ &usf_xx->encdec_cfg);
+ if (rc)
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ else {
+ init_waitqueue_head(&usf_xx->wait);
+ usf_xx->usf_state = USF_CONFIGURED_STATE;
+ }
+
+ return rc;
+} /* __usf_set_rx_info */
+
+static int usf_set_rx_info(struct usf_type *usf, unsigned long arg)
+{
+ struct us_rx_info_type config_rx;
+
+ int rc = copy_from_user(&config_rx,
+ (struct us_rx_info_type __user *) arg,
+ sizeof(config_rx));
+
+ if (rc) {
+ pr_err("%s: copy config_rx from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ if (config_rx.us_xx_info.params_data_size > USF_MAX_USER_BUF_SIZE) {
+ pr_err("%s: user buffer size exceeds maximum\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ return __usf_set_rx_info(usf, &config_rx);
+} /* usf_set_rx_info */
+
+static int __usf_get_tx_update(struct usf_type *usf,
+ struct us_tx_update_info_type *upd_tx_info)
+{
+ unsigned long prev_jiffies = 0;
+ uint32_t timeout = 0;
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+ int rc = 0;
+
+ if (!usf_xx->user_upd_info_na) {
+ usf_set_event_filters(usf, upd_tx_info->event_filters);
+ handle_input_event(usf,
+ upd_tx_info->event_counter,
+ upd_tx_info->event);
+
+ /* Release available regions */
+ rc = q6usm_read(usf_xx->usc,
+ upd_tx_info->free_region);
+ if (rc)
+ return rc;
+ } else
+ usf_xx->user_upd_info_na = 0;
+
+ /* Get data ready regions */
+ if (upd_tx_info->timeout == USF_INFINITIVE_TIMEOUT) {
+ rc = wait_event_interruptible(usf_xx->wait,
+ (usf_xx->prev_region !=
+ usf_xx->new_region) ||
+ (usf_xx->usf_state !=
+ USF_WORK_STATE));
+ } else {
+ if (upd_tx_info->timeout == USF_NO_WAIT_TIMEOUT)
+ rc = (usf_xx->prev_region != usf_xx->new_region);
+ else {
+ prev_jiffies = jiffies;
+ if (upd_tx_info->timeout == USF_DEFAULT_TIMEOUT) {
+ timeout = USF_TIMEOUT_JIFFIES;
+ rc = wait_event_timeout(
+ usf_xx->wait,
+ (usf_xx->prev_region !=
+ usf_xx->new_region) ||
+ (usf_xx->usf_state !=
+ USF_WORK_STATE),
+ timeout);
+ } else {
+ timeout = upd_tx_info->timeout * HZ;
+ rc = wait_event_interruptible_timeout(
+ usf_xx->wait,
+ (usf_xx->prev_region !=
+ usf_xx->new_region) ||
+ (usf_xx->usf_state !=
+ USF_WORK_STATE),
+ timeout);
+ }
+ }
+ if (!rc) {
+ pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
+ __func__, prev_jiffies, jiffies);
+ pr_debug("%s: timeout. prev=%d; new=%d\n",
+ __func__, usf_xx->prev_region,
+ usf_xx->new_region);
+ pr_debug("%s: timeout. free_region=%d;\n",
+ __func__, upd_tx_info->free_region);
+ if (usf_xx->prev_region ==
+ usf_xx->new_region) {
+ pr_err("%s:read data: timeout\n",
+ __func__);
+ return -ETIME;
+ }
+ }
+ }
+
+ if ((usf_xx->usf_state != USF_WORK_STATE) ||
+ (rc == -ERESTARTSYS)) {
+ pr_err("%s: Get ready region failure; state[%d]; rc[%d]\n",
+ __func__, usf_xx->usf_state, rc);
+ return -EINTR;
+ }
+
+ upd_tx_info->ready_region = usf_xx->new_region;
+ usf_xx->prev_region = upd_tx_info->ready_region;
+
+ if (upd_tx_info->ready_region == USM_WRONG_TOKEN) {
+ pr_err("%s: TX path corrupted; prev=%d\n",
+ __func__, usf_xx->prev_region);
+ return -EIO;
+ }
+
+ return rc;
+} /* __usf_get_tx_update */
+
+static int usf_get_tx_update(struct usf_type *usf, unsigned long arg)
+{
+ struct us_tx_update_info_type upd_tx_info;
+
+ int rc = copy_from_user(&upd_tx_info,
+ (struct us_tx_update_info_type __user *) arg,
+ sizeof(upd_tx_info));
+
+ if (rc < 0) {
+ pr_err("%s: copy upd_tx_info from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ rc = __usf_get_tx_update(usf, &upd_tx_info);
+ if (rc < 0) {
+ pr_err("%s: get tx update failed; rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = copy_to_user((void __user *)arg,
+ &upd_tx_info,
+ sizeof(upd_tx_info));
+ if (rc) {
+ pr_err("%s: copy upd_tx_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* usf_get_tx_update */
+
+static int __usf_set_rx_update(struct usf_xx_type *usf_xx,
+ struct us_rx_update_info_type *upd_rx_info)
+{
+ int rc = 0;
+
+ /* Send available data regions */
+ if (upd_rx_info->ready_region !=
+ usf_xx->buffer_count) {
+ rc = q6usm_write(
+ usf_xx->usc,
+ upd_rx_info->ready_region);
+ if (rc)
+ return rc;
+ }
+
+ /* Get free regions */
+ rc = wait_event_timeout(
+ usf_xx->wait,
+ !q6usm_is_write_buf_full(
+ usf_xx->usc,
+ &(upd_rx_info->free_region)) ||
+ (usf_xx->usf_state == USF_IDLE_STATE),
+ USF_TIMEOUT_JIFFIES);
+
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s:timeout. wait for write buf not full\n",
+ __func__);
+ } else {
+ if (usf_xx->usf_state !=
+ USF_WORK_STATE) {
+ pr_err("%s: RX: state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ rc = -EINTR;
+ }
+ }
+
+ return rc;
+} /* __usf_set_rx_update */
+
+static int usf_set_rx_update(struct usf_xx_type *usf_xx, unsigned long arg)
+{
+ struct us_rx_update_info_type upd_rx_info;
+
+ int rc = copy_from_user(&upd_rx_info,
+ (struct us_rx_update_info_type __user *) arg,
+ sizeof(upd_rx_info));
+
+ if (rc) {
+ pr_err("%s: copy upd_rx_info from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ rc = __usf_set_rx_update(usf_xx, &upd_rx_info);
+ if (rc < 0) {
+ pr_err("%s: set rx update failed; rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = copy_to_user((void __user *)arg,
+ &upd_rx_info,
+ sizeof(upd_rx_info));
+ if (rc) {
+ pr_err("%s: copy rx_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* usf_set_rx_update */
+
+static void usf_release_input(struct usf_type *usf)
+{
+ uint16_t ind = 0;
+
+ usf_unregister_conflicting_events(
+ usf->conflicting_event_types);
+ usf->conflicting_event_types = 0;
+ for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
+ if (usf->input_ifs[ind] == NULL)
+ continue;
+ input_unregister_device(usf->input_ifs[ind]);
+ usf->input_ifs[ind] = NULL;
+ pr_debug("%s input_unregister_device[%s]\n",
+ __func__,
+ s_usf_input_devs[ind].input_dev_name);
+ }
+} /* usf_release_input */
+
+static int usf_stop_tx(struct usf_type *usf)
+{
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+
+ usf_release_input(usf);
+ usf_disable(usf_xx);
+
+ return 0;
+} /* usf_stop_tx */
+
+static int __usf_get_version(struct us_version_info_type *version_info)
+{
+ int rc = 0;
+
+ if (version_info->buf_size < sizeof(DRV_VERSION)) {
+ pr_err("%s: buf_size (%d) < version string size (%zu)\n",
+ __func__, version_info->buf_size, sizeof(DRV_VERSION));
+ return -EINVAL;
+ }
+
+ rc = copy_to_user((void __user *)(version_info->pbuf),
+ DRV_VERSION,
+ sizeof(DRV_VERSION));
+ if (rc) {
+ pr_err("%s: copy to version_info.pbuf; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* __usf_get_version */
+
+static int usf_get_version(unsigned long arg)
+{
+ struct us_version_info_type version_info;
+
+ int rc = copy_from_user(&version_info,
+ (struct us_version_info_type __user *) arg,
+ sizeof(version_info));
+
+ if (rc) {
+ pr_err("%s: copy version_info from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ rc = __usf_get_version(&version_info);
+ if (rc < 0) {
+ pr_err("%s: get version failed; rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = copy_to_user((void __user *)arg,
+ &version_info,
+ sizeof(version_info));
+ if (rc) {
+ pr_err("%s: copy version_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* usf_get_version */
+
+static int __usf_set_stream_param(struct usf_xx_type *usf_xx,
+ struct us_stream_param_type *set_stream_param,
+ int dir)
+{
+ struct us_client *usc = usf_xx->usc;
+ struct us_port_data *port;
+ int rc = 0;
+
+ if (usc == NULL) {
+ pr_err("%s: usc is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ port = &usc->port[dir];
+ if (port == NULL) {
+ pr_err("%s: port is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (port->param_buf == NULL) {
+ pr_err("%s: parameter buffer is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (set_stream_param->buf_size > port->param_buf_size) {
+ pr_err("%s: buf_size (%d) > maximum buf size (%d)\n",
+ __func__, set_stream_param->buf_size,
+ port->param_buf_size);
+ return -EINVAL;
+ }
+
+ if (set_stream_param->buf_size == 0) {
+ pr_err("%s: buf_size is 0\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = copy_from_user(port->param_buf,
+ (uint8_t __user *) set_stream_param->pbuf,
+ set_stream_param->buf_size);
+ if (rc) {
+ pr_err("%s: copy param buf from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ rc = q6usm_set_us_stream_param(dir, usc, set_stream_param->module_id,
+ set_stream_param->param_id,
+ set_stream_param->buf_size);
+ if (rc) {
+ pr_err("%s: q6usm_set_us_stream_param failed; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ return rc;
+}
+
+static int usf_set_stream_param(struct usf_xx_type *usf_xx,
+ unsigned long arg, int dir)
+{
+ struct us_stream_param_type set_stream_param;
+ int rc = 0;
+
+ rc = copy_from_user(&set_stream_param,
+ (struct us_stream_param_type __user *) arg,
+ sizeof(set_stream_param));
+
+ if (rc) {
+ pr_err("%s: copy set_stream_param from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ return __usf_set_stream_param(usf_xx, &set_stream_param, dir);
+} /* usf_set_stream_param */
+
+static int __usf_get_stream_param(struct usf_xx_type *usf_xx,
+ struct us_stream_param_type *get_stream_param,
+ int dir)
+{
+ struct us_client *usc = usf_xx->usc;
+ struct us_port_data *port;
+ int rc = 0;
+
+ if (usc == NULL) {
+ pr_err("%s: us_client is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ port = &usc->port[dir];
+
+ if (port->param_buf == NULL) {
+ pr_err("%s: parameter buffer is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (get_stream_param->buf_size > port->param_buf_size) {
+ pr_err("%s: buf_size (%d) > maximum buf size (%d)\n",
+ __func__, get_stream_param->buf_size,
+ port->param_buf_size);
+ return -EINVAL;
+ }
+
+ if (get_stream_param->buf_size == 0) {
+ pr_err("%s: buf_size is 0\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = q6usm_get_us_stream_param(dir, usc, get_stream_param->module_id,
+ get_stream_param->param_id,
+ get_stream_param->buf_size);
+ if (rc) {
+ pr_err("%s: q6usm_get_us_stream_param failed; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ rc = copy_to_user((uint8_t __user *) get_stream_param->pbuf,
+ port->param_buf,
+ get_stream_param->buf_size);
+ if (rc) {
+ pr_err("%s: copy param buf to user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ return rc;
+}
+
+static int usf_get_stream_param(struct usf_xx_type *usf_xx,
+ unsigned long arg, int dir)
+{
+ struct us_stream_param_type get_stream_param;
+ int rc = 0;
+
+ rc = copy_from_user(&get_stream_param,
+ (struct us_stream_param_type __user *) arg,
+ sizeof(get_stream_param));
+
+ if (rc) {
+ pr_err("%s: copy get_stream_param from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ return __usf_get_stream_param(usf_xx, &get_stream_param, dir);
+} /* usf_get_stream_param */
+
+static long __usf_ioctl(struct usf_type *usf,
+ unsigned int cmd,
+ unsigned long arg)
+{
+
+ int rc = 0;
+ struct usf_xx_type *usf_xx = NULL;
+
+ switch (cmd) {
+ case US_START_TX: {
+ usf_xx = &usf->usf_tx;
+ if (usf_xx->usf_state == USF_CONFIGURED_STATE)
+ rc = usf_start_tx(usf_xx);
+ else {
+ pr_err("%s: start_tx: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ return -EBADFD;
+ }
+ break;
+ }
+
+ case US_START_RX: {
+ usf_xx = &usf->usf_rx;
+ if (usf_xx->usf_state == USF_CONFIGURED_STATE)
+ rc = usf_start_rx(usf_xx);
+ else {
+ pr_err("%s: start_rx: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ return -EBADFD;
+ }
+ break;
+ }
+
+ case US_SET_TX_INFO: {
+ usf_xx = &usf->usf_tx;
+ if (usf_xx->usf_state == USF_OPENED_STATE)
+ rc = usf_set_tx_info(usf, arg);
+ else {
+ pr_err("%s: set_tx_info: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ return -EBADFD;
+ }
+
+ break;
+ } /* US_SET_TX_INFO */
+
+ case US_SET_RX_INFO: {
+ usf_xx = &usf->usf_rx;
+ if (usf_xx->usf_state == USF_OPENED_STATE)
+ rc = usf_set_rx_info(usf, arg);
+ else {
+ pr_err("%s: set_rx_info: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ return -EBADFD;
+ }
+
+ break;
+ } /* US_SET_RX_INFO */
+
+ case US_GET_TX_UPDATE: {
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+
+ if (usf_xx->usf_state == USF_WORK_STATE)
+ rc = usf_get_tx_update(usf, arg);
+ else {
+ pr_err("%s: get_tx_update: wrong state[%d]\n", __func__,
+ usf_xx->usf_state);
+ rc = -EBADFD;
+ }
+ break;
+ } /* US_GET_TX_UPDATE */
+
+ case US_SET_RX_UPDATE: {
+ struct usf_xx_type *usf_xx = &usf->usf_rx;
+
+ if (usf_xx->usf_state == USF_WORK_STATE)
+ rc = usf_set_rx_update(usf_xx, arg);
+ else {
+ pr_err("%s: set_rx_update: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ rc = -EBADFD;
+ }
+ break;
+ } /* US_SET_RX_UPDATE */
+
+ case US_STOP_TX: {
+ usf_xx = &usf->usf_tx;
+ if ((usf_xx->usf_state == USF_WORK_STATE)
+ || (usf_xx->usf_state == USF_ADSP_RESTART_STATE))
+ rc = usf_stop_tx(usf);
+ else {
+ pr_err("%s: stop_tx: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ return -EBADFD;
+ }
+ break;
+ } /* US_STOP_TX */
+
+ case US_STOP_RX: {
+ usf_xx = &usf->usf_rx;
+ if ((usf_xx->usf_state == USF_WORK_STATE)
+ || (usf_xx->usf_state == USF_ADSP_RESTART_STATE))
+ usf_disable(usf_xx);
+ else {
+ pr_err("%s: stop_rx: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ return -EBADFD;
+ }
+ break;
+ } /* US_STOP_RX */
+
+ case US_SET_DETECTION: {
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+
+ if (usf_xx->usf_state == USF_WORK_STATE)
+ rc = usf_set_us_detection(usf, arg);
+ else {
+ pr_err("%s: set us detection: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ rc = -EBADFD;
+ }
+ break;
+ } /* US_SET_DETECTION */
+
+ case US_GET_VERSION: {
+ rc = usf_get_version(arg);
+ break;
+ } /* US_GET_VERSION */
+
+ case US_SET_TX_STREAM_PARAM: {
+ rc = usf_set_stream_param(&usf->usf_tx, arg, OUT);
+ break;
+ } /* US_SET_TX_STREAM_PARAM */
+
+ case US_GET_TX_STREAM_PARAM: {
+ rc = usf_get_stream_param(&usf->usf_tx, arg, OUT);
+ break;
+ } /* US_GET_TX_STREAM_PARAM */
+
+ case US_SET_RX_STREAM_PARAM: {
+ rc = usf_set_stream_param(&usf->usf_rx, arg, IN);
+ break;
+ } /* US_SET_RX_STREAM_PARAM */
+
+ case US_GET_RX_STREAM_PARAM: {
+ rc = usf_get_stream_param(&usf->usf_rx, arg, IN);
+ break;
+ } /* US_GET_RX_STREAM_PARAM */
+
+ default:
+ pr_err("%s: unsupported IOCTL command [%d]\n",
+ __func__,
+ cmd);
+ rc = -ENOTTY;
+ break;
+ }
+
+ if (rc &&
+ ((cmd == US_SET_TX_INFO) ||
+ (cmd == US_SET_RX_INFO)))
+ release_xx(usf_xx);
+
+ return rc;
+} /* __usf_ioctl */
+
+static long usf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct usf_type *usf = file->private_data;
+ int rc = 0;
+
+ mutex_lock(&usf->mutex);
+ rc = __usf_ioctl(usf, cmd, arg);
+ mutex_unlock(&usf->mutex);
+
+ return rc;
+} /* usf_ioctl */
+
+#ifdef CONFIG_COMPAT
+
+#define US_SET_TX_INFO32 _IOW(USF_IOCTL_MAGIC, 0, \
+ struct us_tx_info_type32)
+#define US_GET_TX_UPDATE32 _IOWR(USF_IOCTL_MAGIC, 2, \
+ struct us_tx_update_info_type32)
+#define US_SET_RX_INFO32 _IOW(USF_IOCTL_MAGIC, 3, \
+ struct us_rx_info_type32)
+#define US_SET_RX_UPDATE32 _IOWR(USF_IOCTL_MAGIC, 4, \
+ struct us_rx_update_info_type32)
+#define US_SET_DETECTION32 _IOWR(USF_IOCTL_MAGIC, 8, \
+ struct us_detect_info_type32)
+#define US_GET_VERSION32 _IOWR(USF_IOCTL_MAGIC, 9, \
+ struct us_version_info_type32)
+#define US_SET_TX_STREAM_PARAM32 _IOW(USF_IOCTL_MAGIC, 10, \
+ struct us_stream_param_type32)
+#define US_GET_TX_STREAM_PARAM32 _IOWR(USF_IOCTL_MAGIC, 11, \
+ struct us_stream_param_type32)
+#define US_SET_RX_STREAM_PARAM32 _IOW(USF_IOCTL_MAGIC, 12, \
+ struct us_stream_param_type32)
+#define US_GET_RX_STREAM_PARAM32 _IOWR(USF_IOCTL_MAGIC, 13, \
+ struct us_stream_param_type32)
+
+/* Info structure common for TX and RX */
+struct us_xx_info_type32 {
+/* Input: general info */
+/* Name of the client - event calculator, ptr to char */
+ const compat_uptr_t client_name;
+/* Selected device identification, accepted in the kernel's CAD */
+ uint32_t dev_id;
+/* 0 - point_epos type; (e.g. 1 - gr_mmrd) */
+ uint32_t stream_format;
+/* Required sample rate in Hz */
+ uint32_t sample_rate;
+/* Size of a buffer (bytes) for US data transfer between the module and USF */
+ uint32_t buf_size;
+/* Number of the buffers for the US data transfer */
+ uint16_t buf_num;
+/* Number of the microphones (TX) or speakers(RX) */
+ uint16_t port_cnt;
+/* Microphones(TX) or speakers(RX) indexes in their enumeration */
+ uint8_t port_id[USF_MAX_PORT_NUM];
+/* Bits per sample 16 or 32 */
+ uint16_t bits_per_sample;
+/* Input: Transparent info for encoder in the LPASS */
+/* Parameters data size in bytes */
+ uint16_t params_data_size;
+/* Pointer to the parameters, ptr to uint8_t */
+ compat_uptr_t params_data;
+/* Max size of buffer for get and set parameter */
+ uint32_t max_get_set_param_buf_size;
+};
+
+struct us_tx_info_type32 {
+/* Common info. This struct includes ptr and therefore the 32 version */
+ struct us_xx_info_type32 us_xx_info;
+/* Info specific for TX. This struct doesn't include long or ptr
+ * and therefore no 32 version
+ */
+ struct us_input_info_type input_info;
+};
+
+struct us_tx_update_info_type32 {
+/* Input general: */
+/* Number of calculated events */
+ uint16_t event_counter;
+/* Calculated events or NULL, ptr to struct usf_event_type */
+ compat_uptr_t event;
+/* Pointer (read index) to the end of available region */
+/* in the shared US data memory */
+ uint32_t free_region;
+/* Time (sec) to wait for data or special values: */
+/* USF_NO_WAIT_TIMEOUT, USF_INFINITIVE_TIMEOUT, USF_DEFAULT_TIMEOUT */
+ uint32_t timeout;
+/* Events (from conflicting devs) to be disabled/enabled */
+ uint16_t event_filters;
+
+/* Input transparent data: */
+/* Parameters size */
+ uint16_t params_data_size;
+/* Pointer to the parameters, ptr to uint8_t */
+ compat_uptr_t params_data;
+/* Output parameters: */
+/* Pointer (write index) to the end of ready US data region */
+/* in the shared memory */
+ uint32_t ready_region;
+};
+
+struct us_rx_info_type32 {
+ /* Common info */
+ struct us_xx_info_type32 us_xx_info;
+ /* Info specific for RX*/
+};
+
+struct us_rx_update_info_type32 {
+/* Input general: */
+/* Pointer (write index) to the end of ready US data region */
+/* in the shared memory */
+ uint32_t ready_region;
+/* Input transparent data: */
+/* Parameters size */
+ uint16_t params_data_size;
+/* pPointer to the parameters, ptr to uint8_t */
+ compat_uptr_t params_data;
+/* Output parameters: */
+/* Pointer (read index) to the end of available region */
+/* in the shared US data memory */
+ uint32_t free_region;
+};
+
+struct us_detect_info_type32 {
+/* US detection place (HW|FW) */
+/* NA in the Active and OFF states */
+ enum us_detect_place_enum us_detector;
+/* US detection mode */
+ enum us_detect_mode_enum us_detect_mode;
+/* US data dropped during this time (msec) */
+ uint32_t skip_time;
+/* Transparent data size */
+ uint16_t params_data_size;
+/* Pointer to the transparent data, ptr to uint8_t */
+ compat_uptr_t params_data;
+/* Time (sec) to wait for US presence event */
+ uint32_t detect_timeout;
+/* Out parameter: US presence */
+ bool is_us;
+};
+
+struct us_version_info_type32 {
+/* Size of memory for the version string */
+ uint16_t buf_size;
+/* Pointer to the memory for the version string, ptr to char */
+ compat_uptr_t pbuf;
+};
+
+struct us_stream_param_type32 {
+/* Id of module */
+ uint32_t module_id;
+/* Id of parameter */
+ uint32_t param_id;
+/* Size of memory of the parameter buffer */
+ uint32_t buf_size;
+/* Pointer to the memory of the parameter buffer */
+ compat_uptr_t pbuf;
+};
+
+static void usf_compat_xx_info_type(struct us_xx_info_type32 *us_xx_info32,
+ struct us_xx_info_type *us_xx_info)
+{
+ int i = 0;
+
+ us_xx_info->client_name = compat_ptr(us_xx_info32->client_name);
+ us_xx_info->dev_id = us_xx_info32->dev_id;
+ us_xx_info->stream_format = us_xx_info32->stream_format;
+ us_xx_info->sample_rate = us_xx_info32->sample_rate;
+ us_xx_info->buf_size = us_xx_info32->buf_size;
+ us_xx_info->buf_num = us_xx_info32->buf_num;
+ us_xx_info->port_cnt = us_xx_info32->port_cnt;
+ for (i = 0; i < USF_MAX_PORT_NUM; i++)
+ us_xx_info->port_id[i] = us_xx_info32->port_id[i];
+ us_xx_info->bits_per_sample = us_xx_info32->bits_per_sample;
+ us_xx_info->params_data_size = us_xx_info32->params_data_size;
+ us_xx_info->params_data = compat_ptr(us_xx_info32->params_data);
+ us_xx_info->max_get_set_param_buf_size =
+ us_xx_info32->max_get_set_param_buf_size;
+}
+
+static int usf_set_tx_info32(struct usf_type *usf, unsigned long arg)
+{
+ struct us_tx_info_type32 config_tx32;
+ struct us_tx_info_type config_tx;
+
+ int rc = copy_from_user(&config_tx32,
+ (struct us_tx_info_type32 __user *) arg,
+ sizeof(config_tx32));
+
+ if (rc) {
+ pr_err("%s: copy config_tx from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+ memset(&config_tx, 0, sizeof(config_tx));
+ usf_compat_xx_info_type(&(config_tx32.us_xx_info),
+ &(config_tx.us_xx_info));
+ config_tx.input_info = config_tx32.input_info;
+
+ return __usf_set_tx_info(usf, &config_tx);
+} /* usf_set_tx_info 32*/
+
+static int usf_set_rx_info32(struct usf_type *usf, unsigned long arg)
+{
+ struct us_rx_info_type32 config_rx32;
+ struct us_rx_info_type config_rx;
+
+ int rc = copy_from_user(&config_rx32,
+ (struct us_rx_info_type32 __user *) arg,
+ sizeof(config_rx32));
+
+ if (rc) {
+ pr_err("%s: copy config_rx from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+ memset(&config_rx, 0, sizeof(config_rx));
+ usf_compat_xx_info_type(&(config_rx32.us_xx_info),
+ &(config_rx.us_xx_info));
+
+ return __usf_set_rx_info(usf, &config_rx);
+} /* usf_set_rx_info32 */
+
+static int usf_get_tx_update32(struct usf_type *usf, unsigned long arg)
+{
+ struct us_tx_update_info_type32 upd_tx_info32;
+ struct us_tx_update_info_type upd_tx_info;
+
+ int rc = copy_from_user(&upd_tx_info32,
+ (struct us_tx_update_info_type32 __user *) arg,
+ sizeof(upd_tx_info32));
+
+ if (rc) {
+ pr_err("%s: copy upd_tx_info32 from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ memset(&upd_tx_info, 0, sizeof(upd_tx_info));
+ upd_tx_info.event_counter = upd_tx_info32.event_counter;
+ upd_tx_info.event = compat_ptr(upd_tx_info32.event);
+ upd_tx_info.free_region = upd_tx_info32.free_region;
+ upd_tx_info.timeout = upd_tx_info32.timeout;
+ upd_tx_info.event_filters = upd_tx_info32.event_filters;
+ upd_tx_info.params_data_size = upd_tx_info32.params_data_size;
+ upd_tx_info.params_data = compat_ptr(upd_tx_info32.params_data);
+ upd_tx_info.ready_region = upd_tx_info32.ready_region;
+
+ rc = __usf_get_tx_update(usf, &upd_tx_info);
+ if (rc < 0) {
+ pr_err("%s: get tx update failed; rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Update only the fields that were changed */
+ upd_tx_info32.ready_region = upd_tx_info.ready_region;
+
+ rc = copy_to_user((void __user *)arg, &upd_tx_info32,
+ sizeof(upd_tx_info32));
+ if (rc) {
+ pr_err("%s: copy upd_tx_info32 to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* usf_get_tx_update */
+
+static int usf_set_rx_update32(struct usf_xx_type *usf_xx, unsigned long arg)
+{
+ struct us_rx_update_info_type32 upd_rx_info32;
+ struct us_rx_update_info_type upd_rx_info;
+
+ int rc = copy_from_user(&upd_rx_info32,
+ (struct us_rx_update_info_type32 __user *) arg,
+ sizeof(upd_rx_info32));
+
+ if (rc) {
+ pr_err("%s: copy upd_rx_info32 from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ memset(&upd_rx_info, 0, sizeof(upd_rx_info));
+ upd_rx_info.ready_region = upd_rx_info32.ready_region;
+ upd_rx_info.params_data_size = upd_rx_info32.params_data_size;
+ upd_rx_info.params_data = compat_ptr(upd_rx_info32.params_data);
+ upd_rx_info.free_region = upd_rx_info32.free_region;
+
+ rc = __usf_set_rx_update(usf_xx, &upd_rx_info);
+ if (rc < 0) {
+ pr_err("%s: set rx update failed; rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Update only the fields that were changed */
+ upd_rx_info32.free_region = upd_rx_info.free_region;
+
+ rc = copy_to_user((void __user *)arg,
+ &upd_rx_info32,
+ sizeof(upd_rx_info32));
+ if (rc) {
+ pr_err("%s: copy rx_info32 to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* usf_set_rx_update32 */
+
+static int usf_set_us_detection32(struct usf_type *usf, unsigned long arg)
+{
+ struct us_detect_info_type32 detect_info32;
+ struct us_detect_info_type detect_info;
+
+ int rc = copy_from_user(&detect_info32,
+ (struct us_detect_info_type32 __user *) arg,
+ sizeof(detect_info32));
+
+ if (rc) {
+ pr_err("%s: copy detect_info32 from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ if (detect_info32.params_data_size > USF_MAX_USER_BUF_SIZE) {
+ pr_err("%s: user buffer size exceeds maximum\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ memset(&detect_info, 0, sizeof(detect_info));
+ detect_info.us_detector = detect_info32.us_detector;
+ detect_info.us_detect_mode = detect_info32.us_detect_mode;
+ detect_info.skip_time = detect_info32.skip_time;
+ detect_info.params_data_size = detect_info32.params_data_size;
+ detect_info.params_data = compat_ptr(detect_info32.params_data);
+ detect_info.detect_timeout = detect_info32.detect_timeout;
+ detect_info.is_us = detect_info32.is_us;
+
+ rc = __usf_set_us_detection(usf, &detect_info);
+ if (rc < 0) {
+ pr_err("%s: set us detection failed; rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Update only the fields that were changed */
+ detect_info32.is_us = detect_info.is_us;
+
+ rc = copy_to_user((void __user *)arg,
+ &detect_info32,
+ sizeof(detect_info32));
+ if (rc) {
+ pr_err("%s: copy detect_info32 to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* usf_set_us_detection32 */
+
+static int usf_get_version32(unsigned long arg)
+{
+ struct us_version_info_type32 version_info32;
+ struct us_version_info_type version_info;
+
+ int rc = copy_from_user(&version_info32,
+ (struct us_version_info_type32 __user *) arg,
+ sizeof(version_info32));
+
+ if (rc) {
+ pr_err("%s: copy version_info32 from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ memset(&version_info, 0, sizeof(version_info));
+ version_info.buf_size = version_info32.buf_size;
+ version_info.pbuf = compat_ptr(version_info32.pbuf);
+
+ rc = __usf_get_version(&version_info);
+ if (rc < 0) {
+ pr_err("%s: get version failed; rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* None of the fields were changed */
+
+ rc = copy_to_user((void __user *)arg,
+ &version_info32,
+ sizeof(version_info32));
+ if (rc) {
+ pr_err("%s: copy version_info32 to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+
+ return rc;
+} /* usf_get_version32 */
+
+static int usf_set_stream_param32(struct usf_xx_type *usf_xx,
+ unsigned long arg, int dir)
+{
+ struct us_stream_param_type32 set_stream_param32;
+ struct us_stream_param_type set_stream_param;
+ int rc = 0;
+
+ rc = copy_from_user(&set_stream_param32,
+ (struct us_stream_param_type32 __user *) arg,
+ sizeof(set_stream_param32));
+
+ if (rc) {
+ pr_err("%s: copy set_stream_param from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ memset(&set_stream_param, 0, sizeof(set_stream_param));
+ set_stream_param.module_id = set_stream_param32.module_id;
+ set_stream_param.param_id = set_stream_param32.param_id;
+ set_stream_param.buf_size = set_stream_param32.buf_size;
+ set_stream_param.pbuf = compat_ptr(set_stream_param32.pbuf);
+
+ return __usf_set_stream_param(usf_xx, &set_stream_param, dir);
+} /* usf_set_stream_param32 */
+
+static int usf_get_stream_param32(struct usf_xx_type *usf_xx,
+ unsigned long arg, int dir)
+{
+ struct us_stream_param_type32 get_stream_param32;
+ struct us_stream_param_type get_stream_param;
+ int rc = 0;
+
+ rc = copy_from_user(&get_stream_param32,
+ (struct us_stream_param_type32 __user *) arg,
+ sizeof(get_stream_param32));
+
+ if (rc) {
+ pr_err("%s: copy get_stream_param from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ memset(&get_stream_param, 0, sizeof(get_stream_param));
+ get_stream_param.module_id = get_stream_param32.module_id;
+ get_stream_param.param_id = get_stream_param32.param_id;
+ get_stream_param.buf_size = get_stream_param32.buf_size;
+ get_stream_param.pbuf = compat_ptr(get_stream_param32.pbuf);
+
+ return __usf_get_stream_param(usf_xx, &get_stream_param, dir);
+} /* usf_get_stream_param32 */
+
+static long __usf_compat_ioctl(struct usf_type *usf,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int rc = 0;
+ struct usf_xx_type *usf_xx = NULL;
+
+ switch (cmd) {
+ case US_START_TX:
+ case US_START_RX:
+ case US_STOP_TX:
+ case US_STOP_RX: {
+ return __usf_ioctl(usf, cmd, arg);
+ }
+
+ case US_SET_TX_INFO32: {
+ usf_xx = &usf->usf_tx;
+ if (usf_xx->usf_state == USF_OPENED_STATE)
+ rc = usf_set_tx_info32(usf, arg);
+ else {
+ pr_err("%s: set_tx_info32: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ return -EBADFD;
+ }
+
+ break;
+ } /* US_SET_TX_INFO32 */
+
+ case US_SET_RX_INFO32: {
+ usf_xx = &usf->usf_rx;
+ if (usf_xx->usf_state == USF_OPENED_STATE)
+ rc = usf_set_rx_info32(usf, arg);
+ else {
+ pr_err("%s: set_rx_info32: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ return -EBADFD;
+ }
+
+ break;
+ } /* US_SET_RX_INFO32 */
+
+ case US_GET_TX_UPDATE32: {
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+
+ if (usf_xx->usf_state == USF_WORK_STATE)
+ rc = usf_get_tx_update32(usf, arg);
+ else {
+ pr_err("%s: get_tx_update32: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ rc = -EBADFD;
+ }
+ break;
+ } /* US_GET_TX_UPDATE32 */
+
+ case US_SET_RX_UPDATE32: {
+ struct usf_xx_type *usf_xx = &usf->usf_rx;
+
+ if (usf_xx->usf_state == USF_WORK_STATE)
+ rc = usf_set_rx_update32(usf_xx, arg);
+ else {
+ pr_err("%s: set_rx_update: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ rc = -EBADFD;
+ }
+ break;
+ } /* US_SET_RX_UPDATE32 */
+
+ case US_SET_DETECTION32: {
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+
+ if (usf_xx->usf_state == USF_WORK_STATE)
+ rc = usf_set_us_detection32(usf, arg);
+ else {
+ pr_err("%s: set us detection: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ rc = -EBADFD;
+ }
+ break;
+ } /* US_SET_DETECTION32 */
+
+ case US_GET_VERSION32: {
+ rc = usf_get_version32(arg);
+ break;
+ } /* US_GET_VERSION32 */
+
+ case US_SET_TX_STREAM_PARAM32: {
+ rc = usf_set_stream_param32(&usf->usf_tx, arg, OUT);
+ break;
+ } /* US_SET_TX_STREAM_PARAM32 */
+
+ case US_GET_TX_STREAM_PARAM32: {
+ rc = usf_get_stream_param32(&usf->usf_tx, arg, OUT);
+ break;
+ } /* US_GET_TX_STREAM_PARAM32 */
+
+ case US_SET_RX_STREAM_PARAM32: {
+ rc = usf_set_stream_param32(&usf->usf_rx, arg, IN);
+ break;
+ } /* US_SET_RX_STREAM_PARAM32 */
+
+ case US_GET_RX_STREAM_PARAM32: {
+ rc = usf_get_stream_param32(&usf->usf_rx, arg, IN);
+ break;
+ } /* US_GET_RX_STREAM_PARAM32 */
+
+ default:
+ pr_err("%s: unsupported IOCTL command [%d]\n",
+ __func__,
+ cmd);
+ rc = -ENOTTY;
+ break;
+ }
+
+ if (rc &&
+ ((cmd == US_SET_TX_INFO) ||
+ (cmd == US_SET_RX_INFO)))
+ release_xx(usf_xx);
+
+ return rc;
+} /* __usf_compat_ioctl */
+
+static long usf_compat_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ struct usf_type *usf = file->private_data;
+ int rc = 0;
+
+ mutex_lock(&usf->mutex);
+ rc = __usf_compat_ioctl(usf, cmd, arg);
+ mutex_unlock(&usf->mutex);
+
+ return rc;
+} /* usf_compat_ioctl */
+#endif /* CONFIG_COMPAT */
+
+static int usf_mmap(struct file *file, struct vm_area_struct *vms)
+{
+ struct usf_type *usf = file->private_data;
+ int dir = OUT;
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+ int rc = 0;
+
+ mutex_lock(&usf->mutex);
+ if (vms->vm_flags & USF_VM_WRITE) { /* RX buf mapping */
+ dir = IN;
+ usf_xx = &usf->usf_rx;
+ }
+ rc = q6usm_get_virtual_address(dir, usf_xx->usc, vms);
+ mutex_unlock(&usf->mutex);
+
+ return rc;
+}
+
+static uint16_t add_opened_dev(int minor)
+{
+ uint16_t ind = 0;
+
+ for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
+ if (minor == s_opened_devs[ind]) {
+ pr_err("%s: device %d is already opened\n",
+ __func__, minor);
+ return USF_UNDEF_DEV_ID;
+ }
+
+ if (s_opened_devs[ind] == 0) {
+ s_opened_devs[ind] = minor;
+ pr_debug("%s: device %d is added; ind=%d\n",
+ __func__, minor, ind);
+ return ind;
+ }
+ }
+
+ pr_err("%s: there is no place for device %d\n",
+ __func__, minor);
+ return USF_UNDEF_DEV_ID;
+}
+
+static int usf_open(struct inode *inode, struct file *file)
+{
+ struct usf_type *usf = NULL;
+ uint16_t dev_ind = 0;
+ int minor = MINOR(inode->i_rdev);
+
+ dev_ind = add_opened_dev(minor);
+ if (dev_ind == USF_UNDEF_DEV_ID)
+ return -EBUSY;
+
+ usf = kzalloc(sizeof(struct usf_type), GFP_KERNEL);
+ if (usf == NULL)
+ return -ENOMEM;
+
+ wakeup_source_init(&usf_wakeup_source, "usf");
+
+ file->private_data = usf;
+ usf->dev_ind = dev_ind;
+
+ usf->usf_tx.usf_state = USF_OPENED_STATE;
+ usf->usf_rx.usf_state = USF_OPENED_STATE;
+
+ usf->usf_tx.us_detect_type = USF_US_DETECT_UNDEF;
+ usf->usf_rx.us_detect_type = USF_US_DETECT_UNDEF;
+
+ mutex_init(&usf->mutex);
+
+ pr_debug("%s:usf in open\n", __func__);
+ return 0;
+}
+
+static int usf_release(struct inode *inode, struct file *file)
+{
+ struct usf_type *usf = file->private_data;
+
+ pr_debug("%s: release entry\n", __func__);
+
+ mutex_lock(&usf->mutex);
+ usf_release_input(usf);
+
+ usf_disable(&usf->usf_tx);
+ usf_disable(&usf->usf_rx);
+
+ s_opened_devs[usf->dev_ind] = 0;
+
+ wakeup_source_trash(&usf_wakeup_source);
+ mutex_unlock(&usf->mutex);
+ mutex_destroy(&usf->mutex);
+ kfree(usf);
+ pr_debug("%s: release exit\n", __func__);
+ return 0;
+}
+
+extern long usf_compat_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg);
+
+static const struct file_operations usf_fops = {
+ .owner = THIS_MODULE,
+ .open = usf_open,
+ .release = usf_release,
+ .unlocked_ioctl = usf_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = usf_compat_ioctl,
+#endif /* CONFIG_COMPAT */
+ .mmap = usf_mmap,
+};
+
+static struct miscdevice usf_misc[MAX_DEVS_NUMBER] = {
+ {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "usf1",
+ .fops = &usf_fops,
+ },
+};
+
+static int __init usf_init(void)
+{
+ int rc = 0;
+ uint16_t ind = 0;
+
+ pr_debug("%s: USF SW version %s.\n", __func__, DRV_VERSION);
+ pr_debug("%s: Max %d devs registration\n", __func__, MAX_DEVS_NUMBER);
+
+ for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
+ rc = misc_register(&usf_misc[ind]);
+ if (rc) {
+ pr_err("%s: misc_register() failed ind=%d; rc = %d\n",
+ __func__, ind, rc);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+device_initcall(usf_init);
+
+MODULE_DESCRIPTION("Ultrasound framework driver");
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/usfcdev.c b/drivers/misc/qcom/qdsp6v2/ultrasound/usfcdev.c
new file mode 100644
index 0000000..6b8aae0
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/usfcdev.c
@@ -0,0 +1,422 @@
+/* Copyright (c) 2012-2013, 2016-2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input/mt.h>
+#include <linux/syscalls.h>
+#include "usfcdev.h"
+
+#define UNDEF_ID 0xffffffff
+#define SLOT_CMD_ID 0
+#define MAX_RETRIES 10
+
+enum usdev_event_status {
+ USFCDEV_EVENT_ENABLED,
+ USFCDEV_EVENT_DISABLING,
+ USFCDEV_EVENT_DISABLED,
+};
+
+struct usfcdev_event {
+ bool (*match_cb)(uint16_t, struct input_dev *dev);
+ bool registered_event;
+ bool interleaved;
+ enum usdev_event_status event_status;
+};
+static struct usfcdev_event s_usfcdev_events[MAX_EVENT_TYPE_NUM];
+
+struct usfcdev_input_command {
+ unsigned int type;
+ unsigned int code;
+ unsigned int value;
+};
+
+static long s_usf_pid;
+
+static bool usfcdev_filter(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value);
+static bool usfcdev_match(struct input_handler *handler,
+ struct input_dev *dev);
+static int usfcdev_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ const struct input_device_id *id);
+static void usfcdev_disconnect(struct input_handle *handle);
+
+static const struct input_device_id usfc_tsc_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY) },
+ .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
+ /* assumption: ABS_X & ABS_Y are in the same long */
+ .absbit = { [BIT_WORD(ABS_X)] = BIT_MASK(ABS_X) |
+ BIT_MASK(ABS_Y) },
+ },
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY) },
+ .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
+ /* assumption: MT_.._X & MT_.._Y are in the same long */
+ .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
+ BIT_MASK(ABS_MT_POSITION_X) |
+ BIT_MASK(ABS_MT_POSITION_Y) },
+ },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, usfc_tsc_ids);
+
+static struct input_handler s_usfc_handlers[MAX_EVENT_TYPE_NUM] = {
+ { /* TSC handler */
+ .filter = usfcdev_filter,
+ .match = usfcdev_match,
+ .connect = usfcdev_connect,
+ .disconnect = usfcdev_disconnect,
+ /* .minor can be used as index in the container, */
+ /* because .fops isn't supported */
+ .minor = TSC_EVENT_TYPE_IND,
+ .name = "usfc_tsc_handler",
+ .id_table = usfc_tsc_ids,
+ },
+};
+
+/*
+ * For each event type, there are a number conflicting devices (handles)
+ * The first registered device (primary) is real TSC device; it's mandatory
+ * Optionally, later registered devices are simulated ones.
+ * They are dynamically managed
+ * The primary device's handles are stored in the below static array
+ */
+static struct input_handle s_usfc_primary_handles[MAX_EVENT_TYPE_NUM] = {
+ { /* TSC handle */
+ .handler = &s_usfc_handlers[TSC_EVENT_TYPE_IND],
+ .name = "usfc_tsc_handle",
+ },
+};
+
+static struct usfcdev_input_command initial_clear_cmds[] = {
+ {EV_ABS, ABS_PRESSURE, 0},
+ {EV_KEY, BTN_TOUCH, 0},
+};
+
+static struct usfcdev_input_command slot_clear_cmds[] = {
+ {EV_ABS, ABS_MT_SLOT, 0},
+ {EV_ABS, ABS_MT_TRACKING_ID, UNDEF_ID},
+};
+
+static struct usfcdev_input_command no_filter_cmds[] = {
+ {EV_ABS, ABS_MT_SLOT, 0},
+ {EV_ABS, ABS_MT_TRACKING_ID, UNDEF_ID},
+ {EV_SYN, SYN_REPORT, 0},
+};
+
+static bool usfcdev_match(struct input_handler *handler, struct input_dev *dev)
+{
+ bool rc = false;
+ int ind = handler->minor;
+
+ pr_debug("%s: name=[%s]; ind=%d\n", __func__, dev->name, ind);
+
+ if (s_usfcdev_events[ind].registered_event &&
+ s_usfcdev_events[ind].match_cb) {
+ rc = (*s_usfcdev_events[ind].match_cb)((uint16_t)ind, dev);
+ pr_debug("%s: [%s]; rc=%d\n", __func__, dev->name, rc);
+ }
+ return rc;
+}
+
+static int usfcdev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ int ret = 0;
+ uint16_t ind = handler->minor;
+ struct input_handle *usfc_handle = NULL;
+
+ if (s_usfc_primary_handles[ind].dev == NULL) {
+ pr_debug("%s: primary device; ind=%d\n",
+ __func__,
+ ind);
+ usfc_handle = &s_usfc_primary_handles[ind];
+ } else {
+ pr_debug("%s: secondary device; ind=%d\n",
+ __func__,
+ ind);
+ usfc_handle = kzalloc(sizeof(struct input_handle),
+ GFP_KERNEL);
+ if (!usfc_handle)
+ return -ENOMEM;
+
+ usfc_handle->handler = &s_usfc_handlers[ind];
+ usfc_handle->name = s_usfc_primary_handles[ind].name;
+ }
+ usfc_handle->dev = dev;
+ ret = input_register_handle(usfc_handle);
+ pr_debug("%s: name=[%s]; ind=%d; dev=0x%pK\n",
+ __func__,
+ dev->name,
+ ind,
+ usfc_handle->dev);
+ if (ret)
+ pr_err("%s: input_register_handle[%d] failed: ret=%d\n",
+ __func__,
+ ind,
+ ret);
+ else {
+ ret = input_open_device(usfc_handle);
+ if (ret) {
+ pr_err("%s: input_open_device[%d] failed: ret=%d\n",
+ __func__,
+ ind,
+ ret);
+ input_unregister_handle(usfc_handle);
+ } else
+ pr_debug("%s: device[%d] is opened\n",
+ __func__,
+ ind);
+ }
+
+ return ret;
+}
+
+static void usfcdev_disconnect(struct input_handle *handle)
+{
+ int ind = handle->handler->minor;
+
+ input_close_device(handle);
+ input_unregister_handle(handle);
+ pr_debug("%s: handle[%d], name=[%s] is disconnected\n",
+ __func__,
+ ind,
+ handle->dev->name);
+ if (s_usfc_primary_handles[ind].dev == handle->dev)
+ s_usfc_primary_handles[ind].dev = NULL;
+ else
+ kfree(handle);
+}
+
+static bool usfcdev_filter(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
+{
+ uint16_t i = 0;
+ uint16_t ind = (uint16_t)handle->handler->minor;
+ bool rc = (s_usfcdev_events[ind].event_status != USFCDEV_EVENT_ENABLED);
+
+ if (s_usf_pid == sys_getpid()) {
+ /* Pass events from usfcdev driver */
+ rc = false;
+ pr_debug("%s: event_type=%d; type=%d; code=%d; val=%d",
+ __func__,
+ ind,
+ type,
+ code,
+ value);
+ } else if (s_usfcdev_events[ind].event_status ==
+ USFCDEV_EVENT_DISABLING) {
+ uint32_t u_value = value;
+
+ s_usfcdev_events[ind].interleaved = true;
+ /* Pass events for freeing slots from TSC driver */
+ for (i = 0; i < ARRAY_SIZE(no_filter_cmds); ++i) {
+ if ((no_filter_cmds[i].type == type) &&
+ (no_filter_cmds[i].code == code) &&
+ (no_filter_cmds[i].value <= u_value)) {
+ rc = false;
+ pr_debug("%s: no_filter_cmds[%d]; %d",
+ __func__,
+ i,
+ no_filter_cmds[i].value);
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+bool usfcdev_register(
+ uint16_t event_type_ind,
+ bool (*match_cb)(uint16_t, struct input_dev *dev))
+{
+ int ret = 0;
+ bool rc = false;
+
+ if ((event_type_ind >= MAX_EVENT_TYPE_NUM) || !match_cb) {
+ pr_err("%s: wrong input: event_type_ind=%d; match_cb=0x%pK\n",
+ __func__,
+ event_type_ind,
+ match_cb);
+ return false;
+ }
+
+ if (s_usfcdev_events[event_type_ind].registered_event) {
+ pr_info("%s: handler[%d] was already registered\n",
+ __func__,
+ event_type_ind);
+ return true;
+ }
+
+ s_usfcdev_events[event_type_ind].registered_event = true;
+ s_usfcdev_events[event_type_ind].match_cb = match_cb;
+ s_usfcdev_events[event_type_ind].event_status = USFCDEV_EVENT_ENABLED;
+ ret = input_register_handler(&s_usfc_handlers[event_type_ind]);
+ if (!ret) {
+ rc = true;
+ pr_debug("%s: handler[%d] was registered\n",
+ __func__,
+ event_type_ind);
+ } else {
+ s_usfcdev_events[event_type_ind].registered_event = false;
+ s_usfcdev_events[event_type_ind].match_cb = NULL;
+ pr_err("%s: handler[%d] registration failed: ret=%d\n",
+ __func__,
+ event_type_ind,
+ ret);
+ }
+
+ return rc;
+}
+
+void usfcdev_unregister(uint16_t event_type_ind)
+{
+ if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+ pr_err("%s: wrong input: event_type_ind=%d\n",
+ __func__,
+ event_type_ind);
+ return;
+ }
+ if (s_usfcdev_events[event_type_ind].registered_event) {
+ input_unregister_handler(&s_usfc_handlers[event_type_ind]);
+ pr_debug("%s: handler[%d] was unregistered\n",
+ __func__,
+ event_type_ind);
+ s_usfcdev_events[event_type_ind].registered_event = false;
+ s_usfcdev_events[event_type_ind].match_cb = NULL;
+ s_usfcdev_events[event_type_ind].event_status =
+ USFCDEV_EVENT_ENABLED;
+
+ }
+}
+
+static inline void usfcdev_send_cmd(
+ struct input_dev *dev,
+ struct usfcdev_input_command cmd)
+{
+ input_event(dev, cmd.type, cmd.code, cmd.value);
+}
+
+static void usfcdev_clean_dev(uint16_t event_type_ind)
+{
+ struct input_dev *dev = NULL;
+ int i;
+ int j;
+ int retries = 0;
+
+ if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+ pr_err("%s: wrong input: event_type_ind=%d\n",
+ __func__,
+ event_type_ind);
+ return;
+ }
+ /* Only primary device must exist */
+ dev = s_usfc_primary_handles[event_type_ind].dev;
+ if (dev == NULL) {
+ pr_err("%s: NULL primary device\n",
+ __func__);
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(initial_clear_cmds); i++)
+ usfcdev_send_cmd(dev, initial_clear_cmds[i]);
+ input_sync(dev);
+
+ /* Send commands to free all slots */
+ for (i = 0; i < dev->mt->num_slots; i++) {
+ s_usfcdev_events[event_type_ind].interleaved = false;
+ if (input_mt_get_value(&dev->mt->slots[i],
+ ABS_MT_TRACKING_ID) < 0) {
+ pr_debug("%s: skipping slot %d",
+ __func__, i);
+ continue;
+ }
+ slot_clear_cmds[SLOT_CMD_ID].value = i;
+ for (j = 0; j < ARRAY_SIZE(slot_clear_cmds); j++)
+ usfcdev_send_cmd(dev, slot_clear_cmds[j]);
+
+ if (s_usfcdev_events[event_type_ind].interleaved) {
+ pr_debug("%s: interleaved(%d): slot(%d)",
+ __func__, i, dev->mt->slot);
+ if (retries++ < MAX_RETRIES) {
+ --i;
+ continue;
+ }
+ pr_warn("%s: index(%d) reached max retires",
+ __func__, i);
+ }
+
+ retries = 0;
+ input_sync(dev);
+ }
+}
+
+bool usfcdev_set_filter(uint16_t event_type_ind, bool filter)
+{
+ bool rc = true;
+
+ if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+ pr_err("%s: wrong input: event_type_ind=%d\n",
+ __func__,
+ event_type_ind);
+ return false;
+ }
+
+ if (s_usfcdev_events[event_type_ind].registered_event) {
+
+ pr_debug("%s: event_type[%d]; filter=%d\n",
+ __func__,
+ event_type_ind,
+ filter
+ );
+ if (filter) {
+ s_usfcdev_events[event_type_ind].event_status =
+ USFCDEV_EVENT_DISABLING;
+ s_usf_pid = sys_getpid();
+ usfcdev_clean_dev(event_type_ind);
+ s_usfcdev_events[event_type_ind].event_status =
+ USFCDEV_EVENT_DISABLED;
+ } else
+ s_usfcdev_events[event_type_ind].event_status =
+ USFCDEV_EVENT_ENABLED;
+ } else {
+ pr_err("%s: event_type[%d] isn't registered\n",
+ __func__,
+ event_type_ind);
+ rc = false;
+ }
+
+ return rc;
+}
+
+static int __init usfcdev_init(void)
+{
+ return 0;
+}
+
+device_initcall(usfcdev_init);
+
+MODULE_DESCRIPTION("Handle of events from devices, conflicting with USF");
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/usfcdev.h b/drivers/misc/qcom/qdsp6v2/ultrasound/usfcdev.h
new file mode 100644
index 0000000..03b62c5
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/usfcdev.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __USFCDEV_H__
+#define __USFCDEV_H__
+
+#include <linux/input.h>
+
+/* TSC event type index in the containers of the handlers & handles */
+#define TSC_EVENT_TYPE_IND 0
+/* Number of supported event types to be filtered */
+#define MAX_EVENT_TYPE_NUM 1
+
+bool usfcdev_register(
+ uint16_t event_type_ind,
+ bool (*match_cb)(uint16_t, struct input_dev *dev));
+void usfcdev_unregister(uint16_t event_type_ind);
+bool usfcdev_set_filter(uint16_t event_type_ind, bool filter);
+#endif /* __USFCDEV_H__ */
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 85342d1..7ea7114 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -42,6 +42,7 @@
obj-$(CONFIG_MSM_IPC_ROUTER_GLINK_XPRT) += ipc_router_glink_xprt.o
obj-$(CONFIG_MSM_QMI_INTERFACE) += qmi_interface.o
obj-$(CONFIG_MSM_GLINK_PKT) += msm_glink_pkt.o
+obj-y += qdsp6v2/
obj-$(CONFIG_MSM_SYSTEM_HEALTH_MONITOR) += system_health_monitor_v01.o
obj-$(CONFIG_MSM_SYSTEM_HEALTH_MONITOR) += system_health_monitor.o
obj-$(CONFIG_MSM_SYSMON_GLINK_COMM) += sysmon-glink.o sysmon-qmi.o
diff --git a/drivers/soc/qcom/qdsp6v2/Makefile b/drivers/soc/qcom/qdsp6v2/Makefile
new file mode 100644
index 0000000..f3505ba
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o voice_svc.o
+obj-$(CONFIG_MSM_QDSP6_APRV3) += apr.o apr_v3.o apr_tal.o voice_svc.o
+obj-$(CONFIG_MSM_QDSP6_APRV2_GLINK) += apr.o apr_v2.o apr_tal_glink.o voice_svc.o
+obj-$(CONFIG_MSM_QDSP6_APRV3_GLINK) += apr.o apr_v3.o apr_tal_glink.o voice_svc.o
+obj-$(CONFIG_SND_SOC_MSM_QDSP6V2_INTF) += msm_audio_ion.o
+obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
+obj-$(CONFIG_MSM_QDSP6_SSR) += audio_ssr.o
+obj-$(CONFIG_MSM_QDSP6_PDR) += audio_pdr.o
+obj-$(CONFIG_MSM_QDSP6_NOTIFIER) += audio_notifier.o
diff --git a/drivers/soc/qcom/qdsp6v2/adsp-loader.c b/drivers/soc/qcom/qdsp6v2/adsp-loader.c
new file mode 100644
index 0000000..1bde1bf
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/adsp-loader.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/of_device.h>
+#include <linux/sysfs.h>
+#include <soc/qcom/subsystem_restart.h>
+
+#define Q6_PIL_GET_DELAY_MS 100
+#define BOOT_CMD 1
+#define IMAGE_UNLOAD_CMD 0
+
+static ssize_t adsp_boot_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count);
+
+struct adsp_loader_private {
+ void *pil_h;
+ struct kobject *boot_adsp_obj;
+ struct attribute_group *attr_group;
+};
+
+static struct kobj_attribute adsp_boot_attribute =
+ __ATTR(boot, 0220, NULL, adsp_boot_store);
+
+static struct attribute *attrs[] = {
+ &adsp_boot_attribute.attr,
+ NULL,
+};
+
+static struct platform_device *adsp_private;
+static void adsp_loader_unload(struct platform_device *pdev);
+
+static void adsp_loader_do(struct platform_device *pdev)
+{
+
+ struct adsp_loader_private *priv = NULL;
+
+ const char *adsp_dt = "qcom,adsp-state";
+ int rc = 0;
+ u32 adsp_state;
+ const char *img_name;
+
+ if (!pdev) {
+ dev_err(&pdev->dev, "%s: Platform device null\n", __func__);
+ goto fail;
+ }
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev,
+ "%s: Device tree information missing\n", __func__);
+ goto fail;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, adsp_dt, &adsp_state);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: ADSP state = %x\n", __func__, adsp_state);
+ goto fail;
+ }
+
+ rc = of_property_read_string(pdev->dev.of_node,
+ "qcom,proc-img-to-load",
+ &img_name);
+
+ if (rc) {
+ dev_dbg(&pdev->dev,
+ "%s: loading default image ADSP\n", __func__);
+ goto load_adsp;
+ }
+ if (!strcmp(img_name, "modem")) {
+ /* adsp_state always returns "0". So load modem image based on
+ * apr_modem_state to prevent loading of image twice
+ */
+ adsp_state = apr_get_modem_state();
+ if (adsp_state == APR_SUBSYS_DOWN) {
+ priv = platform_get_drvdata(pdev);
+ if (!priv) {
+ dev_err(&pdev->dev,
+ " %s: Private data get failed\n", __func__);
+ goto fail;
+ }
+
+ priv->pil_h = subsystem_get("modem");
+ if (IS_ERR(priv->pil_h)) {
+ dev_err(&pdev->dev, "%s: pil get failed,\n",
+ __func__);
+ goto fail;
+ }
+
+ /* Set the state of the ADSP in APR driver */
+ apr_set_modem_state(APR_SUBSYS_LOADED);
+ } else if (adsp_state == APR_SUBSYS_LOADED) {
+ dev_dbg(&pdev->dev,
+ "%s: MDSP state = %x\n", __func__, adsp_state);
+ }
+
+ dev_dbg(&pdev->dev, "%s: Q6/MDSP image is loaded\n", __func__);
+ return;
+ }
+load_adsp:
+ {
+ adsp_state = apr_get_q6_state();
+ if (adsp_state == APR_SUBSYS_DOWN) {
+ priv = platform_get_drvdata(pdev);
+ if (!priv) {
+ dev_err(&pdev->dev,
+ " %s: Private data get failed\n", __func__);
+ goto fail;
+ }
+
+ priv->pil_h = subsystem_get("adsp");
+ if (IS_ERR(priv->pil_h)) {
+ dev_err(&pdev->dev, "%s: pil get failed,\n",
+ __func__);
+ goto fail;
+ }
+
+ /* Set the state of the ADSP in APR driver */
+ apr_set_q6_state(APR_SUBSYS_LOADED);
+ } else if (adsp_state == APR_SUBSYS_LOADED) {
+ dev_dbg(&pdev->dev,
+ "%s: ADSP state = %x\n", __func__, adsp_state);
+ }
+
+ dev_dbg(&pdev->dev, "%s: Q6/ADSP image is loaded\n", __func__);
+ return;
+ }
+fail:
+ dev_err(&pdev->dev, "%s: Q6 image loading failed\n", __func__);
+}
+
+
+static ssize_t adsp_boot_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int boot = 0;
+
+ if (sscanf(buf, "%du", &boot) != 1) {
+ pr_err("%s: failed to read boot info from string\n", __func__);
+ return -EINVAL;
+ }
+
+ if (boot == BOOT_CMD) {
+ pr_debug("%s: going to call adsp_loader_do\n", __func__);
+ adsp_loader_do(adsp_private);
+ } else if (boot == IMAGE_UNLOAD_CMD) {
+ pr_debug("%s: going to call adsp_unloader\n", __func__);
+ adsp_loader_unload(adsp_private);
+ }
+ return count;
+}
+
+static void adsp_loader_unload(struct platform_device *pdev)
+{
+ struct adsp_loader_private *priv = NULL;
+
+ priv = platform_get_drvdata(pdev);
+
+ if (!priv)
+ return;
+
+ if (priv->pil_h) {
+ dev_dbg(&pdev->dev, "%s: calling subsystem put\n", __func__);
+ subsystem_put(priv->pil_h);
+ priv->pil_h = NULL;
+ }
+}
+
+static int adsp_loader_init_sysfs(struct platform_device *pdev)
+{
+ int ret = -EINVAL;
+ struct adsp_loader_private *priv = NULL;
+
+ adsp_private = NULL;
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ priv->pil_h = NULL;
+ priv->boot_adsp_obj = NULL;
+ priv->attr_group = devm_kzalloc(&pdev->dev,
+ sizeof(*(priv->attr_group)),
+ GFP_KERNEL);
+ if (!priv->attr_group) {
+ ret = -ENOMEM;
+ goto error_return;
+ }
+
+ priv->attr_group->attrs = attrs;
+
+ priv->boot_adsp_obj = kobject_create_and_add("boot_adsp", kernel_kobj);
+ if (!priv->boot_adsp_obj) {
+ dev_err(&pdev->dev, "%s: sysfs create and add failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error_return;
+ }
+
+ ret = sysfs_create_group(priv->boot_adsp_obj, priv->attr_group);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: sysfs create group failed %d\n",
+ __func__, ret);
+ goto error_return;
+ }
+
+ adsp_private = pdev;
+
+ return 0;
+
+error_return:
+
+ if (priv->boot_adsp_obj) {
+ kobject_del(priv->boot_adsp_obj);
+ priv->boot_adsp_obj = NULL;
+ }
+
+ return ret;
+}
+
+static int adsp_loader_remove(struct platform_device *pdev)
+{
+ struct adsp_loader_private *priv = NULL;
+
+ priv = platform_get_drvdata(pdev);
+
+ if (!priv)
+ return 0;
+
+ if (priv->pil_h) {
+ subsystem_put(priv->pil_h);
+ priv->pil_h = NULL;
+ }
+
+ if (priv->boot_adsp_obj) {
+ sysfs_remove_group(priv->boot_adsp_obj, priv->attr_group);
+ kobject_del(priv->boot_adsp_obj);
+ priv->boot_adsp_obj = NULL;
+ }
+
+ return 0;
+}
+
+static int adsp_loader_probe(struct platform_device *pdev)
+{
+ int ret = adsp_loader_init_sysfs(pdev);
+
+ if (ret != 0) {
+ dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id adsp_loader_dt_match[] = {
+ { .compatible = "qcom,adsp-loader" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adsp_loader_dt_match);
+
+static struct platform_driver adsp_loader_driver = {
+ .driver = {
+ .name = "adsp-loader",
+ .owner = THIS_MODULE,
+ .of_match_table = adsp_loader_dt_match,
+ },
+ .probe = adsp_loader_probe,
+ .remove = adsp_loader_remove,
+};
+
+static int __init adsp_loader_init(void)
+{
+ return platform_driver_register(&adsp_loader_driver);
+}
+module_init(adsp_loader_init);
+
+static void __exit adsp_loader_exit(void)
+{
+ platform_driver_unregister(&adsp_loader_driver);
+}
+module_exit(adsp_loader_exit);
+
+MODULE_DESCRIPTION("ADSP Loader module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
new file mode 100644
index 0000000..5f3c9d4
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -0,0 +1,970 @@
+/* Copyright (c) 2010-2014, 2016-2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/scm.h>
+#include <sound/apr_audio-v2.h>
+#include <soc/qcom/smd.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/qdsp6v2/apr_tal.h>
+#include <linux/qdsp6v2/dsp_debug.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <linux/ipc_logging.h>
+
+#define APR_PKT_IPC_LOG_PAGE_CNT 2
+
+static struct apr_q6 q6;
+static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
+static void *apr_pkt_ctx;
+static wait_queue_head_t dsp_wait;
+static wait_queue_head_t modem_wait;
+static bool is_modem_up;
+static bool is_initial_boot;
+/* Subsystem restart: QDSP6 data, functions */
+static struct workqueue_struct *apr_reset_workqueue;
+static void apr_reset_deregister(struct work_struct *work);
+static void dispatch_event(unsigned long code, uint16_t proc);
+struct apr_reset_work {
+ void *handle;
+ struct work_struct work;
+};
+
+static bool apr_cf_debug;
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_apr_debug;
+static ssize_t apr_debug_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ char cmd;
+
+ if (copy_from_user(&cmd, ubuf, 1))
+ return -EFAULT;
+
+ apr_cf_debug = (cmd == '1') ? true : false;
+
+ return cnt;
+}
+
+static const struct file_operations apr_debug_ops = {
+ .write = apr_debug_write,
+};
+#endif
+
+#define APR_PKT_INFO(x...) \
+do { \
+ if (apr_pkt_ctx) \
+ ipc_log_string(apr_pkt_ctx, "<APR>: "x); \
+} while (0)
+
+
+struct apr_svc_table {
+ char name[64];
+ int idx;
+ int id;
+ int client_id;
+};
+
+static const struct apr_svc_table svc_tbl_qdsp6[] = {
+ {
+ .name = "AFE",
+ .idx = 0,
+ .id = APR_SVC_AFE,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "ASM",
+ .idx = 1,
+ .id = APR_SVC_ASM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "ADM",
+ .idx = 2,
+ .id = APR_SVC_ADM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "CORE",
+ .idx = 3,
+ .id = APR_SVC_ADSP_CORE,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "TEST",
+ .idx = 4,
+ .id = APR_SVC_TEST_CLIENT,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "MVM",
+ .idx = 5,
+ .id = APR_SVC_ADSP_MVM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "CVS",
+ .idx = 6,
+ .id = APR_SVC_ADSP_CVS,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "CVP",
+ .idx = 7,
+ .id = APR_SVC_ADSP_CVP,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "USM",
+ .idx = 8,
+ .id = APR_SVC_USM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "VIDC",
+ .idx = 9,
+ .id = APR_SVC_VIDC,
+ },
+ {
+ .name = "LSM",
+ .idx = 10,
+ .id = APR_SVC_LSM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+};
+
+static struct apr_svc_table svc_tbl_voice[] = {
+ {
+ .name = "VSM",
+ .idx = 0,
+ .id = APR_SVC_VSM,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "VPM",
+ .idx = 1,
+ .id = APR_SVC_VPM,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "MVS",
+ .idx = 2,
+ .id = APR_SVC_MVS,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "MVM",
+ .idx = 3,
+ .id = APR_SVC_MVM,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "CVS",
+ .idx = 4,
+ .id = APR_SVC_CVS,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "CVP",
+ .idx = 5,
+ .id = APR_SVC_CVP,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "SRD",
+ .idx = 6,
+ .id = APR_SVC_SRD,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "TEST",
+ .idx = 7,
+ .id = APR_SVC_TEST_CLIENT,
+ .client_id = APR_CLIENT_VOICE,
+ },
+};
+
+enum apr_subsys_state apr_get_modem_state(void)
+{
+ return atomic_read(&q6.modem_state);
+}
+
+void apr_set_modem_state(enum apr_subsys_state state)
+{
+ atomic_set(&q6.modem_state, state);
+}
+
+enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev,
+ enum apr_subsys_state new)
+{
+ return atomic_cmpxchg(&q6.modem_state, prev, new);
+}
+
+static void apr_modem_down(unsigned long opcode)
+{
+ apr_set_modem_state(APR_SUBSYS_DOWN);
+ dispatch_event(opcode, APR_DEST_MODEM);
+}
+
+static void apr_modem_up(void)
+{
+ if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
+ APR_SUBSYS_DOWN)
+ wake_up(&modem_wait);
+ is_modem_up = 1;
+}
+
+enum apr_subsys_state apr_get_q6_state(void)
+{
+ return atomic_read(&q6.q6_state);
+}
+EXPORT_SYMBOL(apr_get_q6_state);
+
+int apr_set_q6_state(enum apr_subsys_state state)
+{
+ pr_debug("%s: setting adsp state %d\n", __func__, state);
+ if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED)
+ return -EINVAL;
+ atomic_set(&q6.q6_state, state);
+ return 0;
+}
+EXPORT_SYMBOL(apr_set_q6_state);
+
+enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev,
+ enum apr_subsys_state new)
+{
+ return atomic_cmpxchg(&q6.q6_state, prev, new);
+}
+
+static void apr_adsp_down(unsigned long opcode)
+{
+ apr_set_q6_state(APR_SUBSYS_DOWN);
+ dispatch_event(opcode, APR_DEST_QDSP6);
+}
+
+static void apr_adsp_up(void)
+{
+ if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_LOADED) ==
+ APR_SUBSYS_DOWN)
+ wake_up(&dsp_wait);
+}
+
+int apr_wait_for_device_up(int dest_id)
+{
+ int rc = -1;
+
+ if (dest_id == APR_DEST_MODEM)
+ rc = wait_event_interruptible_timeout(modem_wait,
+ (apr_get_modem_state() == APR_SUBSYS_UP),
+ (1 * HZ));
+ else if (dest_id == APR_DEST_QDSP6)
+ rc = wait_event_interruptible_timeout(dsp_wait,
+ (apr_get_q6_state() == APR_SUBSYS_UP),
+ (1 * HZ));
+ else
+ pr_err("%s: unknown dest_id %d\n", __func__, dest_id);
+ /* returns left time */
+ return rc;
+}
+
+int apr_load_adsp_image(void)
+{
+ int rc = 0;
+
+ mutex_lock(&q6.lock);
+ if (apr_get_q6_state() == APR_SUBSYS_UP) {
+ q6.pil = subsystem_get("adsp");
+ if (IS_ERR(q6.pil)) {
+ rc = PTR_ERR(q6.pil);
+ pr_err("APR: Unable to load q6 image, error:%d\n", rc);
+ } else {
+ apr_set_q6_state(APR_SUBSYS_LOADED);
+ pr_debug("APR: Image is loaded, stated\n");
+ }
+ } else if (apr_get_q6_state() == APR_SUBSYS_LOADED) {
+ pr_debug("APR: q6 image already loaded\n");
+ } else {
+ pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
+ }
+ mutex_unlock(&q6.lock);
+ return rc;
+}
+
+struct apr_client *apr_get_client(int dest_id, int client_id)
+{
+ return &client[dest_id][client_id];
+}
+
+int apr_send_pkt(void *handle, uint32_t *buf)
+{
+ struct apr_svc *svc = handle;
+ struct apr_client *clnt;
+ struct apr_hdr *hdr;
+ uint16_t dest_id;
+ uint16_t client_id;
+ uint16_t w_len;
+ int rc;
+ unsigned long flags;
+
+ if (!handle || !buf) {
+ pr_err("APR: Wrong parameters\n");
+ return -EINVAL;
+ }
+ if (svc->need_reset) {
+ pr_err("apr: send_pkt service need reset\n");
+ return -ENETRESET;
+ }
+
+ if ((svc->dest_id == APR_DEST_QDSP6) &&
+ (apr_get_q6_state() != APR_SUBSYS_LOADED)) {
+ pr_err("%s: Still dsp is not Up\n", __func__);
+ return -ENETRESET;
+ } else if ((svc->dest_id == APR_DEST_MODEM) &&
+ (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+ pr_err("apr: Still Modem is not Up\n");
+ return -ENETRESET;
+ }
+
+ spin_lock_irqsave(&svc->w_lock, flags);
+ dest_id = svc->dest_id;
+ client_id = svc->client_id;
+ clnt = &client[dest_id][client_id];
+
+ if (!client[dest_id][client_id].handle) {
+ pr_err("APR: Still service is not yet opened\n");
+ spin_unlock_irqrestore(&svc->w_lock, flags);
+ return -EINVAL;
+ }
+ hdr = (struct apr_hdr *)buf;
+
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->src_svc = svc->id;
+ hdr->dest_domain = svc->dest_domain;
+ hdr->dest_svc = svc->id;
+
+ if (unlikely(apr_cf_debug)) {
+ APR_PKT_INFO(
+ "Tx: src_addr[0x%X] dest_addr[0x%X] opcode[0x%X] token[0x%X]",
+ (hdr->src_domain << 8) | hdr->src_svc,
+ (hdr->dest_domain << 8) | hdr->dest_svc, hdr->opcode,
+ hdr->token);
+ }
+
+ rc = apr_tal_write(clnt->handle, buf,
+ (struct apr_pkt_priv *)&svc->pkt_owner,
+ hdr->pkt_size);
+ if (rc >= 0) {
+ w_len = rc;
+ if (w_len != hdr->pkt_size) {
+ pr_err("%s: Unable to write whole APR pkt successfully: %d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ }
+ } else {
+ pr_err("%s: Write APR pkt failed with error %d\n",
+ __func__, rc);
+ }
+ spin_unlock_irqrestore(&svc->w_lock, flags);
+
+ return rc;
+}
+
+int apr_pkt_config(void *handle, struct apr_pkt_cfg *cfg)
+{
+ struct apr_svc *svc = (struct apr_svc *)handle;
+ uint16_t dest_id;
+ uint16_t client_id;
+ struct apr_client *clnt;
+
+ if (!handle) {
+ pr_err("%s: Invalid handle\n", __func__);
+ return -EINVAL;
+ }
+
+ if (svc->need_reset) {
+ pr_err("%s: service need reset\n", __func__);
+ return -ENETRESET;
+ }
+
+ svc->pkt_owner = cfg->pkt_owner;
+ dest_id = svc->dest_id;
+ client_id = svc->client_id;
+ clnt = &client[dest_id][client_id];
+
+ return apr_tal_rx_intents_config(clnt->handle,
+ cfg->intents.num_of_intents, cfg->intents.size);
+}
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+ uint32_t src_port, void *priv)
+{
+ struct apr_client *clnt;
+ int client_id = 0;
+ int svc_idx = 0;
+ int svc_id = 0;
+ int dest_id = 0;
+ int domain_id = 0;
+ int temp_port = 0;
+ struct apr_svc *svc = NULL;
+ int rc = 0;
+ bool can_open_channel = true;
+
+ if (!dest || !svc_name || !svc_fn)
+ return NULL;
+
+ if (!strcmp(dest, "ADSP"))
+ domain_id = APR_DOMAIN_ADSP;
+ else if (!strcmp(dest, "MODEM")) {
+ /* Don't request for SMD channels if destination is MODEM,
+ * as these channels are no longer used and these clients
+ * are to listen only for MODEM SSR events
+ */
+ can_open_channel = false;
+ domain_id = APR_DOMAIN_MODEM;
+ } else {
+ pr_err("APR: wrong destination\n");
+ goto done;
+ }
+
+ dest_id = apr_get_dest_id(dest);
+
+ if (dest_id == APR_DEST_QDSP6) {
+ if (apr_get_q6_state() != APR_SUBSYS_LOADED) {
+ pr_err("%s: adsp not up\n", __func__);
+ return NULL;
+ }
+ pr_debug("%s: adsp Up\n", __func__);
+ } else if (dest_id == APR_DEST_MODEM) {
+ if (apr_get_modem_state() == APR_SUBSYS_DOWN) {
+ if (is_modem_up) {
+ pr_err("%s: modem shutdown due to SSR, ret",
+ __func__);
+ return NULL;
+ }
+ pr_debug("%s: Wait for modem to bootup\n", __func__);
+ rc = apr_wait_for_device_up(APR_DEST_MODEM);
+ if (rc == 0) {
+ pr_err("%s: Modem is not Up\n", __func__);
+ return NULL;
+ }
+ }
+ pr_debug("%s: modem Up\n", __func__);
+ }
+
+ if (apr_get_svc(svc_name, domain_id, &client_id, &svc_idx, &svc_id)) {
+ pr_err("%s: apr_get_svc failed\n", __func__);
+ goto done;
+ }
+
+ clnt = &client[dest_id][client_id];
+ mutex_lock(&clnt->m_lock);
+ if (!clnt->handle && can_open_channel) {
+ clnt->handle = apr_tal_open(client_id, dest_id,
+ APR_DL_SMD, apr_cb_func, NULL);
+ if (!clnt->handle) {
+ svc = NULL;
+ pr_err("APR: Unable to open handle\n");
+ mutex_unlock(&clnt->m_lock);
+ goto done;
+ }
+ }
+ mutex_unlock(&clnt->m_lock);
+ svc = &clnt->svc[svc_idx];
+ mutex_lock(&svc->m_lock);
+ clnt->id = client_id;
+ if (svc->need_reset) {
+ mutex_unlock(&svc->m_lock);
+ pr_err("APR: Service needs reset\n");
+ goto done;
+ }
+ svc->id = svc_id;
+ svc->dest_id = dest_id;
+ svc->client_id = client_id;
+ svc->dest_domain = domain_id;
+ svc->pkt_owner = APR_PKT_OWNER_DRIVER;
+
+ if (src_port != 0xFFFFFFFF) {
+ temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+ pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+ if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
+ pr_err("APR: temp_port out of bounds\n");
+ mutex_unlock(&svc->m_lock);
+ return NULL;
+ }
+ if (!svc->port_cnt && !svc->svc_cnt)
+ clnt->svc_cnt++;
+ svc->port_cnt++;
+ svc->port_fn[temp_port] = svc_fn;
+ svc->port_priv[temp_port] = priv;
+ } else {
+ if (!svc->fn) {
+ if (!svc->port_cnt && !svc->svc_cnt)
+ clnt->svc_cnt++;
+ svc->fn = svc_fn;
+ if (svc->port_cnt)
+ svc->svc_cnt++;
+ svc->priv = priv;
+ }
+ }
+
+ mutex_unlock(&svc->m_lock);
+done:
+ return svc;
+}
+
+
+void apr_cb_func(void *buf, int len, void *priv)
+{
+ struct apr_client_data data;
+ struct apr_client *apr_client;
+ struct apr_svc *c_svc;
+ struct apr_hdr *hdr;
+ uint16_t hdr_size;
+ uint16_t msg_type;
+ uint16_t ver;
+ uint16_t src;
+ uint16_t svc;
+ uint16_t clnt;
+ int i;
+ int temp_port = 0;
+ uint32_t *ptr;
+
+ pr_debug("APR2: len = %d\n", len);
+ ptr = buf;
+ pr_debug("\n*****************\n");
+ for (i = 0; i < len/4; i++)
+ pr_debug("%x ", ptr[i]);
+ pr_debug("\n");
+ pr_debug("\n*****************\n");
+
+ if (!buf || len <= APR_HDR_SIZE) {
+ pr_err("APR: Improper apr pkt received:%pK %d\n", buf, len);
+ return;
+ }
+ hdr = buf;
+
+ ver = hdr->hdr_field;
+ ver = (ver & 0x000F);
+ if (ver > APR_PKT_VER + 1) {
+ pr_err("APR: Wrong version: %d\n", ver);
+ return;
+ }
+
+ hdr_size = hdr->hdr_field;
+ hdr_size = ((hdr_size & 0x00F0) >> 0x4) * 4;
+ if (hdr_size < APR_HDR_SIZE) {
+ pr_err("APR: Wrong hdr size:%d\n", hdr_size);
+ return;
+ }
+
+ if (hdr->pkt_size < APR_HDR_SIZE) {
+ pr_err("APR: Wrong paket size\n");
+ return;
+ }
+ msg_type = hdr->hdr_field;
+ msg_type = (msg_type >> 0x08) & 0x0003;
+ if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) {
+ pr_err("APR: Wrong message type: %d\n", msg_type);
+ return;
+ }
+
+ if (hdr->src_domain >= APR_DOMAIN_MAX ||
+ hdr->dest_domain >= APR_DOMAIN_MAX ||
+ hdr->src_svc >= APR_SVC_MAX ||
+ hdr->dest_svc >= APR_SVC_MAX) {
+ pr_err("APR: Wrong APR header\n");
+ return;
+ }
+
+ svc = hdr->dest_svc;
+ if (hdr->src_domain == APR_DOMAIN_MODEM) {
+ if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
+ svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
+ svc == APR_SVC_TEST_CLIENT)
+ clnt = APR_CLIENT_VOICE;
+ else {
+ pr_err("APR: Wrong svc :%d\n", svc);
+ return;
+ }
+ } else if (hdr->src_domain == APR_DOMAIN_ADSP) {
+ if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
+ svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
+ svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
+ svc == APR_SVC_USM ||
+ svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
+ svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP ||
+ svc == APR_SVC_LSM)
+ clnt = APR_CLIENT_AUDIO;
+ else if (svc == APR_SVC_VIDC)
+ clnt = APR_CLIENT_AUDIO;
+ else {
+ pr_err("APR: Wrong svc :%d\n", svc);
+ return;
+ }
+ } else {
+ pr_err("APR: Pkt from wrong source: %d\n", hdr->src_domain);
+ return;
+ }
+
+ src = apr_get_data_src(hdr);
+ if (src == APR_DEST_MAX)
+ return;
+
+ pr_debug("src =%d clnt = %d\n", src, clnt);
+ apr_client = &client[src][clnt];
+ for (i = 0; i < APR_SVC_MAX; i++)
+ if (apr_client->svc[i].id == svc) {
+ pr_debug("%d\n", apr_client->svc[i].id);
+ c_svc = &apr_client->svc[i];
+ break;
+ }
+
+ if (i == APR_SVC_MAX) {
+ pr_err("APR: service is not registered\n");
+ return;
+ }
+ pr_debug("svc_idx = %d\n", i);
+ pr_debug("%x %x %x %pK %pK\n", c_svc->id, c_svc->dest_id,
+ c_svc->client_id, c_svc->fn, c_svc->priv);
+ data.payload_size = hdr->pkt_size - hdr_size;
+ data.opcode = hdr->opcode;
+ data.src = src;
+ data.src_port = hdr->src_port;
+ data.dest_port = hdr->dest_port;
+ data.token = hdr->token;
+ data.msg_type = msg_type;
+ data.payload = NULL;
+ if (data.payload_size > 0)
+ data.payload = (char *)hdr + hdr_size;
+
+ if (unlikely(apr_cf_debug)) {
+ if (hdr->opcode == APR_BASIC_RSP_RESULT && data.payload) {
+ uint32_t *ptr = data.payload;
+
+ APR_PKT_INFO(
+ "Rx: src_addr[0x%X] dest_addr[0x%X] opcode[0x%X] token[0x%X] rc[0x%X]",
+ (hdr->src_domain << 8) | hdr->src_svc,
+ (hdr->dest_domain << 8) | hdr->dest_svc,
+ hdr->opcode, hdr->token, ptr[1]);
+ } else {
+ APR_PKT_INFO(
+ "Rx: src_addr[0x%X] dest_addr[0x%X] opcode[0x%X] token[0x%X]",
+ (hdr->src_domain << 8) | hdr->src_svc,
+ (hdr->dest_domain << 8) | hdr->dest_svc, hdr->opcode,
+ hdr->token);
+ }
+ }
+
+ temp_port = ((data.dest_port >> 8) * 8) + (data.dest_port & 0xFF);
+ pr_debug("port = %d t_port = %d\n", data.src_port, temp_port);
+ if (c_svc->port_cnt && c_svc->port_fn[temp_port])
+ c_svc->port_fn[temp_port](&data, c_svc->port_priv[temp_port]);
+ else if (c_svc->fn)
+ c_svc->fn(&data, c_svc->priv);
+ else
+ pr_err("APR: Rxed a packet for NULL callback\n");
+}
+
+int apr_get_svc(const char *svc_name, int domain_id, int *client_id,
+ int *svc_idx, int *svc_id)
+{
+ int i;
+ int size;
+ struct apr_svc_table *tbl;
+ int ret = 0;
+
+ if (domain_id == APR_DOMAIN_ADSP) {
+ tbl = (struct apr_svc_table *)&svc_tbl_qdsp6;
+ size = ARRAY_SIZE(svc_tbl_qdsp6);
+ } else {
+ tbl = (struct apr_svc_table *)&svc_tbl_voice;
+ size = ARRAY_SIZE(svc_tbl_voice);
+ }
+
+ for (i = 0; i < size; i++) {
+ if (!strcmp(svc_name, tbl[i].name)) {
+ *client_id = tbl[i].client_id;
+ *svc_idx = tbl[i].idx;
+ *svc_id = tbl[i].id;
+ break;
+ }
+ }
+
+ pr_debug("%s: svc_name = %s c_id = %d domain_id = %d\n",
+ __func__, svc_name, *client_id, domain_id);
+ if (i == size) {
+ pr_err("%s: APR: Wrong svc name %s\n", __func__, svc_name);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void apr_reset_deregister(struct work_struct *work)
+{
+ struct apr_svc *handle = NULL;
+ struct apr_reset_work *apr_reset =
+ container_of(work, struct apr_reset_work, work);
+
+ handle = apr_reset->handle;
+ pr_debug("%s:handle[%pK]\n", __func__, handle);
+ apr_deregister(handle);
+ kfree(apr_reset);
+}
+
+int apr_deregister(void *handle)
+{
+ struct apr_svc *svc = handle;
+ struct apr_client *clnt;
+ uint16_t dest_id;
+ uint16_t client_id;
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&svc->m_lock);
+ dest_id = svc->dest_id;
+ client_id = svc->client_id;
+ clnt = &client[dest_id][client_id];
+
+ if (svc->port_cnt > 0 || svc->svc_cnt > 0) {
+ if (svc->port_cnt)
+ svc->port_cnt--;
+ else if (svc->svc_cnt)
+ svc->svc_cnt--;
+ if (!svc->port_cnt && !svc->svc_cnt) {
+ client[dest_id][client_id].svc_cnt--;
+ svc->need_reset = 0x0;
+ }
+ } else if (client[dest_id][client_id].svc_cnt > 0) {
+ client[dest_id][client_id].svc_cnt--;
+ if (!client[dest_id][client_id].svc_cnt) {
+ svc->need_reset = 0x0;
+ pr_debug("%s: service is reset %pK\n", __func__, svc);
+ }
+ }
+
+ if (!svc->port_cnt && !svc->svc_cnt) {
+ svc->priv = NULL;
+ svc->id = 0;
+ svc->fn = NULL;
+ svc->dest_id = 0;
+ svc->client_id = 0;
+ svc->need_reset = 0x0;
+ }
+ if (client[dest_id][client_id].handle &&
+ !client[dest_id][client_id].svc_cnt) {
+ apr_tal_close(client[dest_id][client_id].handle);
+ client[dest_id][client_id].handle = NULL;
+ }
+ mutex_unlock(&svc->m_lock);
+
+ return 0;
+}
+
+void apr_reset(void *handle)
+{
+ struct apr_reset_work *apr_reset_worker = NULL;
+
+ if (!handle)
+ return;
+ pr_debug("%s: handle[%pK]\n", __func__, handle);
+
+ if (apr_reset_workqueue == NULL) {
+ pr_err("%s: apr_reset_workqueue is NULL\n", __func__);
+ return;
+ }
+
+ apr_reset_worker = kzalloc(sizeof(struct apr_reset_work),
+ GFP_ATOMIC);
+
+ if (apr_reset_worker == NULL) {
+ pr_err("%s: mem failure\n", __func__);
+ return;
+ }
+
+ apr_reset_worker->handle = handle;
+ INIT_WORK(&apr_reset_worker->work, apr_reset_deregister);
+ queue_work(apr_reset_workqueue, &apr_reset_worker->work);
+}
+
+/* Dispatch the Reset events to Modem and audio clients */
+static void dispatch_event(unsigned long code, uint16_t proc)
+{
+ struct apr_client *apr_client;
+ struct apr_client_data data;
+ struct apr_svc *svc;
+ uint16_t clnt;
+ int i, j;
+
+ data.opcode = RESET_EVENTS;
+ data.reset_event = code;
+
+ /* Service domain can be different from the processor */
+ data.reset_proc = apr_get_reset_domain(proc);
+
+ clnt = APR_CLIENT_AUDIO;
+ apr_client = &client[proc][clnt];
+ for (i = 0; i < APR_SVC_MAX; i++) {
+ mutex_lock(&apr_client->svc[i].m_lock);
+ if (apr_client->svc[i].fn) {
+ apr_client->svc[i].need_reset = 0x1;
+ apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
+ }
+ if (apr_client->svc[i].port_cnt) {
+ svc = &(apr_client->svc[i]);
+ svc->need_reset = 0x1;
+ for (j = 0; j < APR_MAX_PORTS; j++)
+ if (svc->port_fn[j])
+ svc->port_fn[j](&data,
+ svc->port_priv[j]);
+ }
+ mutex_unlock(&apr_client->svc[i].m_lock);
+ }
+
+ clnt = APR_CLIENT_VOICE;
+ apr_client = &client[proc][clnt];
+ for (i = 0; i < APR_SVC_MAX; i++) {
+ mutex_lock(&apr_client->svc[i].m_lock);
+ if (apr_client->svc[i].fn) {
+ apr_client->svc[i].need_reset = 0x1;
+ apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
+ }
+ if (apr_client->svc[i].port_cnt) {
+ svc = &(apr_client->svc[i]);
+ svc->need_reset = 0x1;
+ for (j = 0; j < APR_MAX_PORTS; j++)
+ if (svc->port_fn[j])
+ svc->port_fn[j](&data,
+ svc->port_priv[j]);
+ }
+ mutex_unlock(&apr_client->svc[i].m_lock);
+ }
+}
+
+static int apr_notifier_service_cb(struct notifier_block *this,
+ unsigned long opcode, void *data)
+{
+ struct audio_notifier_cb_data *cb_data = data;
+
+ if (cb_data == NULL) {
+ pr_err("%s: Callback data is NULL!\n", __func__);
+ goto done;
+ }
+
+ pr_debug("%s: Service opcode 0x%lx, domain %d\n",
+ __func__, opcode, cb_data->domain);
+
+ switch (opcode) {
+ case AUDIO_NOTIFIER_SERVICE_DOWN:
+ /*
+ * Use flag to ignore down notifications during
+ * initial boot. There is no benefit from error
+ * recovery notifications during initial boot
+ * up since everything is expected to be down.
+ */
+ if (is_initial_boot)
+ break;
+ if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN)
+ apr_modem_down(opcode);
+ else
+ apr_adsp_down(opcode);
+ break;
+ case AUDIO_NOTIFIER_SERVICE_UP:
+ is_initial_boot = false;
+ if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN)
+ apr_modem_up();
+ else
+ apr_adsp_up();
+ break;
+ default:
+ break;
+ }
+done:
+ return NOTIFY_OK;
+}
+
+static struct notifier_block service_nb = {
+ .notifier_call = apr_notifier_service_cb,
+ .priority = 0,
+};
+
+static int __init apr_init(void)
+{
+ int i, j, k;
+
+ for (i = 0; i < APR_DEST_MAX; i++)
+ for (j = 0; j < APR_CLIENT_MAX; j++) {
+ mutex_init(&client[i][j].m_lock);
+ for (k = 0; k < APR_SVC_MAX; k++) {
+ mutex_init(&client[i][j].svc[k].m_lock);
+ spin_lock_init(&client[i][j].svc[k].w_lock);
+ }
+ }
+ apr_set_subsys_state();
+ mutex_init(&q6.lock);
+ apr_reset_workqueue = create_singlethread_workqueue("apr_driver");
+ if (!apr_reset_workqueue)
+ return -ENOMEM;
+
+ apr_pkt_ctx = ipc_log_context_create(APR_PKT_IPC_LOG_PAGE_CNT,
+ "apr", 0);
+ if (!apr_pkt_ctx)
+ pr_err("%s: Unable to create ipc log context\n", __func__);
+
+ is_initial_boot = true;
+ subsys_notif_register("apr_adsp", AUDIO_NOTIFIER_ADSP_DOMAIN,
+ &service_nb);
+ subsys_notif_register("apr_modem", AUDIO_NOTIFIER_MODEM_DOMAIN,
+ &service_nb);
+
+ return 0;
+}
+device_initcall(apr_init);
+
+static int __init apr_late_init(void)
+{
+ int ret = 0;
+
+ init_waitqueue_head(&dsp_wait);
+ init_waitqueue_head(&modem_wait);
+
+ return ret;
+}
+late_initcall(apr_late_init);
+
+#ifdef CONFIG_DEBUG_FS
+static int __init apr_debug_init(void)
+{
+ debugfs_apr_debug = debugfs_create_file("msm_apr_debug",
+ S_IFREG | 0444, NULL, NULL,
+ &apr_debug_ops);
+ return 0;
+}
+device_initcall(apr_debug_init);
+#endif
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal.c b/drivers/soc/qcom/qdsp6v2/apr_tal.c
new file mode 100644
index 0000000..5c296f66
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal.c
@@ -0,0 +1,298 @@
+/* Copyright (c) 2010-2011, 2013-2014, 2016-2017 The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <soc/qcom/smd.h>
+#include <linux/qdsp6v2/apr_tal.h>
+
+static char *svc_names[APR_DEST_MAX][APR_CLIENT_MAX] = {
+ {
+ "apr_audio_svc",
+ "apr_voice_svc",
+ },
+ {
+ "apr_audio_svc",
+ "apr_voice_svc",
+ },
+};
+
+struct apr_svc_ch_dev apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
+
+int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
+ struct apr_pkt_priv *pkt_priv, int len)
+{
+ int w_len;
+ unsigned long flags;
+
+ spin_lock_irqsave(&apr_ch->w_lock, flags);
+ if (smd_write_avail(apr_ch->ch) < len) {
+ spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+ return -EAGAIN;
+ }
+
+ w_len = smd_write(apr_ch->ch, data, len);
+ spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+
+ pr_debug("apr_tal:w_len = %d\n", w_len);
+
+ if (w_len != len) {
+ pr_err("apr_tal: Error in write\n");
+ return -ENETRESET;
+ }
+ return w_len;
+}
+
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
+ struct apr_pkt_priv *pkt_priv, int len)
+{
+ int rc = 0, retries = 0;
+
+ if (!apr_ch->ch)
+ return -EINVAL;
+
+ do {
+ if (rc == -EAGAIN)
+ udelay(50);
+
+ rc = __apr_tal_write(apr_ch, data, pkt_priv, len);
+ } while (rc == -EAGAIN && retries++ < 300);
+
+ if (rc == -EAGAIN)
+ pr_err("apr_tal: TIMEOUT for write\n");
+
+ return rc;
+}
+
+static void apr_tal_notify(void *priv, unsigned int event)
+{
+ struct apr_svc_ch_dev *apr_ch = priv;
+ int len, r_len, sz;
+ int pkt_cnt = 0;
+ unsigned long flags;
+
+ pr_debug("event = %d\n", event);
+ switch (event) {
+ case SMD_EVENT_DATA:
+ pkt_cnt = 0;
+ spin_lock_irqsave(&apr_ch->lock, flags);
+check_pending:
+ len = smd_read_avail(apr_ch->ch);
+ if (len < 0) {
+ pr_err("apr_tal: Invalid Read Event :%d\n", len);
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ return;
+ }
+ sz = smd_cur_packet_size(apr_ch->ch);
+ if (sz < 0) {
+ pr_debug("pkt size is zero\n");
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ return;
+ }
+ if (!len && !sz && !pkt_cnt)
+ goto check_write_avail;
+ if (!len) {
+ pr_debug("len = %d pkt_cnt = %d\n", len, pkt_cnt);
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ return;
+ }
+ r_len = smd_read_from_cb(apr_ch->ch, apr_ch->data, len);
+ if (len != r_len) {
+ pr_err("apr_tal: Invalid Read\n");
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ return;
+ }
+ pkt_cnt++;
+ pr_debug("%d %d %d\n", len, sz, pkt_cnt);
+ if (apr_ch->func)
+ apr_ch->func(apr_ch->data, r_len, apr_ch->priv);
+ goto check_pending;
+check_write_avail:
+ if (smd_write_avail(apr_ch->ch))
+ wake_up(&apr_ch->wait);
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ break;
+ case SMD_EVENT_OPEN:
+ pr_debug("apr_tal: SMD_EVENT_OPEN\n");
+ apr_ch->smd_state = 1;
+ wake_up(&apr_ch->wait);
+ break;
+ case SMD_EVENT_CLOSE:
+ pr_debug("apr_tal: SMD_EVENT_CLOSE\n");
+ break;
+ }
+}
+
+int apr_tal_rx_intents_config(struct apr_svc_ch_dev *apr_ch,
+ int num_of_intents, uint32_t size)
+{
+ /* Rx intents configuration is required for Glink
+ * but not for SMD. No-op for this function.
+ */
+ return 0;
+}
+
+struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest,
+ uint32_t dl, apr_svc_cb_fn func, void *priv)
+{
+ int rc;
+
+ if ((clnt >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
+ (dl >= APR_DL_MAX)) {
+ pr_err("apr_tal: Invalid params\n");
+ return NULL;
+ }
+
+ if (apr_svc_ch[dl][dest][clnt].ch) {
+ pr_err("apr_tal: This channel alreday openend\n");
+ return NULL;
+ }
+
+ mutex_lock(&apr_svc_ch[dl][dest][clnt].m_lock);
+ if (!apr_svc_ch[dl][dest][clnt].dest_state) {
+ rc = wait_event_timeout(apr_svc_ch[dl][dest][clnt].dest,
+ apr_svc_ch[dl][dest][clnt].dest_state,
+ msecs_to_jiffies(APR_OPEN_TIMEOUT_MS));
+ if (rc == 0) {
+ pr_err("apr_tal:open timeout\n");
+ mutex_unlock(&apr_svc_ch[dl][dest][clnt].m_lock);
+ return NULL;
+ }
+ pr_debug("apr_tal:Wakeup done\n");
+ apr_svc_ch[dl][dest][clnt].dest_state = 0;
+ }
+ rc = smd_named_open_on_edge(svc_names[dest][clnt], dest,
+ &apr_svc_ch[dl][dest][clnt].ch,
+ &apr_svc_ch[dl][dest][clnt],
+ apr_tal_notify);
+ if (rc < 0) {
+ pr_err("apr_tal: smd_open failed %s\n",
+ svc_names[dest][clnt]);
+ mutex_unlock(&apr_svc_ch[dl][dest][clnt].m_lock);
+ return NULL;
+ }
+ rc = wait_event_timeout(apr_svc_ch[dl][dest][clnt].wait,
+ (apr_svc_ch[dl][dest][clnt].smd_state == 1), 5 * HZ);
+ if (rc == 0) {
+ pr_err("apr_tal:TIMEOUT for OPEN event\n");
+ mutex_unlock(&apr_svc_ch[dl][dest][clnt].m_lock);
+ apr_tal_close(&apr_svc_ch[dl][dest][clnt]);
+ return NULL;
+ }
+
+ smd_disable_read_intr(apr_svc_ch[dl][dest][clnt].ch);
+
+ if (!apr_svc_ch[dl][dest][clnt].dest_state) {
+ apr_svc_ch[dl][dest][clnt].dest_state = 1;
+ pr_debug("apr_tal:Waiting for apr svc init\n");
+ msleep(200);
+ pr_debug("apr_tal:apr svc init done\n");
+ }
+ apr_svc_ch[dl][dest][clnt].smd_state = 0;
+
+ apr_svc_ch[dl][dest][clnt].func = func;
+ apr_svc_ch[dl][dest][clnt].priv = priv;
+ mutex_unlock(&apr_svc_ch[dl][dest][clnt].m_lock);
+
+ return &apr_svc_ch[dl][dest][clnt];
+}
+
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
+{
+ int r;
+
+ if (!apr_ch->ch)
+ return -EINVAL;
+
+ mutex_lock(&apr_ch->m_lock);
+ r = smd_close(apr_ch->ch);
+ apr_ch->ch = NULL;
+ apr_ch->func = NULL;
+ apr_ch->priv = NULL;
+ mutex_unlock(&apr_ch->m_lock);
+ return r;
+}
+
+static int apr_smd_probe(struct platform_device *pdev)
+{
+ int dest;
+ int clnt;
+
+ if (pdev->id == APR_DEST_MODEM) {
+ pr_info("apr_tal:Modem Is Up\n");
+ dest = APR_DEST_MODEM;
+ if (!strcmp(pdev->name, "apr_audio_svc"))
+ clnt = APR_CLIENT_AUDIO;
+ else
+ clnt = APR_CLIENT_VOICE;
+ apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+ wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+ } else if (pdev->id == APR_DEST_QDSP6) {
+ pr_info("apr_tal:Q6 Is Up\n");
+ dest = APR_DEST_QDSP6;
+ clnt = APR_CLIENT_AUDIO;
+ apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+ wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+ } else
+ pr_err("apr_tal:Invalid Dest Id: %d\n", pdev->id);
+
+ return 0;
+}
+
+static struct platform_driver apr_q6_driver = {
+ .probe = apr_smd_probe,
+ .driver = {
+ .name = "apr_audio_svc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct platform_driver apr_modem_driver = {
+ .probe = apr_smd_probe,
+ .driver = {
+ .name = "apr_voice_svc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init apr_tal_init(void)
+{
+ int i, j, k;
+
+ for (i = 0; i < APR_DL_MAX; i++)
+ for (j = 0; j < APR_DEST_MAX; j++)
+ for (k = 0; k < APR_CLIENT_MAX; k++) {
+ init_waitqueue_head(&apr_svc_ch[i][j][k].wait);
+ init_waitqueue_head(&apr_svc_ch[i][j][k].dest);
+ spin_lock_init(&apr_svc_ch[i][j][k].lock);
+ spin_lock_init(&apr_svc_ch[i][j][k].w_lock);
+ mutex_init(&apr_svc_ch[i][j][k].m_lock);
+ }
+ platform_driver_register(&apr_q6_driver);
+ platform_driver_register(&apr_modem_driver);
+ return 0;
+}
+device_initcall(apr_tal_init);
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
new file mode 100644
index 0000000..b32ed9e
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -0,0 +1,514 @@
+/* Copyright (c) 2016-2017 The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <soc/qcom/smd.h>
+#include <soc/qcom/glink.h>
+#include <linux/qdsp6v2/apr_tal.h>
+
+#define APR_MAXIMUM_NUM_OF_RETRIES 2
+
+struct apr_tx_buf {
+ struct list_head list;
+ struct apr_pkt_priv pkt_priv;
+ char buf[APR_MAX_BUF];
+};
+
+struct apr_buf_list {
+ struct list_head list;
+ spinlock_t lock;
+};
+
+struct link_state {
+ uint32_t dest;
+ void *handle;
+ enum glink_link_state link_state;
+ wait_queue_head_t wait;
+};
+
+static struct link_state link_state[APR_DEST_MAX];
+static struct apr_buf_list buf_list;
+
+static char *svc_names[APR_DEST_MAX][APR_CLIENT_MAX] = {
+ {
+ "apr_audio_svc",
+ "apr_voice_svc",
+ },
+ {
+ "apr_audio_svc",
+ "apr_voice_svc",
+ },
+};
+
+static struct apr_svc_ch_dev
+ apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
+
+static struct apr_tx_buf *apr_get_free_buf(int len)
+{
+ struct apr_tx_buf *tx_buf;
+ unsigned long flags;
+
+ if (len > APR_MAX_BUF) {
+ pr_err("%s: buf too large [%d]\n", __func__, len);
+ return ERR_PTR(-EINVAL);
+ }
+
+ spin_lock_irqsave(&buf_list.lock, flags);
+ if (list_empty(&buf_list.list)) {
+ spin_unlock_irqrestore(&buf_list.lock, flags);
+ pr_err("%s: No buf available\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ tx_buf = list_first_entry(&buf_list.list, struct apr_tx_buf, list);
+ list_del(&tx_buf->list);
+ spin_unlock_irqrestore(&buf_list.lock, flags);
+
+ return tx_buf;
+}
+
+static void apr_buf_add_tail(const void *buf)
+{
+ struct apr_tx_buf *list;
+ unsigned long flags;
+
+ if (!buf)
+ return;
+
+ spin_lock_irqsave(&buf_list.lock, flags);
+ list = container_of((void *)buf, struct apr_tx_buf, buf);
+ list_add_tail(&list->list, &buf_list.list);
+ spin_unlock_irqrestore(&buf_list.lock, flags);
+}
+
+static int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
+ struct apr_pkt_priv *pkt_priv, int len)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&apr_ch->w_lock, flags);
+ rc = glink_tx(apr_ch->handle, pkt_priv, data, len,
+ GLINK_TX_REQ_INTENT | GLINK_TX_ATOMIC);
+ spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+
+ if (rc)
+ pr_err("%s: glink_tx failed, rc[%d]\n", __func__, rc);
+ else
+ rc = len;
+
+ return rc;
+}
+
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
+ struct apr_pkt_priv *pkt_priv, int len)
+{
+ int rc = 0, retries = 0;
+ void *pkt_data = NULL;
+ struct apr_tx_buf *tx_buf;
+ struct apr_pkt_priv *pkt_priv_ptr = pkt_priv;
+
+ if (!apr_ch->handle || !pkt_priv)
+ return -EINVAL;
+
+ if (pkt_priv->pkt_owner == APR_PKT_OWNER_DRIVER) {
+ tx_buf = apr_get_free_buf(len);
+ if (IS_ERR_OR_NULL(tx_buf)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ memcpy(tx_buf->buf, data, len);
+ memcpy(&tx_buf->pkt_priv, pkt_priv, sizeof(tx_buf->pkt_priv));
+ pkt_priv_ptr = &tx_buf->pkt_priv;
+ pkt_data = tx_buf->buf;
+ } else {
+ pkt_data = data;
+ }
+
+ do {
+ if (rc == -EAGAIN)
+ udelay(50);
+
+ rc = __apr_tal_write(apr_ch, pkt_data, pkt_priv_ptr, len);
+ } while (rc == -EAGAIN && retries++ < APR_MAXIMUM_NUM_OF_RETRIES);
+
+ if (rc < 0) {
+ pr_err("%s: Unable to send the packet, rc:%d\n", __func__, rc);
+ if (pkt_priv->pkt_owner == APR_PKT_OWNER_DRIVER)
+ apr_buf_add_tail(pkt_data);
+ }
+exit:
+ return rc;
+}
+
+void apr_tal_notify_rx(void *handle, const void *priv, const void *pkt_priv,
+ const void *ptr, size_t size)
+{
+ struct apr_svc_ch_dev *apr_ch = (struct apr_svc_ch_dev *)priv;
+ unsigned long flags;
+
+ if (!apr_ch || !ptr) {
+ pr_err("%s: Invalid apr_ch or ptr\n", __func__);
+ return;
+ }
+
+ pr_debug("%s: Rx packet received\n", __func__);
+
+ spin_lock_irqsave(&apr_ch->r_lock, flags);
+ if (apr_ch->func)
+ apr_ch->func((void *)ptr, size, (void *)pkt_priv);
+ spin_unlock_irqrestore(&apr_ch->r_lock, flags);
+ glink_rx_done(apr_ch->handle, ptr, true);
+}
+
+static void apr_tal_notify_tx_abort(void *handle, const void *priv,
+ const void *pkt_priv)
+{
+ struct apr_pkt_priv *apr_pkt_priv_ptr =
+ (struct apr_pkt_priv *)pkt_priv;
+ struct apr_tx_buf *list_node;
+
+ if (!apr_pkt_priv_ptr) {
+ pr_err("%s: Invalid pkt_priv\n", __func__);
+ return;
+ }
+
+ pr_debug("%s: tx_abort received for apr_pkt_priv_ptr:%pK\n",
+ __func__, apr_pkt_priv_ptr);
+
+ if (apr_pkt_priv_ptr->pkt_owner == APR_PKT_OWNER_DRIVER) {
+ list_node = container_of(apr_pkt_priv_ptr,
+ struct apr_tx_buf, pkt_priv);
+ apr_buf_add_tail(list_node->buf);
+ }
+}
+
+void apr_tal_notify_tx_done(void *handle, const void *priv,
+ const void *pkt_priv, const void *ptr)
+{
+ struct apr_pkt_priv *apr_pkt_priv = (struct apr_pkt_priv *)pkt_priv;
+
+ if (!pkt_priv || !ptr) {
+ pr_err("%s: Invalid pkt_priv or ptr\n", __func__);
+ return;
+ }
+
+ pr_debug("%s: tx_done received\n", __func__);
+
+ if (apr_pkt_priv->pkt_owner == APR_PKT_OWNER_DRIVER)
+ apr_buf_add_tail(ptr);
+}
+
+bool apr_tal_notify_rx_intent_req(void *handle, const void *priv,
+ size_t req_size)
+{
+ struct apr_svc_ch_dev *apr_ch = (struct apr_svc_ch_dev *)priv;
+
+ if (!apr_ch) {
+ pr_err("%s: Invalid apr_ch\n", __func__);
+ return false;
+ }
+
+ pr_err("%s: No rx intents queued, unable to receive\n", __func__);
+ return false;
+}
+
+static void apr_tal_notify_remote_rx_intent(void *handle, const void *priv,
+ size_t size)
+{
+ struct apr_svc_ch_dev *apr_ch = (struct apr_svc_ch_dev *)priv;
+
+ if (!apr_ch) {
+ pr_err("%s: Invalid apr_ch\n", __func__);
+ return;
+ }
+ /*
+ * This is to make sure that the far end has queued at least one intent
+ * before we attmpt any IPC. A simple bool flag is used here instead of
+ * a counter, as the far end is required to guarantee intent
+ * availability for all use cases once the channel is fully opened.
+ */
+ pr_debug("%s: remote queued an intent\n", __func__);
+ apr_ch->if_remote_intent_ready = true;
+}
+
+void apr_tal_notify_state(void *handle, const void *priv, unsigned int event)
+{
+ struct apr_svc_ch_dev *apr_ch = (struct apr_svc_ch_dev *)priv;
+
+ if (!apr_ch) {
+ pr_err("%s: Invalid apr_ch\n", __func__);
+ return;
+ }
+
+ apr_ch->channel_state = event;
+ pr_info("%s: Channel state[%d]\n", __func__, event);
+
+ if (event == GLINK_CONNECTED)
+ wake_up(&apr_ch->wait);
+}
+
+int apr_tal_rx_intents_config(struct apr_svc_ch_dev *apr_ch,
+ int num_of_intents, uint32_t size)
+{
+ int i;
+ int rc;
+
+ if (!apr_ch || !num_of_intents || !size) {
+ pr_err("%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_of_intents; i++) {
+ rc = glink_queue_rx_intent(apr_ch->handle, apr_ch, size);
+ if (rc) {
+ pr_err("%s: Failed to queue rx intent, iteration[%d]\n",
+ __func__, i);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest, uint32_t dl,
+ apr_svc_cb_fn func, void *priv)
+{
+ int rc;
+ struct glink_open_config open_cfg;
+ struct apr_svc_ch_dev *apr_ch;
+
+ if ((clnt >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
+ (dl >= APR_DL_MAX)) {
+ pr_err("%s: Invalid params, clnt:%d, dest:%d, dl:%d\n",
+ __func__, clnt, dest, dl);
+ return NULL;
+ }
+
+ apr_ch = &apr_svc_ch[dl][dest][clnt];
+ mutex_lock(&apr_ch->m_lock);
+ if (apr_ch->handle) {
+ pr_err("%s: This channel is already opened\n", __func__);
+ rc = -EBUSY;
+ goto unlock;
+ }
+
+ if (link_state[dest].link_state != GLINK_LINK_STATE_UP) {
+ rc = wait_event_timeout(link_state[dest].wait,
+ link_state[dest].link_state == GLINK_LINK_STATE_UP,
+ msecs_to_jiffies(APR_OPEN_TIMEOUT_MS));
+ if (rc == 0) {
+ pr_err("%s: Open timeout, dest:%d\n", __func__, dest);
+ rc = -ETIMEDOUT;
+ goto unlock;
+ }
+ pr_debug("%s: Wakeup done, dest:%d\n", __func__, dest);
+ }
+
+ memset(&open_cfg, 0, sizeof(struct glink_open_config));
+ open_cfg.options = GLINK_OPT_INITIAL_XPORT;
+ if (dest == APR_DEST_MODEM)
+ open_cfg.edge = "mpss";
+ else
+ open_cfg.edge = "lpass";
+
+ open_cfg.name = svc_names[dest][clnt];
+ open_cfg.notify_rx = apr_tal_notify_rx;
+ open_cfg.notify_tx_done = apr_tal_notify_tx_done;
+ open_cfg.notify_state = apr_tal_notify_state;
+ open_cfg.notify_rx_intent_req = apr_tal_notify_rx_intent_req;
+ open_cfg.notify_remote_rx_intent = apr_tal_notify_remote_rx_intent;
+ open_cfg.notify_tx_abort = apr_tal_notify_tx_abort;
+ open_cfg.priv = apr_ch;
+ open_cfg.transport = "smem";
+
+ apr_ch->channel_state = GLINK_REMOTE_DISCONNECTED;
+ apr_ch->handle = glink_open(&open_cfg);
+ if (IS_ERR_OR_NULL(apr_ch->handle)) {
+ pr_err("%s: glink_open failed %s\n", __func__,
+ svc_names[dest][clnt]);
+ apr_ch->handle = NULL;
+ rc = -EINVAL;
+ goto unlock;
+ }
+
+ rc = wait_event_timeout(apr_ch->wait,
+ (apr_ch->channel_state == GLINK_CONNECTED), 5 * HZ);
+ if (rc == 0) {
+ pr_err("%s: TIMEOUT for OPEN event\n", __func__);
+ rc = -ETIMEDOUT;
+ goto close_link;
+ }
+
+ /*
+ * Remote intent is not required for GLINK <--> SMD IPC, so this is
+ * designed not to fail the open call.
+ */
+ rc = wait_event_timeout(apr_ch->wait,
+ apr_ch->if_remote_intent_ready, 5 * HZ);
+ if (rc == 0)
+ pr_err("%s: TIMEOUT for remote intent readiness\n", __func__);
+
+ rc = apr_tal_rx_intents_config(apr_ch, APR_DEFAULT_NUM_OF_INTENTS,
+ APR_MAX_BUF);
+ if (rc) {
+ pr_err("%s: Unable to queue intents\n", __func__);
+ goto close_link;
+ }
+
+ apr_ch->func = func;
+ apr_ch->priv = priv;
+
+close_link:
+ if (rc) {
+ glink_close(apr_ch->handle);
+ apr_ch->handle = NULL;
+ }
+unlock:
+ mutex_unlock(&apr_ch->m_lock);
+
+ return rc ? NULL : apr_ch;
+}
+
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
+{
+ int rc;
+
+ if (!apr_ch || !apr_ch->handle) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ mutex_lock(&apr_ch->m_lock);
+ rc = glink_close(apr_ch->handle);
+ apr_ch->handle = NULL;
+ apr_ch->func = NULL;
+ apr_ch->priv = NULL;
+ apr_ch->if_remote_intent_ready = false;
+ mutex_unlock(&apr_ch->m_lock);
+exit:
+ return rc;
+}
+
+static void apr_tal_link_state_cb(struct glink_link_state_cb_info *cb_info,
+ void *priv)
+{
+ uint32_t dest;
+
+ if (!cb_info) {
+ pr_err("%s: Invalid cb_info\n", __func__);
+ return;
+ }
+
+ if (!strcmp(cb_info->edge, "mpss"))
+ dest = APR_DEST_MODEM;
+ else if (!strcmp(cb_info->edge, "lpass"))
+ dest = APR_DEST_QDSP6;
+ else {
+ pr_err("%s:Unknown edge[%s]\n", __func__, cb_info->edge);
+ return;
+ }
+
+ pr_info("%s: edge[%s] link state[%d]\n", __func__, cb_info->edge,
+ cb_info->link_state);
+
+ link_state[dest].link_state = cb_info->link_state;
+ if (link_state[dest].link_state == GLINK_LINK_STATE_UP)
+ wake_up(&link_state[dest].wait);
+}
+
+static struct glink_link_info mpss_link_info = {
+ .transport = "smem",
+ .edge = "mpss",
+ .glink_link_state_notif_cb = apr_tal_link_state_cb,
+};
+
+static struct glink_link_info lpass_link_info = {
+ .transport = "smem",
+ .edge = "lpass",
+ .glink_link_state_notif_cb = apr_tal_link_state_cb,
+};
+
+static int __init apr_tal_init(void)
+{
+ int i, j, k;
+ struct apr_tx_buf *buf;
+ struct list_head *ptr, *next;
+
+ for (i = 0; i < APR_DL_MAX; i++) {
+ for (j = 0; j < APR_DEST_MAX; j++) {
+ for (k = 0; k < APR_CLIENT_MAX; k++) {
+ init_waitqueue_head(&apr_svc_ch[i][j][k].wait);
+ spin_lock_init(&apr_svc_ch[i][j][k].w_lock);
+ spin_lock_init(&apr_svc_ch[i][j][k].r_lock);
+ mutex_init(&apr_svc_ch[i][j][k].m_lock);
+ }
+ }
+ }
+
+ for (i = 0; i < APR_DEST_MAX; i++)
+ init_waitqueue_head(&link_state[i].wait);
+
+ spin_lock_init(&buf_list.lock);
+ INIT_LIST_HEAD(&buf_list.list);
+ for (i = 0; i < APR_NUM_OF_TX_BUF; i++) {
+ buf = kzalloc(sizeof(struct apr_tx_buf), GFP_KERNEL);
+ if (!buf) {
+ pr_err("%s: Unable to allocate tx buf\n", __func__);
+ goto tx_buf_alloc_fail;
+ }
+
+ INIT_LIST_HEAD(&buf->list);
+ spin_lock(&buf_list.lock);
+ list_add_tail(&buf->list, &buf_list.list);
+ spin_unlock(&buf_list.lock);
+ }
+
+ link_state[APR_DEST_MODEM].link_state = GLINK_LINK_STATE_DOWN;
+ link_state[APR_DEST_MODEM].handle =
+ glink_register_link_state_cb(&mpss_link_info, NULL);
+ if (!link_state[APR_DEST_MODEM].handle)
+ pr_err("%s: Unable to register mpss link state\n", __func__);
+
+ link_state[APR_DEST_QDSP6].link_state = GLINK_LINK_STATE_DOWN;
+ link_state[APR_DEST_QDSP6].handle =
+ glink_register_link_state_cb(&lpass_link_info, NULL);
+ if (!link_state[APR_DEST_QDSP6].handle)
+ pr_err("%s: Unable to register lpass link state\n", __func__);
+
+ return 0;
+
+tx_buf_alloc_fail:
+ list_for_each_safe(ptr, next, &buf_list.list) {
+ buf = list_entry(ptr, struct apr_tx_buf, list);
+ list_del(&buf->list);
+ kfree(buf);
+ }
+ return -ENOMEM;
+}
+device_initcall(apr_tal_init);
diff --git a/drivers/soc/qcom/qdsp6v2/apr_v2.c b/drivers/soc/qcom/qdsp6v2/apr_v2.c
new file mode 100644
index 0000000..4ddf39b
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/apr_v2.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/qdsp6v2/apr_tal.h>
+#include <linux/qdsp6v2/dsp_debug.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+
+enum apr_subsys_state apr_get_subsys_state(void)
+{
+ return apr_get_q6_state();
+}
+
+void apr_set_subsys_state(void)
+{
+ apr_set_q6_state(APR_SUBSYS_DOWN);
+ apr_set_modem_state(APR_SUBSYS_UP);
+}
+
+uint16_t apr_get_data_src(struct apr_hdr *hdr)
+{
+ if (hdr->src_domain == APR_DOMAIN_MODEM)
+ return APR_DEST_MODEM;
+ else if (hdr->src_domain == APR_DOMAIN_ADSP)
+ return APR_DEST_QDSP6;
+
+ pr_err("APR: Pkt from wrong source: %d\n", hdr->src_domain);
+ return APR_DEST_MAX; /*RETURN INVALID VALUE*/
+}
+
+int apr_get_dest_id(char *dest)
+{
+ if (!strcmp(dest, "ADSP"))
+ return APR_DEST_QDSP6;
+ else
+ return APR_DEST_MODEM;
+}
+
+void subsys_notif_register(char *client_name, int domain,
+ struct notifier_block *nb)
+{
+ int ret;
+
+ ret = audio_notifier_register(client_name, domain, nb);
+ if (ret < 0)
+ pr_err("%s: Audio notifier register failed for domain %d ret = %d\n",
+ __func__, domain, ret);
+}
+
+uint16_t apr_get_reset_domain(uint16_t proc)
+{
+ return proc;
+}
diff --git a/drivers/soc/qcom/qdsp6v2/apr_v3.c b/drivers/soc/qcom/qdsp6v2/apr_v3.c
new file mode 100644
index 0000000..2bfc518
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/apr_v3.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/qdsp6v2/apr_tal.h>
+#include <linux/qdsp6v2/dsp_debug.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+
+#define DEST_ID APR_DEST_MODEM
+
+enum apr_subsys_state apr_get_subsys_state(void)
+{
+ return apr_get_modem_state();
+}
+
+void apr_set_subsys_state(void)
+{
+ apr_set_modem_state(APR_SUBSYS_DOWN);
+}
+
+uint16_t apr_get_data_src(struct apr_hdr *hdr)
+{
+ return DEST_ID;
+}
+
+int apr_get_dest_id(char *dest)
+{
+ return DEST_ID;
+}
+
+void subsys_notif_register(char *client_name, int domain,
+ struct notifier_block *nb)
+{
+ int ret;
+
+ if (domain != AUDIO_NOTIFIER_MODEM_DOMAIN) {
+ pr_debug("%s: Unused domain %d not registering with notifier\n",
+ __func__, domain);
+ return;
+ }
+
+ ret = audio_notifier_register(client_name, domain, nb);
+ if (ret < 0)
+ pr_err("%s: Audio notifier register failed for domain %d ret = %d\n",
+ __func__, domain, ret);
+}
+
+uint16_t apr_get_reset_domain(uint16_t proc)
+{
+ return APR_DEST_QDSP6;
+}
diff --git a/drivers/soc/qcom/qdsp6v2/audio_notifier.c b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
new file mode 100644
index 0000000..9119e8b
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
@@ -0,0 +1,635 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/qdsp6v2/audio_pdr.h>
+#include <linux/qdsp6v2/audio_ssr.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/service-notifier.h>
+
+/* Audio states internal to notifier. Client */
+/* used states defined in audio_notifier.h */
+/* for AUDIO_NOTIFIER_SERVICE_DOWN & UP */
+#define NO_SERVICE -2
+#define UNINIT_SERVICE -1
+
+/*
+ * Used for each client registered with audio notifier
+ */
+struct client_data {
+ struct list_head list;
+ /* Notifier block given by client */
+ struct notifier_block *nb;
+ char client_name[20];
+ int service;
+ int domain;
+};
+
+/*
+ * Used for each service and domain combination
+ * Tracks information specific to the underlying
+ * service.
+ */
+struct service_info {
+ const char name[20];
+ int domain_id;
+ int state;
+ void *handle;
+ /* Notifier block registered to service */
+ struct notifier_block *nb;
+ /* Used to determine when to register and deregister service */
+ int num_of_clients;
+ /* List of all clients registered to the service and domain */
+ struct srcu_notifier_head client_nb_list;
+};
+
+static int audio_notifer_ssr_adsp_cb(struct notifier_block *this,
+ unsigned long opcode, void *data);
+static int audio_notifer_ssr_modem_cb(struct notifier_block *this,
+ unsigned long opcode, void *data);
+static int audio_notifer_pdr_adsp_cb(struct notifier_block *this,
+ unsigned long opcode, void *data);
+
+static struct notifier_block notifier_ssr_adsp_nb = {
+ .notifier_call = audio_notifer_ssr_adsp_cb,
+ .priority = 0,
+};
+
+static struct notifier_block notifier_ssr_modem_nb = {
+ .notifier_call = audio_notifer_ssr_modem_cb,
+ .priority = 0,
+};
+
+static struct notifier_block notifier_pdr_adsp_nb = {
+ .notifier_call = audio_notifer_pdr_adsp_cb,
+ .priority = 0,
+};
+
+static struct service_info service_data[AUDIO_NOTIFIER_MAX_SERVICES]
+ [AUDIO_NOTIFIER_MAX_DOMAINS] = {
+
+ {{
+ .name = "SSR_ADSP",
+ .domain_id = AUDIO_SSR_DOMAIN_ADSP,
+ .state = AUDIO_NOTIFIER_SERVICE_DOWN,
+ .nb = ¬ifier_ssr_adsp_nb
+ },
+ {
+ .name = "SSR_MODEM",
+ .domain_id = AUDIO_SSR_DOMAIN_MODEM,
+ .state = AUDIO_NOTIFIER_SERVICE_DOWN,
+ .nb = ¬ifier_ssr_modem_nb
+ } },
+
+ {{
+ .name = "PDR_ADSP",
+ .domain_id = AUDIO_PDR_DOMAIN_ADSP,
+ .state = UNINIT_SERVICE,
+ .nb = ¬ifier_pdr_adsp_nb
+ },
+ { /* PDR MODEM service not enabled */
+ .name = "INVALID",
+ .state = NO_SERVICE,
+ .nb = NULL
+ } }
+};
+
+/* Master list of all audio notifier clients */
+struct list_head client_list;
+struct mutex notifier_mutex;
+
+static int audio_notifer_get_default_service(int domain)
+{
+ int service = NO_SERVICE;
+
+ /* initial service to connect per domain */
+ switch (domain) {
+ case AUDIO_NOTIFIER_ADSP_DOMAIN:
+ service = AUDIO_NOTIFIER_PDR_SERVICE;
+ break;
+ case AUDIO_NOTIFIER_MODEM_DOMAIN:
+ service = AUDIO_NOTIFIER_SSR_SERVICE;
+ break;
+ }
+
+ return service;
+}
+
+static void audio_notifer_disable_service(int service)
+{
+ int i;
+
+ for (i = 0; i < AUDIO_NOTIFIER_MAX_DOMAINS; i++)
+ service_data[service][i].state = NO_SERVICE;
+}
+
+static bool audio_notifer_is_service_enabled(int service)
+{
+ int i;
+
+ for (i = 0; i < AUDIO_NOTIFIER_MAX_DOMAINS; i++)
+ if (service_data[service][i].state != NO_SERVICE)
+ return true;
+ return false;
+}
+
+static void audio_notifer_init_service(int service)
+{
+ int i;
+
+ for (i = 0; i < AUDIO_NOTIFIER_MAX_DOMAINS; i++) {
+ if (service_data[service][i].state == UNINIT_SERVICE)
+ service_data[service][i].state =
+ AUDIO_NOTIFIER_SERVICE_DOWN;
+ }
+}
+
+static int audio_notifer_reg_service(int service, int domain)
+{
+ void *handle;
+ int ret = 0;
+ int curr_state = AUDIO_NOTIFIER_SERVICE_DOWN;
+
+ switch (service) {
+ case AUDIO_NOTIFIER_SSR_SERVICE:
+ handle = audio_ssr_register(
+ service_data[service][domain].domain_id,
+ service_data[service][domain].nb);
+ break;
+ case AUDIO_NOTIFIER_PDR_SERVICE:
+ handle = audio_pdr_service_register(
+ service_data[service][domain].domain_id,
+ service_data[service][domain].nb, &curr_state);
+
+ if (curr_state == SERVREG_NOTIF_SERVICE_STATE_UP_V01)
+ curr_state = AUDIO_NOTIFIER_SERVICE_UP;
+ else
+ curr_state = AUDIO_NOTIFIER_SERVICE_DOWN;
+ break;
+ default:
+ pr_err("%s: Invalid service %d\n",
+ __func__, service);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: handle is incorrect for service %s\n",
+ __func__, service_data[service][domain].name);
+ ret = -EINVAL;
+ goto done;
+ }
+ service_data[service][domain].state = curr_state;
+ service_data[service][domain].handle = handle;
+
+ pr_info("%s: service %s is in use\n",
+ __func__, service_data[service][domain].name);
+ pr_debug("%s: service %s has current state %d, handle 0x%pK\n",
+ __func__, service_data[service][domain].name,
+ service_data[service][domain].state,
+ service_data[service][domain].handle);
+done:
+ return ret;
+}
+
+static int audio_notifer_dereg_service(int service, int domain)
+{
+ int ret;
+
+ switch (service) {
+ case AUDIO_NOTIFIER_SSR_SERVICE:
+ ret = audio_ssr_deregister(
+ service_data[service][domain].handle,
+ service_data[service][domain].nb);
+ break;
+ case AUDIO_NOTIFIER_PDR_SERVICE:
+ ret = audio_pdr_service_deregister(
+ service_data[service][domain].handle,
+ service_data[service][domain].nb);
+ break;
+ default:
+ pr_err("%s: Invalid service %d\n",
+ __func__, service);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: deregister failed for service %s, ret %d\n",
+ __func__, service_data[service][domain].name, ret);
+ goto done;
+ }
+
+ pr_debug("%s: service %s with handle 0x%pK deregistered\n",
+ __func__, service_data[service][domain].name,
+ service_data[service][domain].handle);
+
+ service_data[service][domain].state = AUDIO_NOTIFIER_SERVICE_DOWN;
+ service_data[service][domain].handle = NULL;
+done:
+ return ret;
+}
+
+static int audio_notifer_reg_client_service(struct client_data *client_data,
+ int service)
+{
+ int ret = 0;
+ int domain = client_data->domain;
+ struct audio_notifier_cb_data data;
+
+ switch (service) {
+ case AUDIO_NOTIFIER_SSR_SERVICE:
+ case AUDIO_NOTIFIER_PDR_SERVICE:
+ if (service_data[service][domain].num_of_clients == 0)
+ ret = audio_notifer_reg_service(service, domain);
+ break;
+ default:
+ pr_err("%s: Invalid service for client %s, service %d, domain %d\n",
+ __func__, client_data->client_name, service, domain);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: service registration failed on service %s for client %s\n",
+ __func__, service_data[service][domain].name,
+ client_data->client_name);
+ goto done;
+ }
+
+ client_data->service = service;
+ srcu_notifier_chain_register(
+ &service_data[service][domain].client_nb_list,
+ client_data->nb);
+ service_data[service][domain].num_of_clients++;
+
+ pr_debug("%s: registered client %s on service %s, current state 0x%x\n",
+ __func__, client_data->client_name,
+ service_data[service][domain].name,
+ service_data[service][domain].state);
+
+ /*
+ * PDR registration returns current state
+ * Force callback of client with current state for PDR
+ */
+ if (client_data->service == AUDIO_NOTIFIER_PDR_SERVICE) {
+ data.service = service;
+ data.domain = domain;
+ (void)client_data->nb->notifier_call(client_data->nb,
+ service_data[service][domain].state, &data);
+ }
+done:
+ return ret;
+}
+
+static int audio_notifer_reg_client(struct client_data *client_data)
+{
+ int ret = 0;
+ int service;
+ int domain = client_data->domain;
+
+ service = audio_notifer_get_default_service(domain);
+ if (service < 0) {
+ pr_err("%s: service %d is incorrect\n", __func__, service);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Search through services to find a valid one to register client on. */
+ for (; service >= 0; service--) {
+ /* If a service is not initialized, wait for it to come up. */
+ if (service_data[service][domain].state == UNINIT_SERVICE)
+ goto done;
+ /* Skip unsupported service and domain combinations. */
+ if (service_data[service][domain].state < 0)
+ continue;
+ /* Only register clients who have not acquired a service. */
+ if (client_data->service != NO_SERVICE)
+ continue;
+
+ /*
+ * Only register clients, who have not acquired a service, on
+ * the best available service for their domain. Uninitialized
+ * services will try to register all of their clients after
+ * they initialize correctly or will disable their service and
+ * register clients on the next best avaialable service.
+ */
+ pr_debug("%s: register client %s on service %s",
+ __func__, client_data->client_name,
+ service_data[service][domain].name);
+
+ ret = audio_notifer_reg_client_service(client_data, service);
+ if (IS_ERR_VALUE(ret))
+ pr_err("%s: client %s failed to register on service %s",
+ __func__, client_data->client_name,
+ service_data[service][domain].name);
+ }
+
+done:
+ return ret;
+}
+
+static int audio_notifer_dereg_client(struct client_data *client_data)
+{
+ int ret = 0;
+ int service = client_data->service;
+ int domain = client_data->domain;
+
+ switch (client_data->service) {
+ case AUDIO_NOTIFIER_SSR_SERVICE:
+ case AUDIO_NOTIFIER_PDR_SERVICE:
+ if (service_data[service][domain].num_of_clients == 1)
+ ret = audio_notifer_dereg_service(service, domain);
+ break;
+ case NO_SERVICE:
+ goto done;
+ default:
+ pr_err("%s: Invalid service for client %s, service %d\n",
+ __func__, client_data->client_name,
+ client_data->service);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: deregister failed for client %s on service %s, ret %d\n",
+ __func__, client_data->client_name,
+ service_data[service][domain].name, ret);
+ goto done;
+ }
+
+ ret = srcu_notifier_chain_unregister(&service_data[service][domain].
+ client_nb_list, client_data->nb);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: srcu_notifier_chain_unregister failed, ret %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ pr_debug("%s: deregistered client %s on service %s\n",
+ __func__, client_data->client_name,
+ service_data[service][domain].name);
+
+ client_data->service = NO_SERVICE;
+ if (service_data[service][domain].num_of_clients > 0)
+ service_data[service][domain].num_of_clients--;
+done:
+ return ret;
+}
+
+static void audio_notifer_reg_all_clients(void)
+{
+ struct list_head *ptr, *next;
+ struct client_data *client_data;
+ int ret;
+
+ list_for_each_safe(ptr, next, &client_list) {
+ client_data = list_entry(ptr,
+ struct client_data, list);
+ ret = audio_notifer_reg_client(client_data);
+ if (IS_ERR_VALUE(ret))
+ pr_err("%s: audio_notifer_reg_client failed for client %s, ret %d\n",
+ __func__, client_data->client_name,
+ ret);
+ }
+}
+
+static int audio_notifer_pdr_callback(struct notifier_block *this,
+ unsigned long opcode, void *data)
+{
+ pr_debug("%s: Audio PDR framework state 0x%lx\n",
+ __func__, opcode);
+ mutex_lock(¬ifier_mutex);
+ if (opcode == AUDIO_PDR_FRAMEWORK_DOWN)
+ audio_notifer_disable_service(AUDIO_NOTIFIER_PDR_SERVICE);
+ else
+ audio_notifer_init_service(AUDIO_NOTIFIER_PDR_SERVICE);
+
+ audio_notifer_reg_all_clients();
+ mutex_unlock(¬ifier_mutex);
+ return 0;
+}
+
+static struct notifier_block pdr_nb = {
+ .notifier_call = audio_notifer_pdr_callback,
+ .priority = 0,
+};
+
+static int audio_notifer_convert_opcode(unsigned long opcode,
+ unsigned long *notifier_opcode)
+{
+ int ret = 0;
+
+ switch (opcode) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01:
+ *notifier_opcode = AUDIO_NOTIFIER_SERVICE_DOWN;
+ break;
+ case SUBSYS_AFTER_POWERUP:
+ case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
+ *notifier_opcode = AUDIO_NOTIFIER_SERVICE_UP;
+ break;
+ default:
+ pr_debug("%s: Unused opcode 0x%lx\n", __func__, opcode);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int audio_notifer_service_cb(unsigned long opcode,
+ int service, int domain)
+{
+ int ret = 0;
+ unsigned long notifier_opcode;
+ struct audio_notifier_cb_data data;
+
+ if (audio_notifer_convert_opcode(opcode, ¬ifier_opcode) < 0)
+ goto done;
+
+ data.service = service;
+ data.domain = domain;
+
+ pr_debug("%s: service %s, opcode 0x%lx\n",
+ __func__, service_data[service][domain].name, notifier_opcode);
+
+ mutex_lock(¬ifier_mutex);
+
+ service_data[service][domain].state = notifier_opcode;
+ ret = srcu_notifier_call_chain(&service_data[service][domain].
+ client_nb_list, notifier_opcode, &data);
+ if (IS_ERR_VALUE(ret))
+ pr_err("%s: srcu_notifier_call_chain returned %d, service %s, opcode 0x%lx\n",
+ __func__, ret, service_data[service][domain].name,
+ notifier_opcode);
+
+ mutex_unlock(¬ifier_mutex);
+done:
+ return NOTIFY_OK;
+}
+
+static int audio_notifer_pdr_adsp_cb(struct notifier_block *this,
+ unsigned long opcode, void *data)
+{
+ return audio_notifer_service_cb(opcode,
+ AUDIO_NOTIFIER_PDR_SERVICE,
+ AUDIO_NOTIFIER_ADSP_DOMAIN);
+}
+
+static int audio_notifer_ssr_adsp_cb(struct notifier_block *this,
+ unsigned long opcode, void *data)
+{
+ if (opcode == SUBSYS_BEFORE_SHUTDOWN)
+ audio_ssr_send_nmi(data);
+
+ return audio_notifer_service_cb(opcode,
+ AUDIO_NOTIFIER_SSR_SERVICE,
+ AUDIO_NOTIFIER_ADSP_DOMAIN);
+}
+
+static int audio_notifer_ssr_modem_cb(struct notifier_block *this,
+ unsigned long opcode, void *data)
+{
+ return audio_notifer_service_cb(opcode,
+ AUDIO_NOTIFIER_SSR_SERVICE,
+ AUDIO_NOTIFIER_MODEM_DOMAIN);
+}
+
+int audio_notifier_deregister(char *client_name)
+{
+ int ret = 0;
+ int ret2;
+ struct list_head *ptr, *next;
+ struct client_data *client_data;
+
+ if (client_name == NULL) {
+ pr_err("%s: client_name is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ mutex_lock(¬ifier_mutex);
+ list_for_each_safe(ptr, next, &client_data->list) {
+ client_data = list_entry(ptr, struct client_data,
+ list);
+ if (!strcmp(client_name, client_data->client_name)) {
+ ret2 = audio_notifer_dereg_client(client_data);
+ if (ret2 < 0) {
+ pr_err("%s: audio_notifer_dereg_client failed, ret %d\n, service %d, domain %d",
+ __func__, ret2, client_data->service,
+ client_data->domain);
+ ret = ret2;
+ continue;
+ }
+ list_del(&client_data->list);
+ kfree(client_data);
+ }
+ }
+ mutex_unlock(¬ifier_mutex);
+done:
+ return ret;
+}
+EXPORT_SYMBOL(audio_notifier_deregister);
+
+int audio_notifier_register(char *client_name, int domain,
+ struct notifier_block *nb)
+{
+ int ret;
+ struct client_data *client_data;
+
+ if (client_name == NULL) {
+ pr_err("%s: client_name is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ } else if (nb == NULL) {
+ pr_err("%s: Notifier block is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ client_data = kmalloc(sizeof(*client_data), GFP_KERNEL);
+ if (client_data == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ INIT_LIST_HEAD(&client_data->list);
+ client_data->nb = nb;
+ strlcpy(client_data->client_name, client_name,
+ sizeof(client_data->client_name));
+ client_data->service = NO_SERVICE;
+ client_data->domain = domain;
+
+ mutex_lock(¬ifier_mutex);
+ ret = audio_notifer_reg_client(client_data);
+ if (IS_ERR_VALUE(ret)) {
+ mutex_unlock(¬ifier_mutex);
+ pr_err("%s: audio_notifer_reg_client for client %s failed ret = %d\n",
+ __func__, client_data->client_name,
+ ret);
+ kfree(client_data);
+ goto done;
+ }
+ list_add_tail(&client_data->list, &client_list);
+ mutex_unlock(¬ifier_mutex);
+done:
+ return ret;
+}
+EXPORT_SYMBOL(audio_notifier_register);
+
+static int __init audio_notifier_subsys_init(void)
+{
+ int i, j;
+
+ mutex_init(¬ifier_mutex);
+ INIT_LIST_HEAD(&client_list);
+ for (i = 0; i < AUDIO_NOTIFIER_MAX_SERVICES; i++) {
+ for (j = 0; j < AUDIO_NOTIFIER_MAX_DOMAINS; j++) {
+ if (service_data[i][j].state <= NO_SERVICE)
+ continue;
+
+ srcu_init_notifier_head(
+ &service_data[i][j].client_nb_list);
+ }
+ }
+
+ return 0;
+}
+subsys_initcall(audio_notifier_subsys_init);
+
+static int __init audio_notifier_init(void)
+{
+ int ret;
+
+ ret = audio_pdr_register(&pdr_nb);
+ if (IS_ERR_VALUE(ret)) {
+ pr_debug("%s: PDR register failed, ret = %d, disable service\n",
+ __func__, ret);
+ audio_notifer_disable_service(AUDIO_NOTIFIER_PDR_SERVICE);
+ }
+
+ /* Do not return error since PDR enablement is not critical */
+ return 0;
+}
+module_init(audio_notifier_init);
+
+static int __init audio_notifier_late_init(void)
+{
+ /*
+ * If pdr registration failed, register clients on next service
+ * Do in late init to ensure that SSR subsystem is initialized
+ */
+ if (!audio_notifer_is_service_enabled(AUDIO_NOTIFIER_PDR_SERVICE))
+ audio_notifer_reg_all_clients();
+
+ return 0;
+}
+late_initcall(audio_notifier_late_init);
diff --git a/drivers/soc/qcom/qdsp6v2/audio_pdr.c b/drivers/soc/qcom/qdsp6v2/audio_pdr.c
new file mode 100644
index 0000000..0270e1f
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/audio_pdr.c
@@ -0,0 +1,147 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/qdsp6v2/audio_pdr.h>
+#include <soc/qcom/service-locator.h>
+#include <soc/qcom/service-notifier.h>
+
+static struct pd_qmi_client_data audio_pdr_services[AUDIO_PDR_DOMAIN_MAX] = {
+ { /* AUDIO_PDR_DOMAIN_ADSP */
+ .client_name = "audio_pdr_adsp",
+ .service_name = "avs/audio"
+ }
+};
+
+struct srcu_notifier_head audio_pdr_cb_list;
+
+static int audio_pdr_locator_callback(struct notifier_block *this,
+ unsigned long opcode, void *data)
+{
+ unsigned long pdr_state = AUDIO_PDR_FRAMEWORK_DOWN;
+
+ if (opcode == LOCATOR_DOWN) {
+ pr_debug("%s: Service %s is down!", __func__,
+ audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
+ service_name);
+ goto done;
+ }
+
+ memcpy(&audio_pdr_services, data,
+ sizeof(audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP]));
+ if (audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].total_domains == 1) {
+ pr_debug("%s: Service %s, returned total domains %d, ",
+ __func__,
+ audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
+ audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
+ total_domains);
+ pdr_state = AUDIO_PDR_FRAMEWORK_UP;
+ goto done;
+ } else
+ pr_err("%s: Service %s returned invalid total domains %d",
+ __func__,
+ audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
+ audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
+ total_domains);
+done:
+ srcu_notifier_call_chain(&audio_pdr_cb_list, pdr_state, NULL);
+ return NOTIFY_OK;
+}
+
+static struct notifier_block audio_pdr_locator_nb = {
+ .notifier_call = audio_pdr_locator_callback,
+ .priority = 0,
+};
+
+int audio_pdr_register(struct notifier_block *nb)
+{
+ if (nb == NULL) {
+ pr_err("%s: Notifier block is NULL\n", __func__);
+ return -EINVAL;
+ }
+ return srcu_notifier_chain_register(&audio_pdr_cb_list, nb);
+}
+EXPORT_SYMBOL(audio_pdr_register);
+
+void *audio_pdr_service_register(int domain_id,
+ struct notifier_block *nb, int *curr_state)
+{
+ void *handle;
+
+ if ((domain_id < 0) ||
+ (domain_id >= AUDIO_PDR_DOMAIN_MAX)) {
+ pr_err("%s: Invalid service ID %d\n", __func__, domain_id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ handle = service_notif_register_notifier(
+ audio_pdr_services[domain_id].domain_list[0].name,
+ audio_pdr_services[domain_id].domain_list[0].instance_id,
+ nb, curr_state);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: Failed to register for service %s, instance %d\n",
+ __func__,
+ audio_pdr_services[domain_id].domain_list[0].name,
+ audio_pdr_services[domain_id].domain_list[0].
+ instance_id);
+ }
+ return handle;
+}
+EXPORT_SYMBOL(audio_pdr_service_register);
+
+int audio_pdr_service_deregister(void *service_handle,
+ struct notifier_block *nb)
+{
+ int ret;
+
+ if (service_handle == NULL) {
+ pr_err("%s: service handle is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = service_notif_unregister_notifier(
+ service_handle, nb);
+ if (IS_ERR_VALUE(ret))
+ pr_err("%s: Failed to deregister service ret %d\n",
+ __func__, ret);
+done:
+ return ret;
+}
+EXPORT_SYMBOL(audio_pdr_service_deregister);
+
+static int __init audio_pdr_subsys_init(void)
+{
+ srcu_init_notifier_head(&audio_pdr_cb_list);
+ return 0;
+}
+subsys_initcall(audio_pdr_subsys_init);
+
+static int __init audio_pdr_late_init(void)
+{
+ int ret;
+
+ ret = get_service_location(
+ audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].client_name,
+ audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
+ &audio_pdr_locator_nb);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s get_service_location failed ret %d\n",
+ __func__, ret);
+ srcu_notifier_call_chain(&audio_pdr_cb_list,
+ AUDIO_PDR_FRAMEWORK_DOWN, NULL);
+ }
+
+ return ret;
+}
+late_initcall(audio_pdr_late_init);
diff --git a/drivers/soc/qcom/qdsp6v2/audio_ssr.c b/drivers/soc/qcom/qdsp6v2/audio_ssr.c
new file mode 100644
index 0000000..a66fb2a
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/audio_ssr.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/qdsp6v2/audio_ssr.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+
+#define SCM_Q6_NMI_CMD 0x1
+
+static char *audio_ssr_domains[] = {
+ "adsp",
+ "modem"
+};
+
+void *audio_ssr_register(int domain_id, struct notifier_block *nb)
+{
+ if ((domain_id < 0) ||
+ (domain_id >= AUDIO_SSR_DOMAIN_MAX)) {
+ pr_err("%s: Invalid service ID %d\n", __func__, domain_id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return subsys_notif_register_notifier(
+ audio_ssr_domains[domain_id], nb);
+}
+EXPORT_SYMBOL(audio_ssr_register);
+
+int audio_ssr_deregister(void *handle, struct notifier_block *nb)
+{
+ return subsys_notif_unregister_notifier(handle, nb);
+}
+EXPORT_SYMBOL(audio_ssr_deregister);
+
+void audio_ssr_send_nmi(void *ssr_cb_data)
+{
+ struct notif_data *data = (struct notif_data *)ssr_cb_data;
+ struct scm_desc desc;
+
+ if (data && data->crashed) {
+ /* Send NMI to QDSP6 via an SCM call. */
+ if (!is_scm_armv8()) {
+ scm_call_atomic1(SCM_SVC_UTIL,
+ SCM_Q6_NMI_CMD, 0x1);
+ } else {
+ desc.args[0] = 0x1;
+ desc.arginfo = SCM_ARGS(1);
+ scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_UTIL,
+ SCM_Q6_NMI_CMD), &desc);
+ }
+ /* The write should go through before q6 is shutdown */
+ mb();
+ pr_debug("%s: Q6 NMI was sent.\n", __func__);
+ }
+}
+EXPORT_SYMBOL(audio_ssr_send_nmi);
diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c
new file mode 100644
index 0000000..a021759
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-buf.h>
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/of_device.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/export.h>
+#include <linux/qcom_iommu.h>
+#include <asm/dma-iommu.h>
+
+#define MSM_AUDIO_ION_PROBED (1 << 0)
+
+#define MSM_AUDIO_ION_PHYS_ADDR(alloc_data) \
+ alloc_data->table->sgl->dma_address
+
+#define MSM_AUDIO_ION_VA_START 0x10000000
+#define MSM_AUDIO_ION_VA_LEN 0x0FFFFFFF
+
+#define MSM_AUDIO_SMMU_SID_OFFSET 32
+
+struct addr_range {
+ dma_addr_t start;
+ size_t size;
+};
+
+struct context_bank_info {
+ const char *name;
+ struct addr_range addr_range;
+};
+
+struct msm_audio_ion_private {
+ bool smmu_enabled;
+ bool audioheap_enabled;
+ struct device *cb_dev;
+ struct dma_iommu_mapping *mapping;
+ u8 device_status;
+ struct list_head alloc_list;
+ struct mutex list_mutex;
+ u64 smmu_sid_bits;
+ u32 smmu_version;
+};
+
+struct msm_audio_alloc_data {
+ struct ion_client *client;
+ struct ion_handle *handle;
+ size_t len;
+ struct dma_buf *dma_buf;
+ struct dma_buf_attachment *attach;
+ struct sg_table *table;
+ struct list_head list;
+};
+
+static struct msm_audio_ion_private msm_audio_ion_data = {0,};
+
+static int msm_audio_ion_get_phys(struct ion_client *client,
+ struct ion_handle *handle,
+ ion_phys_addr_t *addr, size_t *len);
+
+static int msm_audio_dma_buf_map(struct ion_client *client,
+ struct ion_handle *handle,
+ ion_phys_addr_t *addr, size_t *len);
+
+static int msm_audio_dma_buf_unmap(struct ion_client *client,
+ struct ion_handle *handle);
+
+static void msm_audio_ion_add_allocation(
+ struct msm_audio_ion_private *msm_audio_ion_data,
+ struct msm_audio_alloc_data *alloc_data)
+{
+ /*
+ * Since these APIs can be invoked by multiple
+ * clients, there is need to make sure the list
+ * of allocations is always protected
+ */
+ mutex_lock(&(msm_audio_ion_data->list_mutex));
+ list_add_tail(&(alloc_data->list),
+ &(msm_audio_ion_data->alloc_list));
+ mutex_unlock(&(msm_audio_ion_data->list_mutex));
+}
+
+int msm_audio_ion_alloc(const char *name, struct ion_client **client,
+ struct ion_handle **handle, size_t bufsz,
+ ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
+{
+ int rc = -EINVAL;
+ unsigned long err_ion_ptr = 0;
+
+ if ((msm_audio_ion_data.smmu_enabled == true) &&
+ !(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
+ pr_debug("%s:probe is not done, deferred\n", __func__);
+ return -EPROBE_DEFER;
+ }
+ if (!name || !client || !handle || !paddr || !vaddr
+ || !bufsz || !pa_len) {
+ pr_err("%s: Invalid params\n", __func__);
+ return -EINVAL;
+ }
+ *client = msm_audio_ion_client_create(name);
+ if (IS_ERR_OR_NULL((void *)(*client))) {
+ pr_err("%s: ION create client for AUDIO failed\n", __func__);
+ goto err;
+ }
+
+ *handle = ion_alloc(*client, bufsz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL((void *) (*handle))) {
+ if (msm_audio_ion_data.smmu_enabled == true) {
+ pr_debug("system heap is used");
+ msm_audio_ion_data.audioheap_enabled = 0;
+ *handle = ion_alloc(*client, bufsz, SZ_4K,
+ ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+ }
+ if (IS_ERR_OR_NULL((void *) (*handle))) {
+ if (IS_ERR((void *)(*handle)))
+ err_ion_ptr = PTR_ERR((int *)(*handle));
+ pr_err("%s:ION alloc fail err ptr=%ld, smmu_enabled=%d\n",
+ __func__, err_ion_ptr, msm_audio_ion_data.smmu_enabled);
+ rc = -ENOMEM;
+ goto err_ion_client;
+ }
+ } else {
+ pr_debug("audio heap is used");
+ msm_audio_ion_data.audioheap_enabled = 1;
+ }
+
+ rc = msm_audio_ion_get_phys(*client, *handle, paddr, pa_len);
+ if (rc) {
+ pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+ __func__, rc);
+ goto err_ion_handle;
+ }
+
+ *vaddr = ion_map_kernel(*client, *handle);
+ if (IS_ERR_OR_NULL((void *)*vaddr)) {
+ pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ goto err_ion_handle;
+ }
+ pr_debug("%s: mapped address = %pK, size=%zd\n", __func__,
+ *vaddr, bufsz);
+
+ if (bufsz != 0) {
+ pr_debug("%s: memset to 0 %pK %zd\n", __func__, *vaddr, bufsz);
+ memset((void *)*vaddr, 0, bufsz);
+ }
+
+ return rc;
+
+err_ion_handle:
+ ion_free(*client, *handle);
+err_ion_client:
+ msm_audio_ion_client_destroy(*client);
+ *handle = NULL;
+ *client = NULL;
+err:
+ return rc;
+}
+EXPORT_SYMBOL(msm_audio_ion_alloc);
+
+int msm_audio_ion_import(const char *name, struct ion_client **client,
+ struct ion_handle **handle, int fd,
+ unsigned long *ionflag, size_t bufsz,
+ ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
+{
+ int rc = 0;
+
+ if ((msm_audio_ion_data.smmu_enabled == true) &&
+ !(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
+ pr_debug("%s:probe is not done, deferred\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
+ if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
+ pr_err("%s: Invalid params\n", __func__);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ *client = msm_audio_ion_client_create(name);
+ if (IS_ERR_OR_NULL((void *)(*client))) {
+ pr_err("%s: ION create client for AUDIO failed\n", __func__);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* name should be audio_acdb_client or Audio_Dec_Client,
+ * bufsz should be 0 and fd shouldn't be 0 as of now
+ */
+ *handle = ion_import_dma_buf(*client, fd);
+ pr_debug("%s: DMA Buf name=%s, fd=%d handle=%pK\n", __func__,
+ name, fd, *handle);
+ if (IS_ERR_OR_NULL((void *) (*handle))) {
+ pr_err("%s: ion import dma buffer failed\n",
+ __func__);
+ rc = -EINVAL;
+ goto err_destroy_client;
+ }
+
+ if (ionflag != NULL) {
+ rc = ion_handle_get_flags(*client, *handle, ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n",
+ __func__);
+ goto err_ion_handle;
+ }
+ }
+
+ rc = msm_audio_ion_get_phys(*client, *handle, paddr, pa_len);
+ if (rc) {
+ pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+ __func__, rc);
+ goto err_ion_handle;
+ }
+
+ *vaddr = ion_map_kernel(*client, *handle);
+ if (IS_ERR_OR_NULL((void *)*vaddr)) {
+ pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ rc = -ENOMEM;
+ goto err_ion_handle;
+ }
+ pr_debug("%s: mapped address = %pK, size=%zd\n", __func__,
+ *vaddr, bufsz);
+
+ return 0;
+
+err_ion_handle:
+ ion_free(*client, *handle);
+err_destroy_client:
+ msm_audio_ion_client_destroy(*client);
+ *client = NULL;
+ *handle = NULL;
+err:
+ return rc;
+}
+
+int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle)
+{
+ if (!client || !handle) {
+ pr_err("%s Invalid params\n", __func__);
+ return -EINVAL;
+ }
+ if (msm_audio_ion_data.smmu_enabled)
+ msm_audio_dma_buf_unmap(client, handle);
+
+ ion_unmap_kernel(client, handle);
+
+ ion_free(client, handle);
+ msm_audio_ion_client_destroy(client);
+ return 0;
+}
+EXPORT_SYMBOL(msm_audio_ion_free);
+
+int msm_audio_ion_mmap(struct audio_buffer *ab,
+ struct vm_area_struct *vma)
+{
+ struct sg_table *table;
+ unsigned long addr = vma->vm_start;
+ unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+ struct scatterlist *sg;
+ unsigned int i;
+ struct page *page;
+ int ret;
+
+ pr_debug("%s\n", __func__);
+
+ table = ion_sg_table(ab->client, ab->handle);
+
+ if (IS_ERR(table)) {
+ pr_err("%s: Unable to get sg_table from ion: %ld\n",
+ __func__, PTR_ERR(table));
+ return PTR_ERR(table);
+ } else if (!table) {
+ pr_err("%s: sg_list is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ /* uncached */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ /* We need to check if a page is associated with this sg list because:
+ * If the allocation came from a carveout we currently don't have
+ * pages associated with carved out memory. This might change in the
+ * future and we can remove this check and the else statement.
+ */
+ page = sg_page(table->sgl);
+ if (page) {
+ pr_debug("%s: page is NOT null\n", __func__);
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ unsigned long remainder = vma->vm_end - addr;
+ unsigned long len = sg->length;
+
+ page = sg_page(sg);
+
+ if (offset >= len) {
+ offset -= len;
+ continue;
+ } else if (offset) {
+ page += offset / PAGE_SIZE;
+ len -= offset;
+ offset = 0;
+ }
+ len = min(len, remainder);
+ pr_debug("vma=%pK, addr=%x len=%ld vm_start=%x vm_end=%x vm_page_prot=%ld\n",
+ vma, (unsigned int)addr, len,
+ (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end,
+ (unsigned long int)vma->vm_page_prot);
+ remap_pfn_range(vma, addr, page_to_pfn(page), len,
+ vma->vm_page_prot);
+ addr += len;
+ if (addr >= vma->vm_end)
+ return 0;
+ }
+ } else {
+ ion_phys_addr_t phys_addr;
+ size_t phys_len;
+ size_t va_len = 0;
+
+ pr_debug("%s: page is NULL\n", __func__);
+ ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len);
+ if (ret) {
+ pr_err("%s: Unable to get phys address from ION buffer: %d\n"
+ , __func__, ret);
+ return ret;
+ }
+ pr_debug("phys=%pKK len=%zd\n", &phys_addr, phys_len);
+ pr_debug("vma=%pK, vm_start=%x vm_end=%x vm_pgoff=%ld vm_page_prot=%ld\n",
+ vma, (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end, vma->vm_pgoff,
+ (unsigned long int)vma->vm_page_prot);
+ va_len = vma->vm_end - vma->vm_start;
+ if ((offset > phys_len) || (va_len > phys_len-offset)) {
+ pr_err("wrong offset size %ld, lens= %zd, va_len=%zd\n",
+ offset, phys_len, va_len);
+ return -EINVAL;
+ }
+ ret = remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(phys_addr) + vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+ }
+ return 0;
+}
+
+
+bool msm_audio_ion_is_smmu_available(void)
+{
+ return msm_audio_ion_data.smmu_enabled;
+}
+
+/* move to static section again */
+struct ion_client *msm_audio_ion_client_create(const char *name)
+{
+ struct ion_client *pclient = NULL;
+
+ pclient = msm_ion_client_create(name);
+ return pclient;
+}
+
+
+void msm_audio_ion_client_destroy(struct ion_client *client)
+{
+ pr_debug("%s: client = %pK smmu_enabled = %d\n", __func__,
+ client, msm_audio_ion_data.smmu_enabled);
+
+ ion_client_destroy(client);
+}
+
+int msm_audio_ion_import_legacy(const char *name, struct ion_client *client,
+ struct ion_handle **handle, int fd,
+ unsigned long *ionflag, size_t bufsz,
+ ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
+{
+ int rc = 0;
+
+ if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
+ pr_err("%s: Invalid params\n", __func__);
+ rc = -EINVAL;
+ goto err;
+ }
+ /* client is already created for legacy and given
+ * name should be audio_acdb_client or Audio_Dec_Client,
+ * bufsz should be 0 and fd shouldn't be 0 as of now
+ */
+ *handle = ion_import_dma_buf(client, fd);
+ pr_debug("%s: DMA Buf name=%s, fd=%d handle=%pK\n", __func__,
+ name, fd, *handle);
+ if (IS_ERR_OR_NULL((void *)(*handle))) {
+ pr_err("%s: ion import dma buffer failed\n",
+ __func__);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if (ionflag != NULL) {
+ rc = ion_handle_get_flags(client, *handle, ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n",
+ __func__);
+ rc = -EINVAL;
+ goto err_ion_handle;
+ }
+ }
+
+ rc = msm_audio_ion_get_phys(client, *handle, paddr, pa_len);
+ if (rc) {
+ pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ goto err_ion_handle;
+ }
+
+ /*Need to add condition SMMU enable or not */
+ *vaddr = ion_map_kernel(client, *handle);
+ if (IS_ERR_OR_NULL((void *)*vaddr)) {
+ pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ rc = -EINVAL;
+ goto err_ion_handle;
+ }
+
+ if (bufsz != 0)
+ memset((void *)*vaddr, 0, bufsz);
+
+ return 0;
+
+err_ion_handle:
+ ion_free(client, *handle);
+err:
+ return rc;
+}
+
+int msm_audio_ion_free_legacy(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ if (msm_audio_ion_data.smmu_enabled)
+ msm_audio_dma_buf_unmap(client, handle);
+
+ ion_unmap_kernel(client, handle);
+
+ ion_free(client, handle);
+ /* no client_destrody in legacy*/
+ return 0;
+}
+
+int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op)
+{
+ unsigned long ionflag = 0;
+ int rc = 0;
+ int msm_cache_ops = 0;
+
+ if (!abuff) {
+ pr_err("%s: Invalid params: %pK\n", __func__, abuff);
+ return -EINVAL;
+ }
+ rc = ion_handle_get_flags(abuff->client, abuff->handle,
+ &ionflag);
+ if (rc) {
+ pr_err("ion_handle_get_flags failed: %d\n", rc);
+ goto cache_op_failed;
+ }
+
+ /* has to be CACHED */
+ if (ION_IS_CACHED(ionflag)) {
+ /* ION_IOC_INV_CACHES or ION_IOC_CLEAN_CACHES */
+ msm_cache_ops = cache_op;
+ rc = msm_ion_do_cache_op(abuff->client,
+ abuff->handle,
+ (unsigned long *) abuff->data,
+ (unsigned long)abuff->size,
+ msm_cache_ops);
+ if (rc) {
+ pr_err("cache operation failed %d\n", rc);
+ goto cache_op_failed;
+ }
+ }
+cache_op_failed:
+ return rc;
+}
+
+
+static int msm_audio_dma_buf_map(struct ion_client *client,
+ struct ion_handle *handle,
+ ion_phys_addr_t *addr, size_t *len)
+{
+
+ struct msm_audio_alloc_data *alloc_data;
+ struct device *cb_dev;
+ int rc = 0;
+
+ cb_dev = msm_audio_ion_data.cb_dev;
+
+ /* Data required per buffer mapping */
+ alloc_data = kzalloc(sizeof(*alloc_data), GFP_KERNEL);
+ if (!alloc_data)
+ return -ENOMEM;
+
+ /* Get the ION handle size */
+ ion_handle_get_size(client, handle, len);
+
+ alloc_data->client = client;
+ alloc_data->handle = handle;
+ alloc_data->len = *len;
+
+ /* Get the dma_buf handle from ion_handle */
+ alloc_data->dma_buf = ion_share_dma_buf(client, handle);
+ if (IS_ERR(alloc_data->dma_buf)) {
+ rc = PTR_ERR(alloc_data->dma_buf);
+ dev_err(cb_dev,
+ "%s: Fail to get dma_buf handle, rc = %d\n",
+ __func__, rc);
+ goto err_dma_buf;
+ }
+
+ /* Attach the dma_buf to context bank device */
+ alloc_data->attach = dma_buf_attach(alloc_data->dma_buf,
+ cb_dev);
+ if (IS_ERR(alloc_data->attach)) {
+ rc = PTR_ERR(alloc_data->attach);
+ dev_err(cb_dev,
+ "%s: Fail to attach dma_buf to CB, rc = %d\n",
+ __func__, rc);
+ goto err_attach;
+ }
+
+ /*
+ * Get the scatter-gather list.
+ * There is no info as this is a write buffer or
+ * read buffer, hence the request is bi-directional
+ * to accommodate both read and write mappings.
+ */
+ alloc_data->table = dma_buf_map_attachment(alloc_data->attach,
+ DMA_BIDIRECTIONAL);
+ if (IS_ERR(alloc_data->table)) {
+ rc = PTR_ERR(alloc_data->table);
+ dev_err(cb_dev,
+ "%s: Fail to map attachment, rc = %d\n",
+ __func__, rc);
+ goto err_map_attach;
+ }
+
+ rc = dma_map_sg(cb_dev, alloc_data->table->sgl,
+ alloc_data->table->nents,
+ DMA_BIDIRECTIONAL);
+ if (rc != alloc_data->table->nents) {
+ dev_err(cb_dev,
+ "%s: Fail to map SG, rc = %d, nents = %d\n",
+ __func__, rc, alloc_data->table->nents);
+ goto err_map_sg;
+ }
+ /* Make sure not to return rc from dma_map_sg, as it can be nonzero */
+ rc = 0;
+
+ /* physical address from mapping */
+ *addr = MSM_AUDIO_ION_PHYS_ADDR(alloc_data);
+
+ msm_audio_ion_add_allocation(&msm_audio_ion_data,
+ alloc_data);
+ return rc;
+
+err_map_sg:
+ dma_buf_unmap_attachment(alloc_data->attach,
+ alloc_data->table,
+ DMA_BIDIRECTIONAL);
+err_map_attach:
+ dma_buf_detach(alloc_data->dma_buf,
+ alloc_data->attach);
+err_attach:
+ dma_buf_put(alloc_data->dma_buf);
+
+err_dma_buf:
+ kfree(alloc_data);
+
+ return rc;
+}
+
+static int msm_audio_dma_buf_unmap(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ int rc = 0;
+ struct msm_audio_alloc_data *alloc_data = NULL;
+ struct list_head *ptr, *next;
+ struct device *cb_dev = msm_audio_ion_data.cb_dev;
+ bool found = false;
+
+ /*
+ * Though list_for_each_safe is delete safe, lock
+ * should be explicitly acquired to avoid race condition
+ * on adding elements to the list.
+ */
+ mutex_lock(&(msm_audio_ion_data.list_mutex));
+ list_for_each_safe(ptr, next,
+ &(msm_audio_ion_data.alloc_list)) {
+
+ alloc_data = list_entry(ptr, struct msm_audio_alloc_data,
+ list);
+
+ if (alloc_data->handle == handle &&
+ alloc_data->client == client) {
+ found = true;
+ dma_unmap_sg(cb_dev,
+ alloc_data->table->sgl,
+ alloc_data->table->nents,
+ DMA_BIDIRECTIONAL);
+
+ dma_buf_unmap_attachment(alloc_data->attach,
+ alloc_data->table,
+ DMA_BIDIRECTIONAL);
+
+ dma_buf_detach(alloc_data->dma_buf,
+ alloc_data->attach);
+
+ dma_buf_put(alloc_data->dma_buf);
+
+ list_del(&(alloc_data->list));
+ kfree(alloc_data);
+ break;
+ }
+ }
+ mutex_unlock(&(msm_audio_ion_data.list_mutex));
+
+ if (!found) {
+ dev_err(cb_dev,
+ "%s: cannot find allocation, ion_handle %pK, ion_client %pK",
+ __func__, handle, client);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int msm_audio_ion_get_phys(struct ion_client *client,
+ struct ion_handle *handle,
+ ion_phys_addr_t *addr, size_t *len)
+{
+ int rc = 0;
+
+ pr_debug("%s: smmu_enabled = %d\n", __func__,
+ msm_audio_ion_data.smmu_enabled);
+
+ if (msm_audio_ion_data.smmu_enabled) {
+ rc = msm_audio_dma_buf_map(client, handle, addr, len);
+ if (rc) {
+ pr_err("%s: failed to map DMA buf, err = %d\n",
+ __func__, rc);
+ goto err;
+ }
+ /* Append the SMMU SID information to the IOVA address */
+ *addr |= msm_audio_ion_data.smmu_sid_bits;
+ } else {
+ rc = ion_phys(client, handle, addr, len);
+ }
+
+ pr_debug("phys=%pK, len=%zd, rc=%d\n", &(*addr), *len, rc);
+err:
+ return rc;
+}
+
+static int msm_audio_smmu_init_legacy(struct device *dev)
+{
+ struct dma_iommu_mapping *mapping;
+ struct device_node *ctx_node = NULL;
+ struct context_bank_info *cb;
+ int ret;
+ u32 read_val[2];
+
+ cb = devm_kzalloc(dev, sizeof(struct context_bank_info), GFP_KERNEL);
+ if (!cb)
+ return -ENOMEM;
+
+ ctx_node = of_parse_phandle(dev->of_node, "iommus", 0);
+ if (!ctx_node) {
+ dev_err(dev, "%s Could not find any iommus for audio\n",
+ __func__);
+ return -EINVAL;
+ }
+ ret = of_property_read_string(ctx_node, "label", &(cb->name));
+ if (ret) {
+ dev_err(dev, "%s Could not find label\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("label found : %s\n", cb->name);
+ ret = of_property_read_u32_array(ctx_node,
+ "qcom,virtual-addr-pool",
+ read_val, 2);
+ if (ret) {
+ dev_err(dev, "%s Could not read addr pool for group : (%d)\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+ msm_audio_ion_data.cb_dev = msm_iommu_get_ctx(cb->name);
+ cb->addr_range.start = (dma_addr_t) read_val[0];
+ cb->addr_range.size = (size_t) read_val[1];
+ dev_dbg(dev, "%s Legacy iommu usage\n", __func__);
+ mapping = arm_iommu_create_mapping(
+ msm_iommu_get_bus(msm_audio_ion_data.cb_dev),
+ cb->addr_range.start,
+ cb->addr_range.size);
+ if (IS_ERR(mapping))
+ return PTR_ERR(mapping);
+
+ ret = arm_iommu_attach_device(msm_audio_ion_data.cb_dev, mapping);
+ if (ret) {
+ dev_err(dev, "%s: Attach failed, err = %d\n",
+ __func__, ret);
+ goto fail_attach;
+ }
+
+ msm_audio_ion_data.mapping = mapping;
+ INIT_LIST_HEAD(&msm_audio_ion_data.alloc_list);
+ mutex_init(&(msm_audio_ion_data.list_mutex));
+
+ return 0;
+
+fail_attach:
+ arm_iommu_release_mapping(mapping);
+ return ret;
+}
+
+static int msm_audio_smmu_init(struct device *dev)
+{
+ struct dma_iommu_mapping *mapping;
+ int ret;
+
+ mapping = arm_iommu_create_mapping(
+ msm_iommu_get_bus(dev),
+ MSM_AUDIO_ION_VA_START,
+ MSM_AUDIO_ION_VA_LEN);
+ if (IS_ERR(mapping))
+ return PTR_ERR(mapping);
+
+ ret = arm_iommu_attach_device(dev, mapping);
+ if (ret) {
+ dev_err(dev, "%s: Attach failed, err = %d\n",
+ __func__, ret);
+ goto fail_attach;
+ }
+
+ msm_audio_ion_data.cb_dev = dev;
+ msm_audio_ion_data.mapping = mapping;
+ INIT_LIST_HEAD(&msm_audio_ion_data.alloc_list);
+ mutex_init(&(msm_audio_ion_data.list_mutex));
+
+ return 0;
+
+fail_attach:
+ arm_iommu_release_mapping(mapping);
+ return ret;
+}
+
+static const struct of_device_id msm_audio_ion_dt_match[] = {
+ { .compatible = "qcom,msm-audio-ion" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, msm_audio_ion_dt_match);
+
+
+u32 msm_audio_ion_get_smmu_sid_mode32(void)
+{
+ if (msm_audio_ion_data.smmu_enabled)
+ return upper_32_bits(msm_audio_ion_data.smmu_sid_bits);
+ else
+ return 0;
+}
+
+u32 msm_audio_populate_upper_32_bits(ion_phys_addr_t pa)
+{
+ if (sizeof(ion_phys_addr_t) == sizeof(u32))
+ return msm_audio_ion_get_smmu_sid_mode32();
+ else
+ return upper_32_bits(pa);
+}
+
+static int msm_audio_ion_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ const char *msm_audio_ion_dt = "qcom,smmu-enabled";
+ const char *msm_audio_ion_smmu = "qcom,smmu-version";
+ bool smmu_enabled;
+ enum apr_subsys_state q6_state;
+ struct device *dev = &pdev->dev;
+
+ if (dev->of_node == NULL) {
+ dev_err(dev,
+ "%s: device tree is not found\n",
+ __func__);
+ msm_audio_ion_data.smmu_enabled = 0;
+ return 0;
+ }
+
+ smmu_enabled = of_property_read_bool(dev->of_node,
+ msm_audio_ion_dt);
+ msm_audio_ion_data.smmu_enabled = smmu_enabled;
+
+ if (smmu_enabled) {
+ rc = of_property_read_u32(dev->of_node,
+ msm_audio_ion_smmu,
+ &msm_audio_ion_data.smmu_version);
+ if (rc) {
+ dev_err(dev,
+ "%s: qcom,smmu_version missing in DT node\n",
+ __func__);
+ return rc;
+ }
+ dev_dbg(dev, "%s: SMMU version is (%d)", __func__,
+ msm_audio_ion_data.smmu_version);
+ q6_state = apr_get_q6_state();
+ if (q6_state == APR_SUBSYS_DOWN) {
+ dev_dbg(dev,
+ "defering %s, adsp_state %d\n",
+ __func__, q6_state);
+ return -EPROBE_DEFER;
+ }
+ dev_dbg(dev, "%s: adsp is ready\n", __func__);
+ }
+
+ dev_dbg(dev, "%s: SMMU is %s\n", __func__,
+ (smmu_enabled) ? "Enabled" : "Disabled");
+
+ if (smmu_enabled) {
+ u64 smmu_sid = 0;
+ struct of_phandle_args iommuspec;
+
+ /* Get SMMU SID information from Devicetree */
+ rc = of_parse_phandle_with_args(dev->of_node, "iommus",
+ "#iommu-cells", 0, &iommuspec);
+ if (rc)
+ dev_err(dev, "%s: could not get smmu SID, ret = %d\n",
+ __func__, rc);
+ else
+ smmu_sid = iommuspec.args[0];
+
+ msm_audio_ion_data.smmu_sid_bits =
+ smmu_sid << MSM_AUDIO_SMMU_SID_OFFSET;
+
+ if (msm_audio_ion_data.smmu_version == 0x1) {
+ rc = msm_audio_smmu_init_legacy(dev);
+ } else if (msm_audio_ion_data.smmu_version == 0x2) {
+ rc = msm_audio_smmu_init(dev);
+ } else {
+ dev_err(dev, "%s: smmu version invalid %d\n",
+ __func__, msm_audio_ion_data.smmu_version);
+ rc = -EINVAL;
+ }
+ if (rc)
+ dev_err(dev, "%s: smmu init failed, err = %d\n",
+ __func__, rc);
+ }
+
+ if (!rc)
+ msm_audio_ion_data.device_status |= MSM_AUDIO_ION_PROBED;
+
+ return rc;
+}
+
+static int msm_audio_ion_remove(struct platform_device *pdev)
+{
+ struct dma_iommu_mapping *mapping;
+ struct device *audio_cb_dev;
+
+ mapping = msm_audio_ion_data.mapping;
+ audio_cb_dev = msm_audio_ion_data.cb_dev;
+
+ if (audio_cb_dev && mapping) {
+ arm_iommu_detach_device(audio_cb_dev);
+ arm_iommu_release_mapping(mapping);
+ }
+
+ msm_audio_ion_data.smmu_enabled = 0;
+ msm_audio_ion_data.device_status = 0;
+ return 0;
+}
+
+static struct platform_driver msm_audio_ion_driver = {
+ .driver = {
+ .name = "msm-audio-ion",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_audio_ion_dt_match,
+ },
+ .probe = msm_audio_ion_probe,
+ .remove = msm_audio_ion_remove,
+};
+
+static int __init msm_audio_ion_init(void)
+{
+ return platform_driver_register(&msm_audio_ion_driver);
+}
+module_init(msm_audio_ion_init);
+
+static void __exit msm_audio_ion_exit(void)
+{
+ platform_driver_unregister(&msm_audio_ion_driver);
+}
+module_exit(msm_audio_ion_exit);
+
+MODULE_DESCRIPTION("MSM Audio ION module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c
new file mode 100644
index 0000000..07e8991
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c
@@ -0,0 +1,792 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/qdsp6v2/apr_tal.h>
+#include <linux/qdsp6v2/apr.h>
+#include <sound/voice_svc.h>
+
+#define MINOR_NUMBER 1
+#define APR_MAX_RESPONSE 10
+#define TIMEOUT_MS 1000
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+
+struct voice_svc_device {
+ struct cdev *cdev;
+ struct device *dev;
+ int major;
+};
+
+struct voice_svc_prvt {
+ void *apr_q6_mvm;
+ void *apr_q6_cvs;
+ uint16_t response_count;
+ struct list_head response_queue;
+ wait_queue_head_t response_wait;
+ spinlock_t response_lock;
+};
+
+struct apr_data {
+ struct apr_hdr hdr;
+ __u8 payload[0];
+} __packed;
+
+struct apr_response_list {
+ struct list_head list;
+ struct voice_svc_cmd_response resp;
+};
+
+static struct voice_svc_device *voice_svc_dev;
+static struct class *voice_svc_class;
+static bool reg_dummy_sess;
+static void *dummy_q6_mvm;
+static void *dummy_q6_cvs;
+dev_t device_num;
+
+static int voice_svc_dummy_reg(void);
+static int32_t qdsp_dummy_apr_callback(struct apr_client_data *data,
+ void *priv);
+
+static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
+{
+ struct voice_svc_prvt *prtd;
+ struct apr_response_list *response_list;
+ unsigned long spin_flags;
+
+ if ((data == NULL) || (priv == NULL)) {
+ pr_err("%s: data or priv is NULL\n", __func__);
+
+ return -EINVAL;
+ }
+
+ prtd = (struct voice_svc_prvt *)priv;
+ if (prtd == NULL) {
+ pr_err("%s: private data is NULL\n", __func__);
+
+ return -EINVAL;
+ }
+
+ pr_debug("%s: data->opcode %x\n", __func__,
+ data->opcode);
+
+ if (data->opcode == RESET_EVENTS) {
+ if (data->reset_proc == APR_DEST_QDSP6) {
+ pr_debug("%s: Received ADSP reset event\n", __func__);
+
+ if (prtd->apr_q6_mvm != NULL) {
+ apr_reset(prtd->apr_q6_mvm);
+ prtd->apr_q6_mvm = NULL;
+ }
+
+ if (prtd->apr_q6_cvs != NULL) {
+ apr_reset(prtd->apr_q6_cvs);
+ prtd->apr_q6_cvs = NULL;
+ }
+ } else if (data->reset_proc == APR_DEST_MODEM) {
+ pr_debug("%s: Received Modem reset event\n", __func__);
+ }
+ /* Set the remaining member variables to default values
+ * for RESET_EVENTS
+ */
+ data->payload_size = 0;
+ data->payload = NULL;
+ data->src_port = 0;
+ data->dest_port = 0;
+ data->token = 0;
+ }
+
+ spin_lock_irqsave(&prtd->response_lock, spin_flags);
+
+ if (prtd->response_count < APR_MAX_RESPONSE) {
+ response_list = kmalloc(sizeof(struct apr_response_list) +
+ data->payload_size, GFP_ATOMIC);
+ if (response_list == NULL) {
+ spin_unlock_irqrestore(&prtd->response_lock,
+ spin_flags);
+ return -ENOMEM;
+ }
+
+ response_list->resp.src_port = data->src_port;
+
+ /* Reverting the bit manipulation done in voice_svc_update_hdr
+ * to the src_port which is returned to us as dest_port.
+ */
+ response_list->resp.dest_port = ((data->dest_port) >> 8);
+ response_list->resp.token = data->token;
+ response_list->resp.opcode = data->opcode;
+ response_list->resp.payload_size = data->payload_size;
+ if (data->payload != NULL && data->payload_size > 0) {
+ memcpy(response_list->resp.payload, data->payload,
+ data->payload_size);
+ }
+
+ list_add_tail(&response_list->list, &prtd->response_queue);
+ prtd->response_count++;
+ spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+
+ wake_up(&prtd->response_wait);
+ } else {
+ spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+ pr_err("%s: Response dropped since the queue is full\n",
+ __func__);
+ }
+
+ return 0;
+}
+
+static int32_t qdsp_dummy_apr_callback(struct apr_client_data *data, void *priv)
+{
+ /* Do Nothing */
+ return 0;
+}
+
+static void voice_svc_update_hdr(struct voice_svc_cmd_request *apr_req_data,
+ struct apr_data *aprdata)
+{
+
+ aprdata->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+ /* Bit manipulation is done on src_port so that a unique ID is sent.
+ * This manipulation can be used in the future where the same service
+ * is tried to open multiple times with the same src_port. At that
+ * time 0x0001 can be replaced with other values depending on the
+ * count.
+ */
+ aprdata->hdr.src_port = ((apr_req_data->src_port) << 8 | 0x0001);
+ aprdata->hdr.dest_port = apr_req_data->dest_port;
+ aprdata->hdr.token = apr_req_data->token;
+ aprdata->hdr.opcode = apr_req_data->opcode;
+ aprdata->hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ apr_req_data->payload_size);
+ memcpy(aprdata->payload, apr_req_data->payload,
+ apr_req_data->payload_size);
+}
+
+static int voice_svc_send_req(struct voice_svc_cmd_request *apr_request,
+ struct voice_svc_prvt *prtd)
+{
+ int ret = 0;
+ void *apr_handle = NULL;
+ struct apr_data *aprdata = NULL;
+ uint32_t user_payload_size;
+ uint32_t payload_size;
+
+ pr_debug("%s\n", __func__);
+
+ if (apr_request == NULL) {
+ pr_err("%s: apr_request is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ user_payload_size = apr_request->payload_size;
+ payload_size = sizeof(struct apr_data) + user_payload_size;
+
+ if (payload_size <= user_payload_size) {
+ pr_err("%s: invalid payload size ( 0x%x ).\n",
+ __func__, user_payload_size);
+ ret = -EINVAL;
+ goto done;
+ } else {
+ aprdata = kmalloc(payload_size, GFP_KERNEL);
+ if (aprdata == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ voice_svc_update_hdr(apr_request, aprdata);
+
+ if (!strcmp(apr_request->svc_name, VOICE_SVC_CVS_STR)) {
+ apr_handle = prtd->apr_q6_cvs;
+ } else if (!strcmp(apr_request->svc_name, VOICE_SVC_MVM_STR)) {
+ apr_handle = prtd->apr_q6_mvm;
+ } else {
+ pr_err("%s: Invalid service %.*s\n", __func__,
+ MAX_APR_SERVICE_NAME_LEN, apr_request->svc_name);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = apr_send_pkt(apr_handle, (uint32_t *)aprdata);
+
+ if (ret < 0) {
+ pr_err("%s: Fail in sending request %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ } else {
+ pr_debug("%s: apr packet sent successfully %d\n",
+ __func__, ret);
+ ret = 0;
+ }
+
+done:
+ kfree(aprdata);
+ return ret;
+}
+static int voice_svc_reg(char *svc, uint32_t src_port,
+ struct voice_svc_prvt *prtd, void **handle)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (handle == NULL) {
+ pr_err("%s: handle is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (*handle != NULL) {
+ pr_err("%s: svc handle not NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (src_port == (APR_MAX_PORTS - 1)) {
+ pr_err("%s: SRC port reserved for dummy session\n", __func__);
+ pr_err("%s: Unable to register %s\n", __func__, svc);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ *handle = apr_register("ADSP",
+ svc, qdsp_apr_callback,
+ ((src_port) << 8 | 0x0001),
+ prtd);
+
+ if (*handle == NULL) {
+ pr_err("%s: Unable to register %s\n",
+ __func__, svc);
+
+ ret = -EFAULT;
+ goto done;
+ }
+ pr_debug("%s: Register %s successful\n",
+ __func__, svc);
+done:
+ return ret;
+}
+
+static int voice_svc_dereg(char *svc, void **handle)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (handle == NULL) {
+ pr_err("%s: handle is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (*handle == NULL) {
+ pr_err("%s: svc handle is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = apr_deregister(*handle);
+ if (ret) {
+ pr_err("%s: Unable to deregister service %s; error: %d\n",
+ __func__, svc, ret);
+
+ goto done;
+ }
+ *handle = NULL;
+ pr_debug("%s: deregister %s successful\n", __func__, svc);
+
+done:
+ return ret;
+}
+
+static int process_reg_cmd(struct voice_svc_register *apr_reg_svc,
+ struct voice_svc_prvt *prtd)
+{
+ int ret = 0;
+ char *svc = NULL;
+ void **handle = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ if (!strcmp(apr_reg_svc->svc_name, VOICE_SVC_MVM_STR)) {
+ svc = VOICE_SVC_MVM_STR;
+ handle = &prtd->apr_q6_mvm;
+ } else if (!strcmp(apr_reg_svc->svc_name, VOICE_SVC_CVS_STR)) {
+ svc = VOICE_SVC_CVS_STR;
+ handle = &prtd->apr_q6_cvs;
+ } else {
+ pr_err("%s: Invalid Service: %.*s\n", __func__,
+ MAX_APR_SERVICE_NAME_LEN, apr_reg_svc->svc_name);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (apr_reg_svc->reg_flag) {
+ ret = voice_svc_reg(svc, apr_reg_svc->src_port, prtd,
+ handle);
+ } else if (!apr_reg_svc->reg_flag) {
+ ret = voice_svc_dereg(svc, handle);
+ }
+
+done:
+ return ret;
+}
+
+static ssize_t voice_svc_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int ret = 0;
+ struct voice_svc_prvt *prtd;
+ struct voice_svc_write_msg *data = NULL;
+ uint32_t cmd;
+
+ pr_debug("%s\n", __func__);
+
+ /*
+ * Check if enough memory is allocated to parse the message type.
+ * Will check there is enough to hold the payload later.
+ */
+ if (count >= sizeof(struct voice_svc_write_msg)) {
+ data = kmalloc(count, GFP_KERNEL);
+ } else {
+ pr_debug("%s: invalid data size\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (data == NULL) {
+ pr_err("%s: data kmalloc failed.\n", __func__);
+
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = copy_from_user(data, buf, count);
+ if (ret) {
+ pr_err("%s: copy_from_user failed %d\n", __func__, ret);
+
+ ret = -EPERM;
+ goto done;
+ }
+
+ cmd = data->msg_type;
+ prtd = (struct voice_svc_prvt *) file->private_data;
+ if (prtd == NULL) {
+ pr_err("%s: prtd is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ switch (cmd) {
+ case MSG_REGISTER:
+ /*
+ * Check that count reflects the expected size to ensure
+ * sufficient memory was allocated. Since voice_svc_register
+ * has a static size, this should be exact.
+ */
+ if (count == (sizeof(struct voice_svc_write_msg) +
+ sizeof(struct voice_svc_register))) {
+ ret = process_reg_cmd(
+ (struct voice_svc_register *)data->payload, prtd);
+ if (!ret)
+ ret = count;
+ } else {
+ pr_err("%s: invalid payload size\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ case MSG_REQUEST:
+ /*
+ * Check that count reflects the expected size to ensure
+ * sufficient memory was allocated. Since voice_svc_cmd_request
+ * has a variable size, check the minimum value count must be.
+ */
+ if (count >= (sizeof(struct voice_svc_write_msg) +
+ sizeof(struct voice_svc_cmd_request))) {
+ ret = voice_svc_send_req(
+ (struct voice_svc_cmd_request *)data->payload, prtd);
+ if (!ret)
+ ret = count;
+ } else {
+ pr_err("%s: invalid payload size\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ default:
+ pr_debug("%s: Invalid command: %u\n", __func__, cmd);
+ ret = -EINVAL;
+ }
+
+done:
+ kfree(data);
+ return ret;
+}
+
+static ssize_t voice_svc_read(struct file *file, char __user *arg,
+ size_t count, loff_t *ppos)
+{
+ int ret = 0;
+ struct voice_svc_prvt *prtd;
+ struct apr_response_list *resp;
+ unsigned long spin_flags;
+ int size;
+
+ pr_debug("%s\n", __func__);
+
+ prtd = (struct voice_svc_prvt *)file->private_data;
+ if (prtd == NULL) {
+ pr_err("%s: prtd is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ spin_lock_irqsave(&prtd->response_lock, spin_flags);
+
+ if (list_empty(&prtd->response_queue)) {
+ spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+ pr_debug("%s: wait for a response\n", __func__);
+
+ ret = wait_event_interruptible_timeout(prtd->response_wait,
+ !list_empty(&prtd->response_queue),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret == 0) {
+ pr_debug("%s: Read timeout\n", __func__);
+
+ ret = -ETIMEDOUT;
+ goto done;
+ } else if (ret > 0 && !list_empty(&prtd->response_queue)) {
+ pr_debug("%s: Interrupt received for response\n",
+ __func__);
+ } else if (ret < 0) {
+ pr_debug("%s: Interrupted by SIGNAL %d\n",
+ __func__, ret);
+
+ goto done;
+ }
+
+ spin_lock_irqsave(&prtd->response_lock, spin_flags);
+ }
+
+ resp = list_first_entry(&prtd->response_queue,
+ struct apr_response_list, list);
+
+ spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+
+ size = resp->resp.payload_size +
+ sizeof(struct voice_svc_cmd_response);
+
+ if (count < size) {
+ pr_err("%s: Invalid payload size %zd, %d\n",
+ __func__, count, size);
+
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (!access_ok(VERIFY_WRITE, arg, size)) {
+ pr_err("%s: Access denied to write\n",
+ __func__);
+
+ ret = -EPERM;
+ goto done;
+ }
+
+ ret = copy_to_user(arg, &resp->resp,
+ sizeof(struct voice_svc_cmd_response) +
+ resp->resp.payload_size);
+ if (ret) {
+ pr_err("%s: copy_to_user failed %d\n", __func__, ret);
+
+ ret = -EPERM;
+ goto done;
+ }
+
+ spin_lock_irqsave(&prtd->response_lock, spin_flags);
+
+ list_del(&resp->list);
+ prtd->response_count--;
+ kfree(resp);
+
+ spin_unlock_irqrestore(&prtd->response_lock,
+ spin_flags);
+
+ ret = count;
+
+done:
+ return ret;
+}
+
+static int voice_svc_dummy_reg(void)
+{
+ uint32_t src_port = APR_MAX_PORTS - 1;
+
+ pr_debug("%s\n", __func__);
+ dummy_q6_mvm = apr_register("ADSP", "MVM",
+ qdsp_dummy_apr_callback,
+ src_port,
+ NULL);
+ if (dummy_q6_mvm == NULL) {
+ pr_err("%s: Unable to register dummy MVM\n", __func__);
+ goto err;
+ }
+
+ dummy_q6_cvs = apr_register("ADSP", "CVS",
+ qdsp_dummy_apr_callback,
+ src_port,
+ NULL);
+ if (dummy_q6_cvs == NULL) {
+ pr_err("%s: Unable to register dummy CVS\n", __func__);
+ goto err;
+ }
+ return 0;
+err:
+ if (dummy_q6_mvm != NULL) {
+ apr_deregister(dummy_q6_mvm);
+ dummy_q6_mvm = NULL;
+ }
+ return -EINVAL;
+}
+
+static int voice_svc_open(struct inode *inode, struct file *file)
+{
+ struct voice_svc_prvt *prtd = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ prtd = kmalloc(sizeof(struct voice_svc_prvt), GFP_KERNEL);
+
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ memset(prtd, 0, sizeof(struct voice_svc_prvt));
+ prtd->apr_q6_cvs = NULL;
+ prtd->apr_q6_mvm = NULL;
+ prtd->response_count = 0;
+ INIT_LIST_HEAD(&prtd->response_queue);
+ init_waitqueue_head(&prtd->response_wait);
+ spin_lock_init(&prtd->response_lock);
+ file->private_data = (void *)prtd;
+
+ /* Current APR implementation doesn't support session based
+ * multiple service registrations. The apr_deregister()
+ * function sets the destination and client IDs to zero, if
+ * deregister is called for a single service instance.
+ * To avoid this, register for additional services.
+ */
+ if (!reg_dummy_sess) {
+ voice_svc_dummy_reg();
+ reg_dummy_sess = 1;
+ }
+ return 0;
+}
+
+static int voice_svc_release(struct inode *inode, struct file *file)
+{
+ int ret = 0;
+ struct apr_response_list *resp = NULL;
+ unsigned long spin_flags;
+ struct voice_svc_prvt *prtd = NULL;
+ char *svc_name = NULL;
+ void **handle = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ prtd = (struct voice_svc_prvt *)file->private_data;
+ if (prtd == NULL) {
+ pr_err("%s: prtd is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (prtd->apr_q6_cvs != NULL) {
+ svc_name = VOICE_SVC_MVM_STR;
+ handle = &prtd->apr_q6_cvs;
+ ret = voice_svc_dereg(svc_name, handle);
+ if (ret)
+ pr_err("%s: Failed to dereg CVS %d\n", __func__, ret);
+ }
+
+ if (prtd->apr_q6_mvm != NULL) {
+ svc_name = VOICE_SVC_MVM_STR;
+ handle = &prtd->apr_q6_mvm;
+ ret = voice_svc_dereg(svc_name, handle);
+ if (ret)
+ pr_err("%s: Failed to dereg MVM %d\n", __func__, ret);
+ }
+
+ spin_lock_irqsave(&prtd->response_lock, spin_flags);
+
+ while (!list_empty(&prtd->response_queue)) {
+ pr_debug("%s: Remove item from response queue\n", __func__);
+
+ resp = list_first_entry(&prtd->response_queue,
+ struct apr_response_list, list);
+ list_del(&resp->list);
+ prtd->response_count--;
+ kfree(resp);
+ }
+
+ spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+
+ kfree(file->private_data);
+ file->private_data = NULL;
+
+done:
+ return ret;
+}
+
+static const struct file_operations voice_svc_fops = {
+ .owner = THIS_MODULE,
+ .open = voice_svc_open,
+ .read = voice_svc_read,
+ .write = voice_svc_write,
+ .release = voice_svc_release,
+};
+
+
+static int voice_svc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ voice_svc_dev = devm_kzalloc(&pdev->dev,
+ sizeof(struct voice_svc_device), GFP_KERNEL);
+ if (!voice_svc_dev) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = alloc_chrdev_region(&device_num, 0, MINOR_NUMBER,
+ VOICE_SVC_DRIVER_NAME);
+ if (ret) {
+ pr_err("%s: Failed to alloc chrdev\n", __func__);
+ ret = -ENODEV;
+ goto chrdev_err;
+ }
+
+ voice_svc_dev->major = MAJOR(device_num);
+ voice_svc_class = class_create(THIS_MODULE, VOICE_SVC_DRIVER_NAME);
+ if (IS_ERR(voice_svc_class)) {
+ ret = PTR_ERR(voice_svc_class);
+ pr_err("%s: Failed to create class; err = %d\n", __func__,
+ ret);
+ goto class_err;
+ }
+
+ voice_svc_dev->dev = device_create(voice_svc_class, NULL, device_num,
+ NULL, VOICE_SVC_DRIVER_NAME);
+ if (IS_ERR(voice_svc_dev->dev)) {
+ ret = PTR_ERR(voice_svc_dev->dev);
+ pr_err("%s: Failed to create device; err = %d\n", __func__,
+ ret);
+ goto dev_err;
+ }
+
+ voice_svc_dev->cdev = cdev_alloc();
+ if (!voice_svc_dev->cdev) {
+ pr_err("%s: Failed to alloc cdev\n", __func__);
+ ret = -ENOMEM;
+ goto cdev_alloc_err;
+ }
+
+ cdev_init(voice_svc_dev->cdev, &voice_svc_fops);
+ ret = cdev_add(voice_svc_dev->cdev, device_num, MINOR_NUMBER);
+ if (ret) {
+ pr_err("%s: Failed to register chrdev; err = %d\n", __func__,
+ ret);
+ goto add_err;
+ }
+ pr_debug("%s: Device created\n", __func__);
+ goto done;
+
+add_err:
+ cdev_del(voice_svc_dev->cdev);
+cdev_alloc_err:
+ device_destroy(voice_svc_class, device_num);
+dev_err:
+ class_destroy(voice_svc_class);
+class_err:
+ unregister_chrdev_region(0, MINOR_NUMBER);
+chrdev_err:
+ kfree(voice_svc_dev);
+done:
+ return ret;
+}
+
+static int voice_svc_remove(struct platform_device *pdev)
+{
+ pr_debug("%s\n", __func__);
+
+ cdev_del(voice_svc_dev->cdev);
+ kfree(voice_svc_dev->cdev);
+ device_destroy(voice_svc_class, device_num);
+ class_destroy(voice_svc_class);
+ unregister_chrdev_region(0, MINOR_NUMBER);
+ kfree(voice_svc_dev);
+
+ return 0;
+}
+
+static const struct of_device_id voice_svc_of_match[] = {
+ {.compatible = "qcom,msm-voice-svc"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, voice_svc_of_match);
+
+static struct platform_driver voice_svc_driver = {
+ .probe = voice_svc_probe,
+ .remove = voice_svc_remove,
+ .driver = {
+ .name = "msm-voice-svc",
+ .owner = THIS_MODULE,
+ .of_match_table = voice_svc_of_match,
+ },
+};
+
+static int __init voice_svc_init(void)
+{
+ pr_debug("%s\n", __func__);
+
+ return platform_driver_register(&voice_svc_driver);
+}
+
+static void __exit voice_svc_exit(void)
+{
+ pr_debug("%s\n", __func__);
+
+ platform_driver_unregister(&voice_svc_driver);
+}
+
+module_init(voice_svc_init);
+module_exit(voice_svc_exit);
+
+MODULE_DESCRIPTION("Soc QDSP6v2 Voice Service driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/clock/qcom,audio-ext-clk.h b/include/dt-bindings/clock/qcom,audio-ext-clk.h
new file mode 100644
index 0000000..c9a8286
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,audio-ext-clk.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __AUDIO_EXT_CLK_H
+#define __AUDIO_EXT_CLK_H
+
+/* Audio External Clocks */
+#ifdef CONFIG_COMMON_CLK_QCOM
+#define AUDIO_PMI_CLK 0
+#define AUDIO_PMIC_LNBB_CLK 1
+#define AUDIO_AP_CLK 2
+#define AUDIO_AP_CLK2 3
+#define AUDIO_LPASS_MCLK 4
+#define AUDIO_LPASS_MCLK2 5
+#else
+#define clk_audio_ap_clk 0x9b5727cb
+#define clk_audio_pmi_clk 0xcbfe416d
+#define clk_audio_ap_clk2 0x454d1e91
+#define clk_audio_lpass_mclk 0xf0f2a284
+#define clk_audio_pmi_lnbb_clk 0x57312343
+#endif
+
+#endif
diff --git a/include/linux/msm_audio_ion.h b/include/linux/msm_audio_ion.h
new file mode 100644
index 0000000..0761b88
--- /dev/null
+++ b/include/linux/msm_audio_ion.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_MSM_AUDIO_ION_H
+#define _LINUX_MSM_AUDIO_ION_H
+#include <sound/q6asm-v2.h>
+#include <sound/pcm.h>
+#include <linux/msm_ion.h>
+
+
+int msm_audio_ion_alloc(const char *name, struct ion_client **client,
+ struct ion_handle **handle, size_t bufsz,
+ ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr);
+
+int msm_audio_ion_import(const char *name, struct ion_client **client,
+ struct ion_handle **handle, int fd,
+ unsigned long *ionflag, size_t bufsz,
+ ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr);
+int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle);
+int msm_audio_ion_mmap(struct audio_buffer *substream,
+ struct vm_area_struct *vma);
+
+bool msm_audio_ion_is_smmu_available(void);
+int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op);
+
+struct ion_client *msm_audio_ion_client_create(const char *name);
+void msm_audio_ion_client_destroy(struct ion_client *client);
+int msm_audio_ion_import_legacy(const char *name, struct ion_client *client,
+ struct ion_handle **handle, int fd,
+ unsigned long *ionflag, size_t bufsz,
+ ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr);
+int msm_audio_ion_free_legacy(struct ion_client *client,
+ struct ion_handle *handle);
+u32 msm_audio_populate_upper_32_bits(ion_phys_addr_t pa);
+#endif /* _LINUX_MSM_AUDIO_ION_H */
diff --git a/include/linux/qdsp6v2/apr.h b/include/linux/qdsp6v2/apr.h
new file mode 100644
index 0000000..29deb3c
--- /dev/null
+++ b/include/linux/qdsp6v2/apr.h
@@ -0,0 +1,190 @@
+/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __APR_H_
+#define __APR_H_
+
+#include <linux/mutex.h>
+#include <soc/qcom/subsystem_notif.h>
+
+enum apr_subsys_state {
+ APR_SUBSYS_DOWN,
+ APR_SUBSYS_UP,
+ APR_SUBSYS_LOADED,
+};
+
+struct apr_q6 {
+ void *pil;
+ atomic_t q6_state;
+ atomic_t modem_state;
+ struct mutex lock;
+};
+
+struct apr_hdr {
+ uint16_t hdr_field;
+ uint16_t pkt_size;
+ uint8_t src_svc;
+ uint8_t src_domain;
+ uint16_t src_port;
+ uint8_t dest_svc;
+ uint8_t dest_domain;
+ uint16_t dest_port;
+ uint32_t token;
+ uint32_t opcode;
+};
+
+#define APR_HDR_LEN(hdr_len) ((hdr_len)/4)
+#define APR_PKT_SIZE(hdr_len, payload_len) ((hdr_len) + (payload_len))
+#define APR_HDR_FIELD(msg_type, hdr_len, ver)\
+ (((msg_type & 0x3) << 8) | ((hdr_len & 0xF) << 4) | (ver & 0xF))
+
+#define APR_HDR_SIZE sizeof(struct apr_hdr)
+
+/* Version */
+#define APR_PKT_VER 0x0
+
+/* Command and Response Types */
+#define APR_MSG_TYPE_EVENT 0x0
+#define APR_MSG_TYPE_CMD_RSP 0x1
+#define APR_MSG_TYPE_SEQ_CMD 0x2
+#define APR_MSG_TYPE_NSEQ_CMD 0x3
+#define APR_MSG_TYPE_MAX 0x04
+
+/* APR Basic Response Message */
+#define APR_BASIC_RSP_RESULT 0x000110E8
+#define APR_RSP_ACCEPTED 0x000100BE
+
+/* Domain IDs */
+#define APR_DOMAIN_SIM 0x1
+#define APR_DOMAIN_PC 0x2
+#define APR_DOMAIN_MODEM 0x3
+#define APR_DOMAIN_ADSP 0x4
+#define APR_DOMAIN_APPS 0x5
+#define APR_DOMAIN_MAX 0x6
+
+/* ADSP service IDs */
+#define APR_SVC_TEST_CLIENT 0x2
+#define APR_SVC_ADSP_CORE 0x3
+#define APR_SVC_AFE 0x4
+#define APR_SVC_VSM 0x5
+#define APR_SVC_VPM 0x6
+#define APR_SVC_ASM 0x7
+#define APR_SVC_ADM 0x8
+#define APR_SVC_ADSP_MVM 0x09
+#define APR_SVC_ADSP_CVS 0x0A
+#define APR_SVC_ADSP_CVP 0x0B
+#define APR_SVC_USM 0x0C
+#define APR_SVC_LSM 0x0D
+#define APR_SVC_VIDC 0x16
+#define APR_SVC_MAX 0x17
+
+/* Modem Service IDs */
+#define APR_SVC_MVS 0x3
+#define APR_SVC_MVM 0x4
+#define APR_SVC_CVS 0x5
+#define APR_SVC_CVP 0x6
+#define APR_SVC_SRD 0x7
+
+/* APR Port IDs */
+#define APR_MAX_PORTS 0x80
+
+#define APR_NAME_MAX 0x40
+
+#define RESET_EVENTS 0x000130D7
+
+#define LPASS_RESTART_EVENT 0x1000
+#define LPASS_RESTART_READY 0x1001
+
+struct apr_client_data {
+ uint16_t reset_event;
+ uint16_t reset_proc;
+ uint16_t payload_size;
+ uint16_t hdr_len;
+ uint16_t msg_type;
+ uint16_t src;
+ uint16_t dest_svc;
+ uint16_t src_port;
+ uint16_t dest_port;
+ uint32_t token;
+ uint32_t opcode;
+ void *payload;
+};
+
+typedef int32_t (*apr_fn)(struct apr_client_data *data, void *priv);
+
+struct apr_svc {
+ uint16_t id;
+ uint16_t dest_id;
+ uint16_t client_id;
+ uint16_t dest_domain;
+ uint8_t rvd;
+ uint8_t port_cnt;
+ uint8_t svc_cnt;
+ uint8_t need_reset;
+ apr_fn port_fn[APR_MAX_PORTS];
+ void *port_priv[APR_MAX_PORTS];
+ apr_fn fn;
+ void *priv;
+ struct mutex m_lock;
+ spinlock_t w_lock;
+ uint8_t pkt_owner;
+};
+
+struct apr_client {
+ uint8_t id;
+ uint8_t svc_cnt;
+ uint8_t rvd;
+ struct mutex m_lock;
+ struct apr_svc_ch_dev *handle;
+ struct apr_svc svc[APR_SVC_MAX];
+};
+
+struct apr_rx_intents {
+ int num_of_intents;
+ uint32_t size;
+};
+
+struct apr_pkt_cfg {
+ uint8_t pkt_owner;
+ struct apr_rx_intents intents;
+};
+
+int apr_load_adsp_image(void);
+struct apr_client *apr_get_client(int dest_id, int client_id);
+int apr_wait_for_device_up(int dest_id);
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+ int *svc_idx, int *svc_id);
+void apr_cb_func(void *buf, int len, void *priv);
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+ uint32_t src_port, void *priv);
+inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
+ uint16_t msg_type, uint16_t dest_port,
+ uint32_t token, uint32_t opcode, uint16_t len);
+
+int apr_send_pkt(void *handle, uint32_t *buf);
+int apr_deregister(void *handle);
+void subsys_notif_register(char *client_name, int domain,
+ struct notifier_block *nb);
+int apr_get_dest_id(char *dest);
+uint16_t apr_get_data_src(struct apr_hdr *hdr);
+void change_q6_state(int state);
+void q6audio_dsp_not_responding(void);
+void apr_reset(void *handle);
+enum apr_subsys_state apr_get_subsys_state(void);
+enum apr_subsys_state apr_get_modem_state(void);
+void apr_set_modem_state(enum apr_subsys_state state);
+enum apr_subsys_state apr_get_q6_state(void);
+int apr_set_q6_state(enum apr_subsys_state state);
+void apr_set_subsys_state(void);
+const char *apr_get_lpass_subsys_name(void);
+uint16_t apr_get_reset_domain(uint16_t proc);
+#endif
diff --git a/include/linux/qdsp6v2/apr_tal.h b/include/linux/qdsp6v2/apr_tal.h
new file mode 100644
index 0000000..32c977f
--- /dev/null
+++ b/include/linux/qdsp6v2/apr_tal.h
@@ -0,0 +1,108 @@
+/* Copyright (c) 2010-2011, 2016-2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __APR_TAL_H_
+#define __APR_TAL_H_
+
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+
+/* APR Client IDs */
+#define APR_CLIENT_AUDIO 0x0
+#define APR_CLIENT_VOICE 0x1
+#define APR_CLIENT_MAX 0x2
+
+#define APR_DL_SMD 0
+#define APR_DL_MAX 1
+
+#define APR_DEST_MODEM 0
+#define APR_DEST_QDSP6 1
+#define APR_DEST_MAX 2
+
+#if defined(CONFIG_MSM_QDSP6_APRV2_GLINK) || \
+ defined(CONFIG_MSM_QDSP6_APRV3_GLINK)
+#define APR_MAX_BUF 512
+#define APR_NUM_OF_TX_BUF 30
+#else
+#define APR_MAX_BUF 8092
+#endif
+
+#define APR_DEFAULT_NUM_OF_INTENTS 20
+
+#define APR_OPEN_TIMEOUT_MS 5000
+
+enum {
+ /* If client sets the pkt_owner to APR_PKT_OWNER_DRIVER, APR
+ * driver will allocate a buffer, where the user packet is
+ * copied into, for each and every single Tx transmission.
+ * The buffer is thereafter passed to underlying link layer
+ * and freed upon the notification received from the link layer
+ * that the packet has been consumed.
+ */
+ APR_PKT_OWNER_DRIVER,
+ /* If client sets the pkt_owner to APR_PKT_OWNER_CLIENT, APR
+ * will pass the user packet memory address directly to underlying
+ * link layer. In this case it is the client's responsibility to
+ * make sure the packet is intact until being notified that the
+ * packet has been consumed.
+ */
+ APR_PKT_OWNER_CLIENT,
+};
+
+struct apr_pkt_priv {
+ /* This property is only applicable for APR over Glink.
+ * It is ignored in APR over SMD cases.
+ */
+ uint8_t pkt_owner;
+};
+
+typedef void (*apr_svc_cb_fn)(void *buf, int len, void *priv);
+struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
+ uint32_t dl, apr_svc_cb_fn func, void *priv);
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
+ struct apr_pkt_priv *pkt_priv, int len);
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch);
+int apr_tal_rx_intents_config(struct apr_svc_ch_dev *apr_ch,
+ int num_of_intents, uint32_t size);
+
+
+#if defined(CONFIG_MSM_QDSP6_APRV2_GLINK) || \
+ defined(CONFIG_MSM_QDSP6_APRV3_GLINK)
+struct apr_svc_ch_dev {
+ void *handle;
+ spinlock_t w_lock;
+ spinlock_t r_lock;
+ struct mutex m_lock;
+ apr_svc_cb_fn func;
+ wait_queue_head_t wait;
+ void *priv;
+ unsigned int channel_state;
+ bool if_remote_intent_ready;
+};
+#else
+struct apr_svc_ch_dev {
+ struct smd_channel *ch;
+ spinlock_t lock;
+ spinlock_t w_lock;
+ struct mutex m_lock;
+ apr_svc_cb_fn func;
+ char data[APR_MAX_BUF];
+ wait_queue_head_t wait;
+ void *priv;
+ uint32_t smd_state;
+ wait_queue_head_t dest;
+ uint32_t dest_state;
+};
+#endif
+
+#endif
diff --git a/include/linux/qdsp6v2/apr_us.h b/include/linux/qdsp6v2/apr_us.h
new file mode 100644
index 0000000..9a6804a
--- /dev/null
+++ b/include/linux/qdsp6v2/apr_us.h
@@ -0,0 +1,193 @@
+/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __APR_US_H__
+#define __APR_US_H__
+
+#include <linux/qdsp6v2/apr.h>
+
+/* ======================================================================= */
+/* Session Level commands */
+
+#define USM_SESSION_CMD_RUN 0x00012306
+struct usm_stream_cmd_run {
+ struct apr_hdr hdr;
+ u32 flags;
+ u32 msw_ts;
+ u32 lsw_ts;
+} __packed;
+
+/* Stream level commands */
+#define USM_STREAM_CMD_OPEN_READ 0x00012309
+struct usm_stream_cmd_open_read {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 src_endpoint;
+ u32 pre_proc_top;
+ u32 format;
+} __packed;
+
+#define USM_STREAM_CMD_OPEN_WRITE 0x00011271
+struct usm_stream_cmd_open_write {
+ struct apr_hdr hdr;
+ u32 format;
+} __packed;
+
+
+#define USM_STREAM_CMD_CLOSE 0x0001230A
+
+#define USM_STREAM_CMD_SET_PARAM 0x00012731
+struct usm_stream_cmd_set_param {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+ u32 buf_addr_msw;
+ u32 mem_map_handle;
+ u32 buf_size;
+ u32 module_id;
+ u32 param_id;
+} __packed;
+
+#define USM_STREAM_CMD_GET_PARAM 0x00012732
+struct usm_stream_cmd_get_param {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+ u32 buf_addr_msw;
+ u32 mem_map_handle;
+ u32 buf_size;
+ u32 module_id;
+ u32 param_id;
+} __packed;
+
+/* Encoder configuration definitions */
+#define USM_STREAM_CMD_SET_ENC_PARAM 0x0001230B
+/* Decoder configuration definitions */
+#define USM_DATA_CMD_MEDIA_FORMAT_UPDATE 0x00011272
+
+/* Encoder/decoder configuration block */
+#define USM_PARAM_ID_ENCDEC_ENC_CFG_BLK 0x0001230D
+
+/* Max number of static located ports (bytes) */
+#define USM_MAX_PORT_NUMBER 8
+
+/* Max number of static located transparent data (bytes) */
+#define USM_MAX_CFG_DATA_SIZE 100
+
+/* Parameter structures used in USM_STREAM_CMD_SET_ENCDEC_PARAM command */
+/* common declarations */
+struct usm_cfg_common {
+ u16 ch_cfg;
+ u16 bits_per_sample;
+ u32 sample_rate;
+ u32 dev_id;
+ u8 data_map[USM_MAX_PORT_NUMBER];
+} __packed;
+
+struct us_encdec_cfg {
+ u32 format_id;
+ struct usm_cfg_common cfg_common;
+ u16 params_size;
+ u8 *params;
+} __packed;
+
+/* Start/stop US signal detection */
+#define USM_SESSION_CMD_SIGNAL_DETECT_MODE 0x00012719
+
+struct usm_session_cmd_detect_info {
+ struct apr_hdr hdr;
+ u32 detect_mode;
+ u32 skip_interval;
+ u32 algorithm_cfg_size;
+} __packed;
+
+/* US signal detection result */
+#define USM_SESSION_EVENT_SIGNAL_DETECT_RESULT 0x00012720
+
+/* ======================================================================= */
+/* Session Level commands */
+#define USM_CMD_SHARED_MEM_MAP_REGION 0x00012728
+struct usm_cmd_memory_map_region {
+ struct apr_hdr hdr;
+ u16 mempool_id;
+ u16 num_regions;
+ u32 flags;
+ u32 shm_addr_lsw;
+ u32 shm_addr_msw;
+ u32 mem_size_bytes;
+} __packed;
+
+#define USM_CMDRSP_SHARED_MEM_MAP_REGION 0x00012729
+struct usm_cmdrsp_memory_map_region {
+ u32 mem_map_handle;
+} __packed;
+
+#define USM_CMD_SHARED_MEM_UNMAP_REGION 0x0001272A
+struct usm_cmd_memory_unmap_region {
+ struct apr_hdr hdr;
+ u32 mem_map_handle;
+} __packed;
+
+#define USM_DATA_CMD_READ 0x00012724
+struct usm_stream_cmd_read {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+ u32 buf_addr_msw;
+ u32 mem_map_handle;
+ u32 buf_size;
+ u32 seq_id;
+ u32 counter;
+} __packed;
+
+#define USM_DATA_EVENT_READ_DONE 0x00012725
+
+#define USM_DATA_CMD_WRITE 0x00012726
+struct usm_stream_cmd_write {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+ u32 buf_addr_msw;
+ u32 mem_map_handle;
+ u32 buf_size;
+ u32 seq_id;
+ u32 res0;
+ u32 res1;
+ u32 res2;
+} __packed;
+
+#define USM_DATA_EVENT_WRITE_DONE 0x00012727
+
+struct usm_stream_media_format_update {
+ struct apr_hdr hdr;
+ u32 format_id;
+ /* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+ u32 cfg_size;
+ struct usm_cfg_common cfg_common;
+ /* Transparent configuration data for specific encoder */
+ u8 transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_encode_cfg_blk {
+ u32 frames_per_buf;
+ u32 format_id;
+ /* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+ u32 cfg_size;
+ struct usm_cfg_common cfg_common;
+ /* Transparent configuration data for specific encoder */
+ u8 transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_stream_cmd_encdec_cfg_blk {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct usm_encode_cfg_blk enc_blk;
+} __packed;
+
+#endif /* __APR_US_H__ */
diff --git a/include/linux/qdsp6v2/audio_notifier.h b/include/linux/qdsp6v2/audio_notifier.h
new file mode 100644
index 0000000..3587b49
--- /dev/null
+++ b/include/linux/qdsp6v2/audio_notifier.h
@@ -0,0 +1,105 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __AUDIO_NOTIFIER_H_
+#define __AUDIO_NOTIFIER_H_
+
+/* State of the notifier domain */
+enum {
+ AUDIO_NOTIFIER_SERVICE_DOWN,
+ AUDIO_NOTIFIER_SERVICE_UP
+};
+
+/* Service order determines connection priority
+ * Highest number connected first
+ */
+enum {
+ AUDIO_NOTIFIER_SSR_SERVICE,
+ AUDIO_NOTIFIER_PDR_SERVICE,
+ AUDIO_NOTIFIER_MAX_SERVICES
+};
+
+enum {
+ AUDIO_NOTIFIER_ADSP_DOMAIN,
+ AUDIO_NOTIFIER_MODEM_DOMAIN,
+ AUDIO_NOTIFIER_MAX_DOMAINS
+};
+
+/* Structure populated in void *data of nb function
+ * callback used for audio_notifier_register
+ */
+struct audio_notifier_cb_data {
+ int service;
+ int domain;
+};
+
+#ifdef CONFIG_MSM_QDSP6_NOTIFIER
+
+/*
+ * Use audio_notifier_register to register any audio
+ * clients who need to be notified of a remote process.
+ * This API will determine and register the client with
+ * the best available subsystem (SSR or PDR) for that
+ * domain (Adsp or Modem). When an event is sent from that
+ * domain the notifier block callback function will be called.
+ *
+ * client_name - A unique user name defined by the client.
+ * If the same name is used for multiple calls each will
+ * be tracked & called back separately and a single call
+ * to deregister will delete them all.
+ * domain - Domain the client wants to get events from.
+ * AUDIO_NOTIFIER_ADSP_DOMAIN
+ * AUDIO_NOTIFIER_MODEM_DOMAIN
+ * *nb - Pointer to a notifier block. Provide a callback function
+ * to be notified of an even on that domain.
+ *
+ * nb_func(struct notifier_block *this, unsigned long opcode, void *data)
+ * this - pointer to own nb
+ * opcode - event from registered domain
+ * AUDIO_NOTIFIER_SERVICE_DOWN
+ * AUDIO_NOTIFIER_SERVICE_UP
+ * *data - pointer to struct audio_notifier_cb_data
+ *
+ * Returns: Success: 0
+ * Error: -#
+ */
+int audio_notifier_register(char *client_name, int domain,
+ struct notifier_block *nb);
+
+/*
+ * Use audio_notifier_deregister to deregister the clients from
+ * all domains registered using audio_notifier_register that
+ * match the client name.
+ *
+ * client_name - Unique user name used in audio_notifier_register.
+ * Returns: Success: 0
+ * Error: -#
+ */
+int audio_notifier_deregister(char *client_name);
+
+#else
+
+static inline int audio_notifier_register(char *client_name, int domain,
+ struct notifier_block *nb)
+{
+ return -ENODEV;
+}
+
+static inline int audio_notifier_deregister(char *client_name)
+{
+ return 0;
+}
+
+#endif /* CONFIG_MSM_QDSP6_PDR */
+
+#endif
diff --git a/include/linux/qdsp6v2/audio_pdr.h b/include/linux/qdsp6v2/audio_pdr.h
new file mode 100644
index 0000000..ebfd366
--- /dev/null
+++ b/include/linux/qdsp6v2/audio_pdr.h
@@ -0,0 +1,101 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __AUDIO_PDR_H_
+#define __AUDIO_PDR_H_
+
+enum {
+ AUDIO_PDR_DOMAIN_ADSP,
+ AUDIO_PDR_DOMAIN_MAX
+};
+
+enum {
+ AUDIO_PDR_FRAMEWORK_DOWN,
+ AUDIO_PDR_FRAMEWORK_UP
+};
+
+#ifdef CONFIG_MSM_QDSP6_PDR
+
+/*
+ * Use audio_pdr_register to register with the PDR subsystem this
+ * should be done before module late init otherwise notification
+ * of the AUDIO_PDR_FRAMEWORK_UP cannot be guaranteed.
+ *
+ * *nb - Pointer to a notifier block. Provide a callback function
+ * to be notified once the PDR framework has been initialized.
+ * Callback will receive either the AUDIO_PDR_FRAMEWORK_DOWN
+ * or AUDIO_PDR_FRAMEWORK_UP ioctl depending on the state of
+ * the PDR framework.
+ *
+ * Returns: Success: 0
+ * Failure: Error code
+ */
+int audio_pdr_register(struct notifier_block *nb);
+
+/*
+ * Use audio_pdr_service_register to register with a PDR service
+ * Function should be called after nb callback registered with
+ * audio_pdr_register has been called back with the
+ * AUDIO_PDR_FRAMEWORK_UP ioctl.
+ *
+ * domain_id - Domain to use, example: AUDIO_PDR_ADSP
+ * *nb - Pointer to a notifier block. Provide a callback function
+ * that will be notified of the state of the domain
+ * requested. The ioctls received by the callback are
+ * defined in service-notifier.h.
+ *
+ * Returns: Success: Client handle
+ * Failure: Pointer error code
+ */
+void *audio_pdr_service_register(int domain_id,
+ struct notifier_block *nb, int *curr_state);
+
+/*
+ * Use audio_pdr_service_deregister to deregister with a PDR
+ * service that was registered using the audio_pdr_service_register
+ * API.
+ *
+ * *service_handle - Service handle returned by audio_pdr_service_register
+ * *nb - Pointer to the notifier block. Used in the call to
+ * audio_pdr_service_register.
+ *
+ * Returns: Success: Client handle
+ * Failure: Error code
+ */
+int audio_pdr_service_deregister(void *service_handle,
+ struct notifier_block *nb);
+
+#else
+
+static inline int audio_pdr_register(struct notifier_block *nb)
+{
+ return -ENODEV;
+}
+
+
+static inline void *audio_pdr_service_register(int domain_id,
+ struct notifier_block *nb,
+ int *curr_state)
+{
+ return NULL;
+}
+
+static inline int audio_pdr_service_deregister(void *service_handle,
+ struct notifier_block *nb)
+{
+ return 0;
+}
+
+#endif /* CONFIG_MSM_QDSP6_PDR */
+
+#endif
diff --git a/include/linux/qdsp6v2/audio_ssr.h b/include/linux/qdsp6v2/audio_ssr.h
new file mode 100644
index 0000000..a807021
--- /dev/null
+++ b/include/linux/qdsp6v2/audio_ssr.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __AUDIO_SSR_H_
+#define __AUDIO_SSR_H_
+
+enum {
+ AUDIO_SSR_DOMAIN_ADSP,
+ AUDIO_SSR_DOMAIN_MODEM,
+ AUDIO_SSR_DOMAIN_MAX
+};
+
+#ifdef CONFIG_MSM_QDSP6_SSR
+
+/*
+ * Use audio_ssr_register to register with the SSR subsystem
+ *
+ * domain_id - Service to use, example: AUDIO_SSR_DOMAIN_ADSP
+ * *nb - Pointer to a notifier block. Provide a callback function
+ * to be notified of an event for that service. The ioctls
+ * used by the callback are defined in subsystem_notif.h.
+ *
+ * Returns: Success: Client handle
+ * Failure: Pointer error code
+ */
+void *audio_ssr_register(int domain_id, struct notifier_block *nb);
+
+/*
+ * Use audio_ssr_deregister to register with the SSR subsystem
+ *
+ * handle - Handle received from audio_ssr_register
+ * *nb - Pointer to a notifier block. Callback function
+ * Used from audio_ssr_register.
+ *
+ * Returns: Success: 0
+ * Failure: Error code
+ */
+int audio_ssr_deregister(void *handle, struct notifier_block *nb);
+
+
+/*
+ * Use audio_ssr_send_nmi to force a RAM dump on ADSP
+ * down event.
+ *
+ * *ssr_cb_data - *data received from notifier callback
+ */
+void audio_ssr_send_nmi(void *ssr_cb_data);
+
+#else
+
+static inline void *audio_ssr_register(int domain_id,
+ struct notifier_block *nb)
+{
+ return NULL;
+}
+
+static inline int audio_ssr_deregister(void *handle, struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline void audio_ssr_send_nmi(void *ssr_cb_data)
+{
+}
+
+#endif /* CONFIG_MSM_QDSP6_SSR */
+
+#endif
diff --git a/include/linux/qdsp6v2/dsp_debug.h b/include/linux/qdsp6v2/dsp_debug.h
new file mode 100644
index 0000000..bc1cd9e
--- /dev/null
+++ b/include/linux/qdsp6v2/dsp_debug.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __DSP_DEBUG_H_
+#define __DSP_DEBUG_H_
+
+typedef int (*dsp_state_cb)(int state);
+int dsp_debug_register(dsp_state_cb ptr);
+
+#define DSP_STATE_CRASHED 0x0
+#define DSP_STATE_CRASH_DUMP_DONE 0x1
+
+#endif
diff --git a/include/linux/qdsp6v2/rtac.h b/include/linux/qdsp6v2/rtac.h
new file mode 100644
index 0000000..3e5433b
--- /dev/null
+++ b/include/linux/qdsp6v2/rtac.h
@@ -0,0 +1,98 @@
+/* Copyright (c) 2011, 2013-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __RTAC_H__
+#define __RTAC_H__
+
+#include <sound/apr_audio-v2.h>
+
+/* Voice Modes */
+#define RTAC_CVP 0
+#define RTAC_CVS 1
+#define RTAC_VOICE_MODES 2
+
+#define RTAC_MAX_ACTIVE_DEVICES 4
+#define RTAC_MAX_ACTIVE_POPP 8
+
+#define DEFAULT_APP_TYPE 0x00011130
+
+enum {
+ ADM_RTAC_CAL,
+ ASM_RTAC_CAL,
+ VOICE_RTAC_CAL,
+ AFE_RTAC_CAL,
+ MAX_RTAC_BLOCKS
+};
+
+struct rtac_cal_mem_map_data {
+ uint32_t map_size;
+ uint32_t map_handle;
+ struct ion_client *ion_client;
+ struct ion_handle *ion_handle;
+};
+
+struct rtac_cal_data {
+ size_t size;
+ void *kvaddr;
+ phys_addr_t paddr;
+};
+
+struct rtac_cal_block_data {
+ struct rtac_cal_mem_map_data map_data;
+ struct rtac_cal_data cal_data;
+};
+
+struct rtac_popp_data {
+ uint32_t popp;
+ uint32_t popp_topology;
+ uint32_t app_type;
+};
+
+struct rtac_adm_data {
+ uint32_t topology_id;
+ uint32_t afe_topology;
+ uint32_t afe_port;
+ uint32_t copp;
+ uint32_t num_of_popp;
+ uint32_t app_type;
+ uint32_t acdb_dev_id;
+ struct rtac_popp_data popp[RTAC_MAX_ACTIVE_POPP];
+};
+
+struct rtac_adm {
+ uint32_t num_of_dev;
+ struct rtac_adm_data device[RTAC_MAX_ACTIVE_DEVICES];
+};
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id,
+ u32 app_type, u32 acdb_dev_id);
+void rtac_remove_adm_device(u32 port_id, u32 copp_id);
+void rtac_remove_popp_from_adm_devices(u32 popp_id);
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+ u32 tx_afe_port, u32 rx_acdb_id, u32 tx_acdb_id, u32 session_id);
+void rtac_remove_voice(u32 cvs_handle);
+void rtac_set_adm_handle(void *handle);
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size);
+void rtac_copy_adm_payload_to_user(void *payload, u32 payload_size);
+void rtac_set_asm_handle(u32 session_id, void *handle);
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+ u32 payload_size);
+void rtac_copy_asm_payload_to_user(void *payload, u32 payload_size);
+void rtac_set_voice_handle(u32 mode, void *handle);
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size);
+void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size);
+int rtac_clear_mapping(uint32_t cal_type);
+bool rtac_make_afe_callback(uint32_t *payload, u32 payload_size);
+void rtac_set_afe_handle(void *handle);
+void get_rtac_adm_data(struct rtac_adm *adm_data);
+#endif
diff --git a/include/linux/qdsp6v2/usf.h b/include/linux/qdsp6v2/usf.h
new file mode 100644
index 0000000..544b624
--- /dev/null
+++ b/include/linux/qdsp6v2/usf.h
@@ -0,0 +1,298 @@
+/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __USF_H__
+#define __USF_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define USF_IOCTL_MAGIC 'U'
+
+#define US_SET_TX_INFO _IOW(USF_IOCTL_MAGIC, 0, \
+ struct us_tx_info_type)
+#define US_START_TX _IO(USF_IOCTL_MAGIC, 1)
+#define US_GET_TX_UPDATE _IOWR(USF_IOCTL_MAGIC, 2, \
+ struct us_tx_update_info_type)
+#define US_SET_RX_INFO _IOW(USF_IOCTL_MAGIC, 3, \
+ struct us_rx_info_type)
+#define US_SET_RX_UPDATE _IOWR(USF_IOCTL_MAGIC, 4, \
+ struct us_rx_update_info_type)
+#define US_START_RX _IO(USF_IOCTL_MAGIC, 5)
+
+#define US_STOP_TX _IO(USF_IOCTL_MAGIC, 6)
+#define US_STOP_RX _IO(USF_IOCTL_MAGIC, 7)
+
+#define US_SET_DETECTION _IOWR(USF_IOCTL_MAGIC, 8, \
+ struct us_detect_info_type)
+
+#define US_GET_VERSION _IOWR(USF_IOCTL_MAGIC, 9, \
+ struct us_version_info_type)
+
+#define US_SET_TX_STREAM_PARAM _IOW(USF_IOCTL_MAGIC, 10, \
+ struct us_stream_param_type)
+#define US_GET_TX_STREAM_PARAM _IOWR(USF_IOCTL_MAGIC, 11, \
+ struct us_stream_param_type)
+#define US_SET_RX_STREAM_PARAM _IOW(USF_IOCTL_MAGIC, 12, \
+ struct us_stream_param_type)
+#define US_GET_RX_STREAM_PARAM _IOWR(USF_IOCTL_MAGIC, 13, \
+ struct us_stream_param_type)
+
+/* Special timeout values */
+#define USF_NO_WAIT_TIMEOUT 0x00000000
+/* Infinitive */
+#define USF_INFINITIVE_TIMEOUT 0xffffffff
+/* Default value, used by the driver */
+#define USF_DEFAULT_TIMEOUT 0xfffffffe
+
+/* US detection place (HW|FW) */
+enum us_detect_place_enum {
+/* US is detected in HW */
+ US_DETECT_HW,
+/* US is detected in FW */
+ US_DETECT_FW
+};
+
+/* US detection mode */
+enum us_detect_mode_enum {
+/* US detection is disabled */
+ US_DETECT_DISABLED_MODE,
+/* US detection is enabled in continue mode */
+ US_DETECT_CONTINUE_MODE,
+/* US detection is enabled in one shot mode */
+ US_DETECT_SHOT_MODE
+};
+
+/* Encoder (TX), decoder (RX) supported US data formats */
+#define USF_POINT_EPOS_FORMAT 0
+#define USF_RAW_FORMAT 1
+
+/* Indexes of event types, produced by the calculators */
+#define USF_TSC_EVENT_IND 0
+#define USF_TSC_PTR_EVENT_IND 1
+#define USF_MOUSE_EVENT_IND 2
+#define USF_KEYBOARD_EVENT_IND 3
+#define USF_TSC_EXT_EVENT_IND 4
+#define USF_MAX_EVENT_IND 5
+
+/* Types of events, produced by the calculators */
+#define USF_NO_EVENT 0
+#define USF_TSC_EVENT (1 << USF_TSC_EVENT_IND)
+#define USF_TSC_PTR_EVENT (1 << USF_TSC_PTR_EVENT_IND)
+#define USF_MOUSE_EVENT (1 << USF_MOUSE_EVENT_IND)
+#define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_TSC_EXT_EVENT (1 << USF_TSC_EXT_EVENT_IND)
+#define USF_ALL_EVENTS (USF_TSC_EVENT |\
+ USF_TSC_PTR_EVENT |\
+ USF_MOUSE_EVENT |\
+ USF_KEYBOARD_EVENT |\
+ USF_TSC_EXT_EVENT)
+
+/* min, max array dimension */
+#define MIN_MAX_DIM 2
+
+/* coordinates (x,y,z) array dimension */
+#define COORDINATES_DIM 3
+
+/* tilts (x,y) array dimension */
+#define TILTS_DIM 2
+
+/* Max size of the client name */
+#define USF_MAX_CLIENT_NAME_SIZE 20
+
+/* Max number of the ports (mics/speakers) */
+#define USF_MAX_PORT_NUM 8
+
+/* Info structure common for TX and RX */
+struct us_xx_info_type {
+/* Input: general info */
+/* Name of the client - event calculator */
+ const char __user *client_name;
+/* Selected device identification, accepted in the kernel's CAD */
+ uint32_t dev_id;
+/* 0 - point_epos type; (e.g. 1 - gr_mmrd) */
+ uint32_t stream_format;
+/* Required sample rate in Hz */
+ uint32_t sample_rate;
+/* Size of a buffer (bytes) for US data transfer between the module and USF */
+ uint32_t buf_size;
+/* Number of the buffers for the US data transfer */
+ uint16_t buf_num;
+/* Number of the microphones (TX) or speakers(RX) */
+ uint16_t port_cnt;
+/* Microphones(TX) or speakers(RX) indexes in their enumeration */
+ uint8_t port_id[USF_MAX_PORT_NUM];
+/* Bits per sample 16 or 32 */
+ uint16_t bits_per_sample;
+/* Input: Transparent info for encoder in the LPASS */
+/* Parameters data size in bytes */
+ uint16_t params_data_size;
+/* Pointer to the parameters */
+ uint8_t __user *params_data;
+/* Max size of buffer for get and set parameter */
+ uint32_t max_get_set_param_buf_size;
+};
+
+struct us_input_info_type {
+ /* Touch screen dimensions: min & max;for input module */
+ int tsc_x_dim[MIN_MAX_DIM];
+ int tsc_y_dim[MIN_MAX_DIM];
+ int tsc_z_dim[MIN_MAX_DIM];
+ /* Touch screen tilt dimensions: min & max;for input module */
+ int tsc_x_tilt[MIN_MAX_DIM];
+ int tsc_y_tilt[MIN_MAX_DIM];
+ /* Touch screen pressure limits: min & max; for input module */
+ int tsc_pressure[MIN_MAX_DIM];
+ /* The requested buttons bitmap */
+ uint16_t req_buttons_bitmap;
+ /* Bitmap of types of events (USF_X_EVENT), produced by calculator */
+ uint16_t event_types;
+ /* Bitmap of types of events from devs, conflicting with USF */
+ uint16_t conflicting_event_types;
+};
+
+struct us_tx_info_type {
+ /* Common info */
+ struct us_xx_info_type us_xx_info;
+ /* Info specific for TX*/
+ struct us_input_info_type input_info;
+};
+
+struct us_rx_info_type {
+ /* Common info */
+ struct us_xx_info_type us_xx_info;
+ /* Info specific for RX*/
+};
+
+struct point_event_type {
+/* Pen coordinates (x, y, z) in units, defined by <coordinates_type> */
+ int coordinates[COORDINATES_DIM];
+ /* {x;y} in transparent units */
+ int inclinations[TILTS_DIM];
+/* [0-1023] (10bits); 0 - pen up */
+ uint32_t pressure;
+/* Bitmap for button state. 1 - down, 0 - up */
+ uint16_t buttons_state_bitmap;
+};
+
+/* Mouse buttons, supported by USF */
+#define USF_BUTTON_LEFT_MASK 1
+#define USF_BUTTON_MIDDLE_MASK 2
+#define USF_BUTTON_RIGHT_MASK 4
+struct mouse_event_type {
+/* The mouse relative movement (dX, dY, dZ) */
+ int rels[COORDINATES_DIM];
+/* Bitmap of mouse buttons states: 1 - down, 0 - up; */
+ uint16_t buttons_states;
+};
+
+struct key_event_type {
+/* Calculated MS key- see input.h. */
+ uint32_t key;
+/* Keyboard's key state: 1 - down, 0 - up; */
+ uint8_t key_state;
+};
+
+struct usf_event_type {
+/* Event sequence number */
+ uint32_t seq_num;
+/* Event generation system time */
+ uint32_t timestamp;
+/* Destination input event type index (e.g. touch screen, mouse, key) */
+ uint16_t event_type_ind;
+ union {
+ struct point_event_type point_event;
+ struct mouse_event_type mouse_event;
+ struct key_event_type key_event;
+ } event_data;
+};
+
+struct us_tx_update_info_type {
+/* Input general: */
+/* Number of calculated events */
+ uint16_t event_counter;
+/* Calculated events or NULL */
+ struct usf_event_type __user *event;
+/* Pointer (read index) to the end of available region */
+/* in the shared US data memory */
+ uint32_t free_region;
+/* Time (sec) to wait for data or special values: */
+/* USF_NO_WAIT_TIMEOUT, USF_INFINITIVE_TIMEOUT, USF_DEFAULT_TIMEOUT */
+ uint32_t timeout;
+/* Events (from conflicting devs) to be disabled/enabled */
+ uint16_t event_filters;
+
+/* Input transparent data: */
+/* Parameters size */
+ uint16_t params_data_size;
+/* Pointer to the parameters */
+ uint8_t __user *params_data;
+/* Output parameters: */
+/* Pointer (write index) to the end of ready US data region */
+/* in the shared memory */
+ uint32_t ready_region;
+};
+
+struct us_rx_update_info_type {
+/* Input general: */
+/* Pointer (write index) to the end of ready US data region */
+/* in the shared memory */
+ uint32_t ready_region;
+/* Input transparent data: */
+/* Parameters size */
+ uint16_t params_data_size;
+/* pPointer to the parameters */
+ uint8_t __user *params_data;
+/* Output parameters: */
+/* Pointer (read index) to the end of available region */
+/* in the shared US data memory */
+ uint32_t free_region;
+};
+
+struct us_detect_info_type {
+/* US detection place (HW|FW) */
+/* NA in the Active and OFF states */
+ enum us_detect_place_enum us_detector;
+/* US detection mode */
+ enum us_detect_mode_enum us_detect_mode;
+/* US data dropped during this time (msec) */
+ uint32_t skip_time;
+/* Transparent data size */
+ uint16_t params_data_size;
+/* Pointer to the transparent data */
+ uint8_t __user *params_data;
+/* Time (sec) to wait for US presence event */
+ uint32_t detect_timeout;
+/* Out parameter: US presence */
+ bool is_us;
+};
+
+struct us_version_info_type {
+/* Size of memory for the version string */
+ uint16_t buf_size;
+/* Pointer to the memory for the version string */
+ char __user *pbuf;
+};
+
+struct us_stream_param_type {
+/* Id of module */
+ uint32_t module_id;
+/* Id of parameter */
+ uint32_t param_id;
+/* Size of memory of the parameter buffer */
+ uint32_t buf_size;
+/* Pointer to the memory of the parameter buffer */
+ uint8_t __user *pbuf;
+};
+
+#endif /* __USF_H__ */
diff --git a/include/soc/qcom/liquid_dock.h b/include/soc/qcom/liquid_dock.h
new file mode 100644
index 0000000..3668224
--- /dev/null
+++ b/include/soc/qcom/liquid_dock.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/notifier.h>
+
+#if IS_ENABLED(CONFIG_QCOM_LIQUID_DOCK)
+void register_liquid_dock_notify(struct notifier_block *nb);
+void unregister_liquid_dock_notify(struct notifier_block *nb);
+#else
+static inline void register_liquid_dock_notify(struct notifier_block *nb) { }
+static inline void unregister_liquid_dock_notify(struct notifier_block *nb) { }
+#endif
diff --git a/include/sound/adsp_err.h b/include/sound/adsp_err.h
new file mode 100644
index 0000000..43be91d
--- /dev/null
+++ b/include/sound/adsp_err.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ADSP_ERR__
+#define __ADSP_ERR__
+
+int adsp_err_get_lnx_err_code(u32 adsp_error);
+
+char *adsp_err_get_err_str(u32 adsp_error);
+
+#endif
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
new file mode 100644
index 0000000..812ea65
--- /dev/null
+++ b/include/sound/apr_audio-v2.h
@@ -0,0 +1,9901 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _APR_AUDIO_V2_H_
+#define _APR_AUDIO_V2_H_
+
+#include <linux/qdsp6v2/apr.h>
+
+/* size of header needed for passing data out of band */
+#define APR_CMD_OB_HDR_SZ 12
+
+/* size of header needed for getting data */
+#define APR_CMD_GET_HDR_SZ 16
+
+struct param_outband {
+ size_t size;
+ void *kvaddr;
+ phys_addr_t paddr;
+};
+
+#define ADSP_ADM_VERSION 0x00070000
+
+#define ADM_CMD_SHARED_MEM_MAP_REGIONS 0x00010322
+#define ADM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010323
+#define ADM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010324
+
+#define ADM_CMD_MATRIX_MAP_ROUTINGS_V5 0x00010325
+#define ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5 0x0001033D
+/* Enumeration for an audio Rx matrix ID.*/
+#define ADM_MATRIX_ID_AUDIO_RX 0
+
+#define ADM_MATRIX_ID_AUDIO_TX 1
+
+#define ADM_MATRIX_ID_COMPRESSED_AUDIO_RX 2
+/* Enumeration for an audio Tx matrix ID.*/
+#define ADM_MATRIX_ID_AUDIOX 1
+
+#define ADM_MAX_COPPS 5
+
+/* make sure this matches with msm_audio_calibration */
+#define SP_V2_NUM_MAX_SPKR 2
+
+/* Session map node structure.
+ * Immediately following this structure are num_copps
+ * entries of COPP IDs. The COPP IDs are 16 bits, so
+ * there might be a padding 16-bit field if num_copps
+ * is odd.
+ */
+struct adm_session_map_node_v5 {
+ u16 session_id;
+ /* Handle of the ASM session to be routed. Supported values: 1
+ * to 8.
+ */
+
+
+ u16 num_copps;
+ /* Number of COPPs to which this session is to be routed.
+ * Supported values: 0 < num_copps <= ADM_MAX_COPPS.
+ */
+} __packed;
+
+/* Payload of the #ADM_CMD_MATRIX_MAP_ROUTINGS_V5 command.
+ * Immediately following this structure are num_sessions of the session map
+ * node payload (adm_session_map_node_v5).
+ */
+
+struct adm_cmd_matrix_map_routings_v5 {
+ struct apr_hdr hdr;
+
+ u32 matrix_id;
+ /* Specifies whether the matrix ID is Audio Rx (0) or Audio Tx
+ * (1). Use the ADM_MATRIX_ID_AUDIO_RX or ADM_MATRIX_ID_AUDIOX
+ * macros to set this field.
+ */
+ u32 num_sessions;
+ /* Number of sessions being updated by this command (optional). */
+} __packed;
+
+/* This command allows a client to open a COPP/Voice Proc. TX module
+ * and sets up the device session: Matrix -> COPP -> AFE on the RX
+ * and AFE -> COPP -> Matrix on the TX. This enables PCM data to
+ * be transferred to/from the endpoint (AFEPortID).
+ *
+ * @return
+ * #ADM_CMDRSP_DEVICE_OPEN_V5 with the resulting status and COPP ID.
+ */
+#define ADM_CMD_DEVICE_OPEN_V5 0x00010326
+
+/* Definition for a low latency stream session. */
+#define ADM_LOW_LATENCY_DEVICE_SESSION 0x2000
+
+/* Definition for a ultra low latency stream session. */
+#define ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION 0x4000
+
+/* Definition for a ultra low latency with Post Processing stream session. */
+#define ADM_ULL_POST_PROCESSING_DEVICE_SESSION 0x8000
+
+/* Definition for a legacy device session. */
+#define ADM_LEGACY_DEVICE_SESSION 0
+
+/* Indicates that endpoint_id_2 is to be ignored.*/
+#define ADM_CMD_COPP_OPEN_END_POINT_ID_2_IGNORE 0xFFFF
+
+#define ADM_CMD_COPP_OPEN_MODE_OF_OPERATION_RX_PATH_COPP 1
+
+#define ADM_CMD_COPP_OPEN_MODE_OF_OPERATIONX_PATH_LIVE_COPP 2
+
+#define ADM_CMD_COPP_OPEN_MODE_OF_OPERATIONX_PATH_NON_LIVE_COPP 3
+
+/* Indicates that an audio COPP is to send/receive a mono PCM
+ * stream to/from
+ * END_POINT_ID_1.
+ */
+#define ADM_CMD_COPP_OPEN_CHANNEL_CONFIG_MONO 1
+
+/* Indicates that an audio COPP is to send/receive a
+ * stereo PCM stream to/from END_POINT_ID_1.
+ */
+#define ADM_CMD_COPP_OPEN_CHANNEL_CONFIG_STEREO 2
+
+/* Sample rate is 8000 Hz.*/
+#define ADM_CMD_COPP_OPEN_SAMPLE_RATE_8K 8000
+
+/* Sample rate is 16000 Hz.*/
+#define ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K 16000
+
+/* Sample rate is 48000 Hz.*/
+#define ADM_CMD_COPP_OPEN_SAMPLE_RATE_48K 48000
+
+/* Definition for a COPP live input flag bitmask.*/
+#define ADM_BIT_MASK_COPP_LIVE_INPUT_FLAG (0x0001U)
+
+/* Definition for a COPP live shift value bitmask.*/
+#define ADM_SHIFT_COPP_LIVE_INPUT_FLAG 0
+
+/* Definition for the COPP ID bitmask.*/
+#define ADM_BIT_MASK_COPP_ID (0x0000FFFFUL)
+
+/* Definition for the COPP ID shift value.*/
+#define ADM_SHIFT_COPP_ID 0
+
+/* Definition for the service ID bitmask.*/
+#define ADM_BIT_MASK_SERVICE_ID (0x00FF0000UL)
+
+/* Definition for the service ID shift value.*/
+#define ADM_SHIFT_SERVICE_ID 16
+
+/* Definition for the domain ID bitmask.*/
+#define ADM_BIT_MASK_DOMAIN_ID (0xFF000000UL)
+
+/* Definition for the domain ID shift value.*/
+#define ADM_SHIFT_DOMAIN_ID 24
+
+/* ADM device open command payload of the
+ * #ADM_CMD_DEVICE_OPEN_V5 command.
+ */
+struct adm_cmd_device_open_v5 {
+ struct apr_hdr hdr;
+ u16 flags;
+/* Reserved for future use. Clients must set this field
+ * to zero.
+ */
+
+ u16 mode_of_operation;
+/* Specifies whether the COPP must be opened on the Tx or Rx
+ * path. Use the ADM_CMD_COPP_OPEN_MODE_OF_OPERATION_* macros for
+ * supported values and interpretation.
+ * Supported values:
+ * - 0x1 -- Rx path COPP
+ * - 0x2 -- Tx path live COPP
+ * - 0x3 -- Tx path nonlive COPP
+ * Live connections cause sample discarding in the Tx device
+ * matrix if the destination output ports do not pull them
+ * fast enough. Nonlive connections queue the samples
+ * indefinitely.
+ */
+
+ u16 endpoint_id_1;
+/* Logical and physical endpoint ID of the audio path.
+ * If the ID is a voice processor Tx block, it receives near
+ * samples. Supported values: Any pseudoport, AFE Rx port,
+ * or AFE Tx port For a list of valid IDs, refer to
+ * @xhyperref{Q4,[Q4]}.
+ * Q4 = Hexagon Multimedia: AFE Interface Specification
+ */
+
+ u16 endpoint_id_2;
+/* Logical and physical endpoint ID 2 for a voice processor
+ * Tx block.
+ * This is not applicable to audio COPP.
+ * Supported values:
+ * - AFE Rx port
+ * - 0xFFFF -- Endpoint 2 is unavailable and the voice
+ * processor Tx
+ * block ignores this endpoint
+ * When the voice processor Tx block is created on the audio
+ * record path,
+ * it can receive far-end samples from an AFE Rx port if the
+ * voice call
+ * is active. The ID of the AFE port is provided in this
+ * field.
+ * For a list of valid IDs, refer @xhyperref{Q4,[Q4]}.
+ */
+
+ u32 topology_id;
+/* Audio COPP topology ID; 32-bit GUID. */
+
+ u16 dev_num_channel;
+/* Number of channels the audio COPP sends to/receives from
+ * the endpoint.
+ * Supported values: 1 to 8.
+ * The value is ignored for the voice processor Tx block,
+ * where channel
+ * configuration is derived from the topology ID.
+ */
+
+ u16 bit_width;
+/* Bit width (in bits) that the audio COPP sends to/receives
+ * from the
+ * endpoint. The value is ignored for the voice processing
+ * Tx block,
+ * where the PCM width is 16 bits.
+ */
+
+ u32 sample_rate;
+/* Sampling rate at which the audio COPP/voice processor
+ * Tx block
+ * interfaces with the endpoint.
+ * Supported values for voice processor Tx: 8000, 16000,
+ * 48000 Hz
+ * Supported values for audio COPP: >0 and <=192 kHz
+ */
+
+ u8 dev_channel_mapping[8];
+/* Array of channel mapping of buffers that the audio COPP
+ * sends to the endpoint. Channel[i] mapping describes channel
+ * I inside the buffer, where 0 < i < dev_num_channel.
+ * This value is relevant only for an audio Rx COPP.
+ * For the voice processor block and Tx audio block, this field
+ * is set to zero and is ignored.
+ */
+} __packed;
+
+/*
+ * This command allows the client to close a COPP and disconnect
+ * the device session.
+ */
+#define ADM_CMD_DEVICE_CLOSE_V5 0x00010327
+
+/* Sets one or more parameters to a COPP. */
+#define ADM_CMD_SET_PP_PARAMS_V5 0x00010328
+
+/* Payload of the #ADM_CMD_SET_PP_PARAMS_V5 command.
+ * If the data_payload_addr_lsw and data_payload_addr_msw element
+ * are NULL, a series of adm_param_datastructures immediately
+ * follows, whose total size is data_payload_size bytes.
+ */
+struct adm_cmd_set_pp_params_v5 {
+ struct apr_hdr hdr;
+ u32 payload_addr_lsw;
+/* LSW of parameter data payload address. */
+ u32 payload_addr_msw;
+/* MSW of parameter data payload address. */
+
+ u32 mem_map_handle;
+/* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS
+ * command
+ *
+ * If mem_map_handle is zero implies the message is in
+ * the payload
+ */
+
+ u32 payload_size;
+/* Size in bytes of the variable payload accompanying this
+ * message or
+ * in shared memory. This is used for parsing the parameter
+ * payload.
+ */
+} __packed;
+
+/* Payload format for COPP parameter data.
+ * Immediately following this structure are param_size bytes
+ * of parameter
+ * data.
+ */
+struct adm_param_data_v5 {
+ u32 module_id;
+ /* Unique ID of the module. */
+ u32 param_id;
+ /* Unique ID of the parameter. */
+ u16 param_size;
+ /* Data size of the param_id/module_id combination.
+ * This value is a
+ * multiple of 4 bytes.
+ */
+ u16 reserved;
+ /* Reserved for future enhancements.
+ * This field must be set to zero.
+ */
+} __packed;
+
+/* set customized mixing on matrix mixer */
+#define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344
+struct adm_cmd_set_pspd_mtmx_strtr_params_v5 {
+ struct apr_hdr hdr;
+ /* LSW of parameter data payload address.*/
+ u32 payload_addr_lsw;
+ /* MSW of parameter data payload address.*/
+ u32 payload_addr_msw;
+ /* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS */
+ /* command. If mem_map_handle is zero implies the message is in */
+ /* the payload */
+ u32 mem_map_handle;
+ /* Size in bytes of the variable payload accompanying this */
+ /* message or in shared memory. This is used for parsing the */
+ /* parameter payload. */
+ u32 payload_size;
+ u16 direction;
+ u16 sessionid;
+ u16 deviceid;
+ u16 reserved;
+} __packed;
+
+/* Defined specifically for in-band use, includes params */
+struct adm_cmd_set_pp_params_inband_v5 {
+ struct apr_hdr hdr;
+ /* LSW of parameter data payload address.*/
+ u32 payload_addr_lsw;
+ /* MSW of parameter data payload address.*/
+ u32 payload_addr_msw;
+ /* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS */
+ /* command. If mem_map_handle is zero implies the message is in */
+ /* the payload */
+ u32 mem_map_handle;
+ /* Size in bytes of the variable payload accompanying this */
+ /* message or in shared memory. This is used for parsing the */
+ /* parameter payload. */
+ u32 payload_size;
+ /* Parameters passed for in band payload */
+ struct adm_param_data_v5 params;
+} __packed;
+
+/* Returns the status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V5 command.
+ */
+#define ADM_CMDRSP_DEVICE_OPEN_V5 0x00010329
+
+/* Payload of the #ADM_CMDRSP_DEVICE_OPEN_V5 message,
+ * which returns the
+ * status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V5 command.
+ */
+struct adm_cmd_rsp_device_open_v5 {
+ u32 status;
+ /* Status message (error code).*/
+
+ u16 copp_id;
+ /* COPP ID: Supported values: 0 <= copp_id < ADM_MAX_COPPS*/
+
+ u16 reserved;
+ /* Reserved. This field must be set to zero.*/
+} __packed;
+
+/* This command allows a query of one COPP parameter. */
+#define ADM_CMD_GET_PP_PARAMS_V5 0x0001032A
+
+/* Payload an #ADM_CMD_GET_PP_PARAMS_V5 command. */
+struct adm_cmd_get_pp_params_v5 {
+ struct apr_hdr hdr;
+ u32 data_payload_addr_lsw;
+ /* LSW of parameter data payload address.*/
+
+ u32 data_payload_addr_msw;
+ /* MSW of parameter data payload address.*/
+
+ /* If the mem_map_handle is non zero,
+ * on ACK, the ParamData payloads begin at
+ * the address specified (out-of-band).
+ */
+
+ u32 mem_map_handle;
+ /* Memory map handle returned
+ * by ADM_CMD_SHARED_MEM_MAP_REGIONS command.
+ * If the mem_map_handle is 0, it implies that
+ * the ACK's payload will contain the ParamData (in-band).
+ */
+
+ u32 module_id;
+ /* Unique ID of the module. */
+
+ u32 param_id;
+ /* Unique ID of the parameter. */
+
+ u16 param_max_size;
+ /* Maximum data size of the parameter
+ *ID/module ID combination. This
+ * field is a multiple of 4 bytes.
+ */
+ u16 reserved;
+ /* Reserved for future enhancements.
+ * This field must be set to zero.
+ */
+} __packed;
+
+/* Returns parameter values
+ * in response to an #ADM_CMD_GET_PP_PARAMS_V5 command.
+ */
+#define ADM_CMDRSP_GET_PP_PARAMS_V5 0x0001032B
+
+/* Payload of the #ADM_CMDRSP_GET_PP_PARAMS_V5 message,
+ * which returns parameter values in response
+ * to an #ADM_CMD_GET_PP_PARAMS_V5 command.
+ * Immediately following this
+ * structure is the adm_param_data_v5
+ * structure containing the pre/postprocessing
+ * parameter data. For an in-band
+ * scenario, the variable payload depends
+ * on the size of the parameter.
+ */
+struct adm_cmd_rsp_get_pp_params_v5 {
+ u32 status;
+ /* Status message (error code).*/
+} __packed;
+
+/* Structure for holding soft stepping volume parameters. */
+
+/*
+ * Payload of the #ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS
+ * parameters used by the Volume Control module.
+ */
+
+struct audproc_softvolume_params {
+ u32 period;
+ u32 step;
+ u32 rampingcurve;
+} __packed;
+
+/*
+ * ID of the Media Format Converter (MFC) module.
+ * This module supports the following parameter IDs:
+ * #AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT
+ * #AUDPROC_CHMIXER_PARAM_ID_COEFF
+ */
+#define AUDPROC_MODULE_ID_MFC 0x00010912
+
+/* ID of the Output Media Format parameters used by AUDPROC_MODULE_ID_MFC.
+ *
+ */
+#define AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT 0x00010913
+
+
+struct audproc_mfc_output_media_fmt {
+ struct adm_cmd_set_pp_params_v5 params;
+ struct adm_param_data_v5 data;
+ uint32_t sampling_rate;
+ uint16_t bits_per_sample;
+ uint16_t num_channels;
+ uint16_t channel_type[8];
+} __packed;
+
+struct audproc_volume_ctrl_master_gain {
+ struct adm_cmd_set_pp_params_v5 params;
+ struct adm_param_data_v5 data;
+ /* Linear gain in Q13 format. */
+ uint16_t master_gain;
+ /* Clients must set this field to zero. */
+ uint16_t reserved;
+} __packed;
+
+struct audproc_soft_step_volume_params {
+ struct adm_cmd_set_pp_params_v5 params;
+ struct adm_param_data_v5 data;
+/*
+ * Period in milliseconds.
+ * Supported values: 0 to 15000
+ */
+ uint32_t period;
+/*
+ * Step in microseconds.
+ * Supported values: 0 to 15000000
+ */
+ uint32_t step;
+/*
+ * Ramping curve type.
+ * Supported values:
+ * - #AUDPROC_PARAM_SVC_RAMPINGCURVE_LINEAR
+ * - #AUDPROC_PARAM_SVC_RAMPINGCURVE_EXP
+ * - #AUDPROC_PARAM_SVC_RAMPINGCURVE_LOG
+ */
+ uint32_t ramping_curve;
+} __packed;
+
+struct audproc_enable_param_t {
+ struct adm_cmd_set_pp_params_inband_v5 pp_params;
+ /*
+ * Specifies whether the Audio processing module is enabled.
+ * This parameter is generic/common parameter to configure or
+ * determine the state of any audio processing module.
+
+ * @values 0 : Disable 1: Enable
+ */
+ uint32_t enable;
+};
+
+/*
+ * Allows a client to control the gains on various session-to-COPP paths.
+ */
+#define ADM_CMD_MATRIX_RAMP_GAINS_V5 0x0001032C
+
+/* Indicates that the target gain in the
+ * current adm_session_copp_gain_v5
+ * structure is to be applied to all
+ * the session-to-COPP paths that exist for
+ * the specified session.
+ */
+#define ADM_CMD_MATRIX_RAMP_GAINS_COPP_ID_ALL_CONNECTED_COPPS 0xFFFF
+
+/* Indicates that the target gain is
+ * to be immediately applied to the
+ * specified session-to-COPP path,
+ * without a ramping fashion.
+ */
+#define ADM_CMD_MATRIX_RAMP_GAINS_RAMP_DURATION_IMMEDIATE 0x0000
+
+/* Enumeration for a linear ramping curve.*/
+#define ADM_CMD_MATRIX_RAMP_GAINS_RAMP_CURVE_LINEAR 0x0000
+
+/* Payload of the #ADM_CMD_MATRIX_RAMP_GAINS_V5 command.
+ * Immediately following this structure are num_gains of the
+ * adm_session_copp_gain_v5structure.
+ */
+struct adm_cmd_matrix_ramp_gains_v5 {
+ u32 matrix_id;
+/* Specifies whether the matrix ID is Audio Rx (0) or Audio Tx (1).
+ * Use the ADM_MATRIX_ID_AUDIO_RX or ADM_MATRIX_ID_AUDIOX
+ * macros to set this field.
+ */
+
+ u16 num_gains;
+ /* Number of gains being applied. */
+
+ u16 reserved_for_align;
+ /* Reserved. This field must be set to zero.*/
+} __packed;
+
+/* Session-to-COPP path gain structure, used by the
+ * #ADM_CMD_MATRIX_RAMP_GAINS_V5 command.
+ * This structure specifies the target
+ * gain (per channel) that must be applied
+ * to a particular session-to-COPP path in
+ * the audio matrix. The structure can
+ * also be used to apply the gain globally
+ * to all session-to-COPP paths that
+ * exist for the given session.
+ * The aDSP uses device channel mapping to
+ * determine which channel gains to
+ * use from this command. For example,
+ * if the device is configured as stereo,
+ * the aDSP uses only target_gain_ch_1 and
+ * target_gain_ch_2, and it ignores
+ * the others.
+ */
+struct adm_session_copp_gain_v5 {
+ u16 session_id;
+/* Handle of the ASM session.
+ * Supported values: 1 to 8.
+ */
+
+ u16 copp_id;
+/* Handle of the COPP. Gain will be applied on the Session ID
+ * COPP ID path.
+ */
+
+ u16 ramp_duration;
+/* Duration (in milliseconds) of the ramp over
+ * which target gains are
+ * to be applied. Use
+ * #ADM_CMD_MATRIX_RAMP_GAINS_RAMP_DURATION_IMMEDIATE
+ * to indicate that gain must be applied immediately.
+ */
+
+ u16 step_duration;
+/* Duration (in milliseconds) of each step in the ramp.
+ * This parameter is ignored if ramp_duration is equal to
+ * #ADM_CMD_MATRIX_RAMP_GAINS_RAMP_DURATION_IMMEDIATE.
+ * Supported value: 1
+ */
+
+ u16 ramp_curve;
+/* Type of ramping curve.
+ * Supported value: #ADM_CMD_MATRIX_RAMP_GAINS_RAMP_CURVE_LINEAR
+ */
+
+ u16 reserved_for_align;
+ /* Reserved. This field must be set to zero. */
+
+ u16 target_gain_ch_1;
+ /* Target linear gain for channel 1 in Q13 format; */
+
+ u16 target_gain_ch_2;
+ /* Target linear gain for channel 2 in Q13 format; */
+
+ u16 target_gain_ch_3;
+ /* Target linear gain for channel 3 in Q13 format; */
+
+ u16 target_gain_ch_4;
+ /* Target linear gain for channel 4 in Q13 format; */
+
+ u16 target_gain_ch_5;
+ /* Target linear gain for channel 5 in Q13 format; */
+
+ u16 target_gain_ch_6;
+ /* Target linear gain for channel 6 in Q13 format; */
+
+ u16 target_gain_ch_7;
+ /* Target linear gain for channel 7 in Q13 format; */
+
+ u16 target_gain_ch_8;
+ /* Target linear gain for channel 8 in Q13 format; */
+} __packed;
+
+/* Allows to set mute/unmute on various session-to-COPP paths.
+ * For every session-to-COPP path (stream-device interconnection),
+ * mute/unmute can be set individually on the output channels.
+ */
+#define ADM_CMD_MATRIX_MUTE_V5 0x0001032D
+
+/* Indicates that mute/unmute in the
+ * current adm_session_copp_mute_v5structure
+ * is to be applied to all the session-to-COPP
+ * paths that exist for the specified session.
+ */
+#define ADM_CMD_MATRIX_MUTE_COPP_ID_ALL_CONNECTED_COPPS 0xFFFF
+
+/* Payload of the #ADM_CMD_MATRIX_MUTE_V5 command*/
+struct adm_cmd_matrix_mute_v5 {
+ u32 matrix_id;
+/* Specifies whether the matrix ID is Audio Rx (0) or Audio Tx (1).
+ * Use the ADM_MATRIX_ID_AUDIO_RX or ADM_MATRIX_ID_AUDIOX
+ * macros to set this field.
+ */
+
+ u16 session_id;
+/* Handle of the ASM session.
+ * Supported values: 1 to 8.
+ */
+
+ u16 copp_id;
+/* Handle of the COPP.
+ * Use ADM_CMD_MATRIX_MUTE_COPP_ID_ALL_CONNECTED_COPPS
+ * to indicate that mute/unmute must be applied to
+ * all the COPPs connected to session_id.
+ * Supported values:
+ * - 0xFFFF -- Apply mute/unmute to all connected COPPs
+ * - Other values -- Valid COPP ID
+ */
+
+ u8 mute_flag_ch_1;
+ /* Mute flag for channel 1 is set to unmute (0) or mute (1). */
+
+ u8 mute_flag_ch_2;
+ /* Mute flag for channel 2 is set to unmute (0) or mute (1). */
+
+ u8 mute_flag_ch_3;
+ /* Mute flag for channel 3 is set to unmute (0) or mute (1). */
+
+ u8 mute_flag_ch_4;
+ /* Mute flag for channel 4 is set to unmute (0) or mute (1). */
+
+ u8 mute_flag_ch_5;
+ /* Mute flag for channel 5 is set to unmute (0) or mute (1). */
+
+ u8 mute_flag_ch_6;
+ /* Mute flag for channel 6 is set to unmute (0) or mute (1). */
+
+ u8 mute_flag_ch_7;
+ /* Mute flag for channel 7 is set to unmute (0) or mute (1). */
+
+ u8 mute_flag_ch_8;
+ /* Mute flag for channel 8 is set to unmute (0) or mute (1). */
+
+ u16 ramp_duration;
+/* Period (in milliseconds) over which the soft mute/unmute will be
+ * applied.
+ * Supported values: 0 (Default) to 0xFFFF
+ * The default of 0 means mute/unmute will be applied immediately.
+ */
+
+ u16 reserved_for_align;
+ /* Clients must set this field to zero.*/
+} __packed;
+
+#define ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2 (0x00010DD8)
+
+struct asm_aac_stereo_mix_coeff_selection_param_v2 {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ u32 aac_stereo_mix_coeff_flag;
+} __packed;
+
+/* Allows a client to connect the desired stream to
+ * the desired AFE port through the stream router
+ *
+ * This command allows the client to connect specified session to
+ * specified AFE port. This is used for compressed streams only
+ * opened using the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED or
+ * #ASM_STREAM_CMD_OPEN_READ_COMPRESSED command.
+ *
+ * @prerequisites
+ * Session ID and AFE Port ID must be valid.
+ * #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED or
+ * #ASM_STREAM_CMD_OPEN_READ_COMPRESSED
+ * must have been called on this session.
+ */
+
+#define ADM_CMD_CONNECT_AFE_PORT_V5 0x0001032E
+#define ADM_CMD_DISCONNECT_AFE_PORT_V5 0x0001032F
+/* Enumeration for the Rx stream router ID.*/
+#define ADM_STRTR_ID_RX 0
+/* Enumeration for the Tx stream router ID.*/
+#define ADM_STRTR_IDX 1
+
+/* Payload of the #ADM_CMD_CONNECT_AFE_PORT_V5 command.*/
+struct adm_cmd_connect_afe_port_v5 {
+ struct apr_hdr hdr;
+ u8 mode;
+/* ID of the stream router (RX/TX). Use the
+ * ADM_STRTR_ID_RX or ADM_STRTR_IDX macros
+ * to set this field.
+ */
+
+ u8 session_id;
+ /* Session ID of the stream to connect */
+
+ u16 afe_port_id;
+ /* Port ID of the AFE port to connect to.*/
+ u32 num_channels;
+/* Number of device channels
+ * Supported values: 2(Audio Sample Packet),
+ * 8 (HBR Audio Stream Sample Packet)
+ */
+
+ u32 sampling_rate;
+/* Device sampling rate
+ * Supported values: Any
+ */
+} __packed;
+
+
+/* adsp_adm_api.h */
+
+
+/* Port ID. Update afe_get_port_index
+ * when a new port is added here.
+ */
+#define PRIMARY_I2S_RX 0
+#define PRIMARY_I2S_TX 1
+#define SECONDARY_I2S_RX 4
+#define SECONDARY_I2S_TX 5
+#define MI2S_RX 6
+#define MI2S_TX 7
+#define HDMI_RX 8
+#define RSVD_2 9
+#define RSVD_3 10
+#define DIGI_MIC_TX 11
+#define VOICE2_PLAYBACK_TX 0x8002
+#define VOICE_RECORD_RX 0x8003
+#define VOICE_RECORD_TX 0x8004
+#define VOICE_PLAYBACK_TX 0x8005
+
+/* Slimbus Multi channel port id pool */
+#define SLIMBUS_0_RX 0x4000
+#define SLIMBUS_0_TX 0x4001
+#define SLIMBUS_1_RX 0x4002
+#define SLIMBUS_1_TX 0x4003
+#define SLIMBUS_2_RX 0x4004
+#define SLIMBUS_2_TX 0x4005
+#define SLIMBUS_3_RX 0x4006
+#define SLIMBUS_3_TX 0x4007
+#define SLIMBUS_4_RX 0x4008
+#define SLIMBUS_4_TX 0x4009
+#define SLIMBUS_5_RX 0x400a
+#define SLIMBUS_5_TX 0x400b
+#define SLIMBUS_6_RX 0x400c
+#define SLIMBUS_6_TX 0x400d
+#define SLIMBUS_7_RX 0x400e
+#define SLIMBUS_7_TX 0x400f
+#define SLIMBUS_8_RX 0x4010
+#define SLIMBUS_8_TX 0x4011
+#define SLIMBUS_PORT_LAST SLIMBUS_8_TX
+#define INT_BT_SCO_RX 0x3000
+#define INT_BT_SCO_TX 0x3001
+#define INT_BT_A2DP_RX 0x3002
+#define INT_FM_RX 0x3004
+#define INT_FM_TX 0x3005
+#define RT_PROXY_PORT_001_RX 0x2000
+#define RT_PROXY_PORT_001_TX 0x2001
+#define DISPLAY_PORT_RX 0x6020
+
+#define AFE_PORT_INVALID 0xFFFF
+#define SLIMBUS_INVALID AFE_PORT_INVALID
+
+#define AFE_PORT_CMD_START 0x000100ca
+
+#define AFE_EVENT_RTPORT_START 0
+#define AFE_EVENT_RTPORT_STOP 1
+#define AFE_EVENT_RTPORT_LOW_WM 2
+#define AFE_EVENT_RTPORT_HI_WM 3
+
+#define ADSP_AFE_VERSION 0x00200000
+
+/* Size of the range of port IDs for the audio interface. */
+#define AFE_PORT_ID_AUDIO_IF_PORT_RANGE_SIZE 0xF
+
+/* Size of the range of port IDs for internal BT-FM ports. */
+#define AFE_PORT_ID_INTERNAL_BT_FM_RANGE_SIZE 0x6
+
+/* Size of the range of port IDs for SLIMbus<sup>®
+ * </sup> multichannel
+ * ports.
+ */
+#define AFE_PORT_ID_SLIMBUS_RANGE_SIZE 0xA
+
+/* Size of the range of port IDs for real-time proxy ports. */
+#define AFE_PORT_ID_RT_PROXY_PORT_RANGE_SIZE 0x2
+
+/* Size of the range of port IDs for pseudoports. */
+#define AFE_PORT_ID_PSEUDOPORT_RANGE_SIZE 0x5
+
+/* Start of the range of port IDs for the audio interface. */
+#define AFE_PORT_ID_AUDIO_IF_PORT_RANGE_START 0x1000
+
+/* End of the range of port IDs for the audio interface. */
+#define AFE_PORT_ID_AUDIO_IF_PORT_RANGE_END \
+ (AFE_PORT_ID_AUDIO_IF_PORT_RANGE_START +\
+ AFE_PORT_ID_AUDIO_IF_PORT_RANGE_SIZE - 1)
+
+/* Start of the range of port IDs for real-time proxy ports. */
+#define AFE_PORT_ID_RT_PROXY_PORT_RANGE_START 0x2000
+
+/* End of the range of port IDs for real-time proxy ports. */
+#define AFE_PORT_ID_RT_PROXY_PORT_RANGE_END \
+ (AFE_PORT_ID_RT_PROXY_PORT_RANGE_START +\
+ AFE_PORT_ID_RT_PROXY_PORT_RANGE_SIZE-1)
+
+/* Start of the range of port IDs for internal BT-FM devices. */
+#define AFE_PORT_ID_INTERNAL_BT_FM_RANGE_START 0x3000
+
+/* End of the range of port IDs for internal BT-FM devices. */
+#define AFE_PORT_ID_INTERNAL_BT_FM_RANGE_END \
+ (AFE_PORT_ID_INTERNAL_BT_FM_RANGE_START +\
+ AFE_PORT_ID_INTERNAL_BT_FM_RANGE_SIZE-1)
+
+/* Start of the range of port IDs for SLIMbus devices. */
+#define AFE_PORT_ID_SLIMBUS_RANGE_START 0x4000
+
+/* End of the range of port IDs for SLIMbus devices. */
+#define AFE_PORT_ID_SLIMBUS_RANGE_END \
+ (AFE_PORT_ID_SLIMBUS_RANGE_START +\
+ AFE_PORT_ID_SLIMBUS_RANGE_SIZE-1)
+
+/* Start of the range of port IDs for pseudoports. */
+#define AFE_PORT_ID_PSEUDOPORT_RANGE_START 0x8001
+
+/* End of the range of port IDs for pseudoports. */
+#define AFE_PORT_ID_PSEUDOPORT_RANGE_END \
+ (AFE_PORT_ID_PSEUDOPORT_RANGE_START +\
+ AFE_PORT_ID_PSEUDOPORT_RANGE_SIZE-1)
+
+/* Start of the range of port IDs for TDM devices. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000
+
+/* End of the range of port IDs for TDM devices. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_END \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START+0x40-1)
+
+/* Size of the range of port IDs for TDM ports. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_SIZE \
+ (AFE_PORT_ID_TDM_PORT_RANGE_END - \
+ AFE_PORT_ID_TDM_PORT_RANGE_START+1)
+
+#define AFE_PORT_ID_PRIMARY_MI2S_RX 0x1000
+#define AFE_PORT_ID_PRIMARY_MI2S_TX 0x1001
+#define AFE_PORT_ID_SECONDARY_MI2S_RX 0x1002
+#define AFE_PORT_ID_SECONDARY_MI2S_TX 0x1003
+#define AFE_PORT_ID_TERTIARY_MI2S_RX 0x1004
+#define AFE_PORT_ID_TERTIARY_MI2S_TX 0x1005
+#define AFE_PORT_ID_QUATERNARY_MI2S_RX 0x1006
+#define AFE_PORT_ID_QUATERNARY_MI2S_TX 0x1007
+#define AUDIO_PORT_ID_I2S_RX 0x1008
+#define AFE_PORT_ID_DIGITAL_MIC_TX 0x1009
+#define AFE_PORT_ID_PRIMARY_PCM_RX 0x100A
+#define AFE_PORT_ID_PRIMARY_PCM_TX 0x100B
+#define AFE_PORT_ID_SECONDARY_PCM_RX 0x100C
+#define AFE_PORT_ID_SECONDARY_PCM_TX 0x100D
+#define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E
+#define AFE_PORT_ID_SECONDARY_MI2S_RX_SD1 0x1010
+#define AFE_PORT_ID_TERTIARY_PCM_RX 0x1012
+#define AFE_PORT_ID_TERTIARY_PCM_TX 0x1013
+#define AFE_PORT_ID_QUATERNARY_PCM_RX 0x1014
+#define AFE_PORT_ID_QUATERNARY_PCM_TX 0x1015
+#define AFE_PORT_ID_QUINARY_MI2S_RX 0x1016
+#define AFE_PORT_ID_QUINARY_MI2S_TX 0x1017
+/* ID of the senary MI2S Rx port. */
+#define AFE_PORT_ID_SENARY_MI2S_RX 0x1018
+/* ID of the senary MI2S Tx port. */
+#define AFE_PORT_ID_SENARY_MI2S_TX 0x1019
+/* ID of the Internal 0 MI2S Rx port */
+#define AFE_PORT_ID_INT0_MI2S_RX 0x102E
+/* ID of the Internal 0 MI2S Tx port */
+#define AFE_PORT_ID_INT0_MI2S_TX 0x102F
+/* ID of the Internal 1 MI2S Rx port */
+#define AFE_PORT_ID_INT1_MI2S_RX 0x1030
+/* ID of the Internal 1 MI2S Tx port */
+#define AFE_PORT_ID_INT1_MI2S_TX 0x1031
+/* ID of the Internal 2 MI2S Rx port */
+#define AFE_PORT_ID_INT2_MI2S_RX 0x1032
+/* ID of the Internal 2 MI2S Tx port */
+#define AFE_PORT_ID_INT2_MI2S_TX 0x1033
+/* ID of the Internal 3 MI2S Rx port */
+#define AFE_PORT_ID_INT3_MI2S_RX 0x1034
+/* ID of the Internal 3 MI2S Tx port */
+#define AFE_PORT_ID_INT3_MI2S_TX 0x1035
+/* ID of the Internal 4 MI2S Rx port */
+#define AFE_PORT_ID_INT4_MI2S_RX 0x1036
+/* ID of the Internal 4 MI2S Tx port */
+#define AFE_PORT_ID_INT4_MI2S_TX 0x1037
+/* ID of the Internal 5 MI2S Rx port */
+#define AFE_PORT_ID_INT5_MI2S_RX 0x1038
+/* ID of the Internal 5 MI2S Tx port */
+#define AFE_PORT_ID_INT5_MI2S_TX 0x1039
+/* ID of the Internal 6 MI2S Rx port */
+#define AFE_PORT_ID_INT6_MI2S_RX 0x103A
+/* ID of the Internal 6 MI2S Tx port */
+#define AFE_PORT_ID_INT6_MI2S_TX 0x103B
+#define AFE_PORT_ID_SPDIF_RX 0x5000
+#define AFE_PORT_ID_RT_PROXY_PORT_001_RX 0x2000
+#define AFE_PORT_ID_RT_PROXY_PORT_001_TX 0x2001
+#define AFE_PORT_ID_INTERNAL_BT_SCO_RX 0x3000
+#define AFE_PORT_ID_INTERNAL_BT_SCO_TX 0x3001
+#define AFE_PORT_ID_INTERNAL_BT_A2DP_RX 0x3002
+#define AFE_PORT_ID_INTERNAL_FM_RX 0x3004
+#define AFE_PORT_ID_INTERNAL_FM_TX 0x3005
+/* SLIMbus Rx port on channel 0. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX 0x4000
+/* SLIMbus Tx port on channel 0. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX 0x4001
+/* SLIMbus Rx port on channel 1. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX 0x4002
+/* SLIMbus Tx port on channel 1. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX 0x4003
+/* SLIMbus Rx port on channel 2. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX 0x4004
+/* SLIMbus Tx port on channel 2. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX 0x4005
+/* SLIMbus Rx port on channel 3. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX 0x4006
+/* SLIMbus Tx port on channel 3. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX 0x4007
+/* SLIMbus Rx port on channel 4. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX 0x4008
+/* SLIMbus Tx port on channel 4. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX 0x4009
+/* SLIMbus Rx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX 0x400a
+/* SLIMbus Tx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX 0x400b
+/* SLIMbus Rx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX 0x400c
+/* SLIMbus Tx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX 0x400d
+/* SLIMbus Rx port on channel 7. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_7_RX 0x400e
+/* SLIMbus Tx port on channel 7. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_7_TX 0x400f
+/* SLIMbus Rx port on channel 8. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_8_RX 0x4010
+/* SLIMbus Tx port on channel 8. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_8_TX 0x4011
+/* AFE Rx port for audio over Display port */
+#define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020
+/*USB AFE port */
+#define AFE_PORT_ID_USB_RX 0x7000
+#define AFE_PORT_ID_USB_TX 0x7001
+
+/* Generic pseudoport 1. */
+#define AFE_PORT_ID_PSEUDOPORT_01 0x8001
+/* Generic pseudoport 2. */
+#define AFE_PORT_ID_PSEUDOPORT_02 0x8002
+
+/* @xreflabel{hdr:AfePortIdPrimaryAuxPcmTx}
+ * Primary Aux PCM Tx port ID.
+ */
+#define AFE_PORT_ID_PRIMARY_PCM_TX 0x100B
+/* Pseudoport that corresponds to the voice Rx path.
+ * For recording, the voice Rx path samples are written to this
+ * port and consumed by the audio path.
+ */
+
+#define AFE_PORT_ID_VOICE_RECORD_RX 0x8003
+
+/* Pseudoport that corresponds to the voice Tx path.
+ * For recording, the voice Tx path samples are written to this
+ * port and consumed by the audio path.
+ */
+
+#define AFE_PORT_ID_VOICE_RECORD_TX 0x8004
+/* Pseudoport that corresponds to in-call voice delivery samples.
+ * During in-call audio delivery, the audio path delivers samples
+ * to this port from where the voice path delivers them on the
+ * Rx path.
+ */
+#define AFE_PORT_ID_VOICE2_PLAYBACK_TX 0x8002
+#define AFE_PORT_ID_VOICE_PLAYBACK_TX 0x8005
+
+#define AFE_PORT_ID_PRIMARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x00)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_1 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_2 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_3 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_4 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_5 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_6 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_7 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_PRIMARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x01)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_1 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_2 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_3 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_4 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_5 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_6 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_7 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_SECONDARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x10)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_1 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_2 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_3 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_4 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_5 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_6 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_7 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_SECONDARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x11)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_1 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_2 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_3 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_4 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_5 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_6 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_7 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_TERTIARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x20)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_1 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_2 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_3 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_4 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_5 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_6 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_7 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_TERTIARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x21)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_1 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_2 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_3 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_4 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_5 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_6 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_7 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_QUATERNARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x30)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_1 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_2 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_3 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_4 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_5 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_6 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_7 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_QUATERNARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x31)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_1 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_2 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_3 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_4 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_5 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_6 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_7 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_INVALID 0xFFFF
+
+#define AAC_ENC_MODE_AAC_LC 0x02
+#define AAC_ENC_MODE_AAC_P 0x05
+#define AAC_ENC_MODE_EAAC_P 0x1D
+
+#define AFE_PSEUDOPORT_CMD_START 0x000100cf
+struct afe_pseudoport_start_command {
+ struct apr_hdr hdr;
+ u16 port_id; /* Pseudo Port 1 = 0x8000 */
+ /* Pseudo Port 2 = 0x8001 */
+ /* Pseudo Port 3 = 0x8002 */
+ u16 timing; /* FTRT = 0 , AVTimer = 1, */
+} __packed;
+
+#define AFE_PSEUDOPORT_CMD_STOP 0x000100d0
+struct afe_pseudoport_stop_command {
+ struct apr_hdr hdr;
+ u16 port_id; /* Pseudo Port 1 = 0x8000 */
+ /* Pseudo Port 2 = 0x8001 */
+ /* Pseudo Port 3 = 0x8002 */
+ u16 reserved;
+} __packed;
+
+
+#define AFE_MODULE_SIDETONE_IIR_FILTER 0x00010202
+#define AFE_PARAM_ID_ENABLE 0x00010203
+
+/* Payload of the #AFE_PARAM_ID_ENABLE
+ * parameter, which enables or
+ * disables any module.
+ * The fixed size of this structure is four bytes.
+ */
+
+struct afe_mod_enable_param {
+ u16 enable;
+ /* Enables (1) or disables (0) the module. */
+
+ u16 reserved;
+ /* This field must be set to zero. */
+} __packed;
+
+/* ID of the configuration parameter used by the
+ * #AFE_MODULE_SIDETONE_IIR_FILTER module.
+ */
+#define AFE_PARAM_ID_SIDETONE_IIR_FILTER_CONFIG 0x00010204
+
+struct afe_sidetone_iir_filter_config_params {
+ u16 num_biquad_stages;
+/* Number of stages.
+ * Supported values: Minimum of 5 and maximum of 10
+ */
+
+ u16 pregain;
+/* Pregain for the compensating filter response.
+ * Supported values: Any number in Q13 format
+ */
+} __packed;
+
+#define AFE_MODULE_LOOPBACK 0x00010205
+#define AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH 0x00010206
+
+/* Payload of the #AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH parameter,
+ * which gets/sets loopback gain of a port to an Rx port.
+ * The Tx port ID of the loopback is part of the set_param command.
+ */
+
+/* Payload of the #AFE_PORT_CMD_SET_PARAM_V2 command's
+ * configuration/calibration settings for the AFE port.
+ */
+struct afe_port_cmd_set_param_v2 {
+ u16 port_id;
+/* Port interface and direction (Rx or Tx) to start. */
+
+ u16 payload_size;
+/* Actual size of the payload in bytes.
+ * This is used for parsing the parameter payload.
+ * Supported values: > 0
+ */
+
+u32 payload_address_lsw;
+/* LSW of 64 bit Payload address.
+ * Address should be 32-byte,
+ * 4kbyte aligned and must be contiguous memory.
+ */
+
+u32 payload_address_msw;
+/* MSW of 64 bit Payload address.
+ * In case of 32-bit shared memory address,
+ * this field must be set to zero.
+ * In case of 36-bit shared memory address,
+ * bit-4 to bit-31 must be set to zero.
+ * Address should be 32-byte, 4kbyte aligned
+ * and must be contiguous memory.
+ */
+
+u32 mem_map_handle;
+/* Memory map handle returned by
+ * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS commands.
+ * Supported Values:
+ * - NULL -- Message. The parameter data is in-band.
+ * - Non-NULL -- The parameter data is Out-band.Pointer to
+ * the physical address
+ * in shared memory of the payload data.
+ * An optional field is available if parameter
+ * data is in-band:
+ * afe_param_data_v2 param_data[...].
+ * For detailed payload content, see the
+ * afe_port_param_data_v2 structure.
+ */
+} __packed;
+
+#define AFE_PORT_CMD_SET_PARAM_V2 0x000100EF
+
+struct afe_port_param_data_v2 {
+ u32 module_id;
+/* ID of the module to be configured.
+ * Supported values: Valid module ID
+ */
+
+u32 param_id;
+/* ID of the parameter corresponding to the supported parameters
+ * for the module ID.
+ * Supported values: Valid parameter ID
+ */
+
+u16 param_size;
+/* Actual size of the data for the
+ * module_id/param_id pair. The size is a
+ * multiple of four bytes.
+ * Supported values: > 0
+ */
+
+u16 reserved;
+/* This field must be set to zero.
+ */
+} __packed;
+
+struct afe_loopback_gain_per_path_param {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ u16 rx_port_id;
+/* Rx port of the loopback. */
+
+u16 gain;
+/* Loopback gain per path of the port.
+ * Supported values: Any number in Q13 format
+ */
+} __packed;
+
+/* Parameter ID used to configure and enable/disable the
+ * loopback path. The difference with respect to the existing
+ * API, AFE_PORT_CMD_LOOPBACK, is that it allows Rx port to be
+ * configured as source port in loopback path. Port-id in
+ * AFE_PORT_CMD_SET_PARAM cmd is the source port which can be
+ * Tx or Rx port. In addition, we can configure the type of
+ * routing mode to handle different use cases.
+ */
+#define AFE_PARAM_ID_LOOPBACK_CONFIG 0x0001020B
+#define AFE_API_VERSION_LOOPBACK_CONFIG 0x1
+
+enum afe_loopback_routing_mode {
+ LB_MODE_DEFAULT = 1,
+ /* Regular loopback from source to destination port */
+ LB_MODE_SIDETONE,
+ /* Sidetone feed from Tx source to Rx destination port */
+ LB_MODE_EC_REF_VOICE_AUDIO,
+ /* Echo canceller reference, voice + audio + DTMF */
+ LB_MODE_EC_REF_VOICE
+ /* Echo canceller reference, voice alone */
+} __packed;
+
+/* Payload of the #AFE_PARAM_ID_LOOPBACK_CONFIG ,
+ * which enables/disables one AFE loopback.
+ */
+struct afe_loopback_cfg_v1 {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ u32 loopback_cfg_minor_version;
+/* Minor version used for tracking the version of the RMC module
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_LOOPBACK_CONFIG
+ */
+ u16 dst_port_id;
+ /* Destination Port Id. */
+ u16 routing_mode;
+/* Specifies data path type from src to dest port.
+ * Supported values:
+ * #LB_MODE_DEFAULT
+ * #LB_MODE_SIDETONE
+ * #LB_MODE_EC_REF_VOICE_AUDIO
+ * #LB_MODE_EC_REF_VOICE_A
+ * #LB_MODE_EC_REF_VOICE
+ */
+
+ u16 enable;
+/* Specifies whether to enable (1) or
+ * disable (0) an AFE loopback.
+ */
+ u16 reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.
+ */
+
+} __packed;
+
+#define AFE_MODULE_SPEAKER_PROTECTION 0x00010209
+#define AFE_PARAM_ID_SPKR_PROT_CONFIG 0x0001020a
+#define AFE_API_VERSION_SPKR_PROT_CONFIG 0x1
+#define AFE_SPKR_PROT_EXCURSIONF_LEN 512
+struct afe_spkr_prot_cfg_param_v1 {
+ u32 spkr_prot_minor_version;
+/*
+ * Minor version used for tracking the version of the
+ * speaker protection module configuration interface.
+ * Supported values: #AFE_API_VERSION_SPKR_PROT_CONFIG
+ */
+
+int16_t win_size;
+/* Analysis and synthesis window size (nWinSize).
+ * Supported values: 1024, 512, 256 samples
+ */
+
+int16_t margin;
+/* Allowable margin for excursion prediction,
+ * in L16Q15 format. This is a
+ * control parameter to allow
+ * for overestimation of peak excursion.
+ */
+
+int16_t spkr_exc_limit;
+/* Speaker excursion limit, in L16Q15 format.*/
+
+int16_t spkr_resonance_freq;
+/* Resonance frequency of the speaker; used
+ * to define a frequency range
+ * for signal modification.
+ *
+ * Supported values: 0 to 2000 Hz
+ */
+
+int16_t limhresh;
+/* Threshold of the hard limiter; used to
+ * prevent overshooting beyond a
+ * signal level that was set by the limiter
+ * prior to speaker protection.
+ * Supported values: 0 to 32767
+ */
+
+int16_t hpf_cut_off_freq;
+/* High pass filter cutoff frequency.
+ * Supported values: 100, 200, 300 Hz
+ */
+
+int16_t hpf_enable;
+/* Specifies whether the high pass filter
+ * is enabled (0) or disabled (1).
+ */
+
+int16_t reserved;
+/* This field must be set to zero. */
+
+int32_t amp_gain;
+/* Amplifier gain in L32Q15 format.
+ * This is the RMS voltage at the
+ * loudspeaker when a 0dBFS tone
+ * is played in the digital domain.
+ */
+
+int16_t excursionf[AFE_SPKR_PROT_EXCURSIONF_LEN];
+/* Array of the excursion transfer function.
+ * The peak excursion of the
+ * loudspeaker diaphragm is
+ * measured in millimeters for 1 Vrms Sine
+ * tone at all FFT bin frequencies.
+ * Supported values: Q15 format
+ */
+} __packed;
+
+
+#define AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER 0x000100E0
+
+/* Payload of the #AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER
+ * command, which registers a real-time port driver
+ * with the AFE service.
+ */
+struct afe_service_cmd_register_rt_port_driver {
+ struct apr_hdr hdr;
+ u16 port_id;
+/* Port ID with which the real-time driver exchanges data
+ * (registers for events).
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ */
+
+ u16 reserved;
+ /* This field must be set to zero. */
+} __packed;
+
+#define AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER 0x000100E1
+
+/* Payload of the #AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER
+ * command, which unregisters a real-time port driver from
+ * the AFE service.
+ */
+struct afe_service_cmd_unregister_rt_port_driver {
+ struct apr_hdr hdr;
+ u16 port_id;
+/* Port ID from which the real-time
+ * driver unregisters for events.
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ */
+
+ u16 reserved;
+ /* This field must be set to zero. */
+} __packed;
+
+#define AFE_EVENT_RT_PROXY_PORT_STATUS 0x00010105
+#define AFE_EVENTYPE_RT_PROXY_PORT_START 0
+#define AFE_EVENTYPE_RT_PROXY_PORT_STOP 1
+#define AFE_EVENTYPE_RT_PROXY_PORT_LOW_WATER_MARK 2
+#define AFE_EVENTYPE_RT_PROXY_PORT_HIGH_WATER_MARK 3
+#define AFE_EVENTYPE_RT_PROXY_PORT_INVALID 0xFFFF
+
+/* Payload of the #AFE_EVENT_RT_PROXY_PORT_STATUS
+ * message, which sends an event from the AFE service
+ * to a registered client.
+ */
+struct afe_event_rt_proxy_port_status {
+ u16 port_id;
+/* Port ID to which the event is sent.
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ */
+
+ u16 eventype;
+/* Type of event.
+ * Supported values:
+ * - #AFE_EVENTYPE_RT_PROXY_PORT_START
+ * - #AFE_EVENTYPE_RT_PROXY_PORT_STOP
+ * - #AFE_EVENTYPE_RT_PROXY_PORT_LOW_WATER_MARK
+ * - #AFE_EVENTYPE_RT_PROXY_PORT_HIGH_WATER_MARK
+ */
+} __packed;
+
+#define AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2 0x000100ED
+
+struct afe_port_data_cmd_rt_proxy_port_write_v2 {
+ struct apr_hdr hdr;
+ u16 port_id;
+/* Tx (mic) proxy port ID with which the real-time
+ * driver exchanges data.
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ */
+
+ u16 reserved;
+ /* This field must be set to zero. */
+
+ u32 buffer_address_lsw;
+/* LSW Address of the buffer containing the
+ * data from the real-time source
+ * device on a client.
+ */
+
+ u32 buffer_address_msw;
+/* MSW Address of the buffer containing the
+ * data from the real-time source
+ * device on a client.
+ */
+
+ u32 mem_map_handle;
+/* A memory map handle encapsulating shared memory
+ * attributes is returned if
+ * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS
+ * command is successful.
+ * Supported Values:
+ * - Any 32 bit value
+ */
+
+ u32 available_bytes;
+/* Number of valid bytes available
+ * in the buffer (including all
+ * channels: number of bytes per
+ * channel = availableBytesumChannels).
+ * Supported values: > 0
+ *
+ * This field must be equal to the frame
+ * size specified in the #AFE_PORT_AUDIO_IF_CONFIG
+ * command that was sent to configure this
+ * port.
+ */
+} __packed;
+
+#define AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2 0x000100EE
+
+/* Payload of the
+ * #AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2 command, which
+ * delivers an empty buffer to the AFE service. On
+ * acknowledgment, data is filled in the buffer.
+ */
+struct afe_port_data_cmd_rt_proxy_port_read_v2 {
+ struct apr_hdr hdr;
+ u16 port_id;
+/* Rx proxy port ID with which the real-time
+ * driver exchanges data.
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ * (This must be an Rx (speaker) port.)
+ */
+
+ u16 reserved;
+ /* This field must be set to zero. */
+
+ u32 buffer_address_lsw;
+/* LSW Address of the buffer containing the data sent from the AFE
+ * service to a real-time sink device on the client.
+ */
+
+
+ u32 buffer_address_msw;
+/* MSW Address of the buffer containing the data sent from the AFE
+ * service to a real-time sink device on the client.
+ */
+
+ u32 mem_map_handle;
+/* A memory map handle encapsulating shared memory attributes is
+ * returned if AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS command is
+ * successful.
+ * Supported Values:
+ * - Any 32 bit value
+ */
+
+ u32 available_bytes;
+/* Number of valid bytes available in the buffer (including all
+ * channels).
+ * Supported values: > 0
+ * This field must be equal to the frame size specified in the
+ * #AFE_PORT_AUDIO_IF_CONFIG command that was sent to configure
+ * this port.
+ */
+} __packed;
+
+/* This module ID is related to device configuring like I2S,PCM,
+ * HDMI, SLIMBus etc. This module supports following parameter ids.
+ * - #AFE_PARAM_ID_I2S_CONFIG
+ * - #AFE_PARAM_ID_PCM_CONFIG
+ * - #AFE_PARAM_ID_DIGI_MIC_CONFIG
+ * - #AFE_PARAM_ID_HDMI_CONFIG
+ * - #AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG
+ * - #AFE_PARAM_ID_SLIMBUS_CONFIG
+ * - #AFE_PARAM_ID_RT_PROXY_CONFIG
+ */
+
+#define AFE_MODULE_AUDIO_DEV_INTERFACE 0x0001020C
+#define AFE_PORT_SAMPLE_RATE_8K 8000
+#define AFE_PORT_SAMPLE_RATE_16K 16000
+#define AFE_PORT_SAMPLE_RATE_48K 48000
+#define AFE_PORT_SAMPLE_RATE_96K 96000
+#define AFE_PORT_SAMPLE_RATE_192K 192000
+#define AFE_LINEAR_PCM_DATA 0x0
+#define AFE_NON_LINEAR_DATA 0x1
+#define AFE_LINEAR_PCM_DATA_PACKED_60958 0x2
+#define AFE_NON_LINEAR_DATA_PACKED_60958 0x3
+
+/* This param id is used to configure I2S interface */
+#define AFE_PARAM_ID_I2S_CONFIG 0x0001020D
+#define AFE_API_VERSION_I2S_CONFIG 0x1
+/* Enumeration for setting the I2S configuration
+ * channel_mode parameter to
+ * serial data wire number 1-3 (SD3).
+ */
+#define AFE_PORT_I2S_SD0 0x1
+#define AFE_PORT_I2S_SD1 0x2
+#define AFE_PORT_I2S_SD2 0x3
+#define AFE_PORT_I2S_SD3 0x4
+#define AFE_PORT_I2S_QUAD01 0x5
+#define AFE_PORT_I2S_QUAD23 0x6
+#define AFE_PORT_I2S_6CHS 0x7
+#define AFE_PORT_I2S_8CHS 0x8
+#define AFE_PORT_I2S_MONO 0x0
+#define AFE_PORT_I2S_STEREO 0x1
+#define AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL 0x0
+#define AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL 0x1
+
+/* Payload of the #AFE_PARAM_ID_I2S_CONFIG
+ * command's (I2S configuration
+ * parameter).
+ */
+struct afe_param_id_i2s_cfg {
+ u32 i2s_cfg_minor_version;
+/* Minor version used for tracking the version of the I2S
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_I2S_CONFIG
+ */
+
+ u16 bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+
+ u16 channel_mode;
+/* I2S lines and multichannel operation.
+ * Supported values:
+ * - #AFE_PORT_I2S_SD0
+ * - #AFE_PORT_I2S_SD1
+ * - #AFE_PORT_I2S_SD2
+ * - #AFE_PORT_I2S_SD3
+ * - #AFE_PORT_I2S_QUAD01
+ * - #AFE_PORT_I2S_QUAD23
+ * - #AFE_PORT_I2S_6CHS
+ * - #AFE_PORT_I2S_8CHS
+ */
+
+ u16 mono_stereo;
+/* Specifies mono or stereo. This applies only when
+ * a single I2S line is used.
+ * Supported values:
+ * - #AFE_PORT_I2S_MONO
+ * - #AFE_PORT_I2S_STEREO
+ */
+
+ u16 ws_src;
+/* Word select source: internal or external.
+ * Supported values:
+ * - #AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL
+ * - #AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL
+ */
+
+ u32 sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K
+ */
+
+ u16 data_format;
+/* data format
+ * Supported values:
+ * - #LINEAR_PCM_DATA
+ * - #NON_LINEAR_DATA
+ * - #LINEAR_PCM_DATA_PACKED_IN_60958
+ * - #NON_LINEAR_DATA_PACKED_IN_60958
+ */
+ u16 reserved;
+ /* This field must be set to zero. */
+} __packed;
+
+/*
+ * This param id is used to configure PCM interface
+ */
+
+#define AFE_API_VERSION_SPDIF_CONFIG 0x1
+#define AFE_API_VERSION_SPDIF_CH_STATUS_CONFIG 0x1
+#define AFE_API_VERSION_SPDIF_CLK_CONFIG 0x1
+#define AFE_CH_STATUS_A 1
+#define AFE_CH_STATUS_B 2
+
+#define AFE_PARAM_ID_SPDIF_CONFIG 0x00010244
+#define AFE_PARAM_ID_CH_STATUS_CONFIG 0x00010245
+#define AFE_PARAM_ID_SPDIF_CLK_CONFIG 0x00010246
+
+#define AFE_PORT_CLK_ROOT_LPAPLL 0x3
+#define AFE_PORT_CLK_ROOT_LPAQ6PLL 0x4
+
+struct afe_param_id_spdif_cfg {
+/* Minor version used for tracking the version of the SPDIF
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_SPDIF_CONFIG
+ */
+ u32 spdif_cfg_minor_version;
+
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_22_05K
+ * - #AFE_PORT_SAMPLE_RATE_32K
+ * - #AFE_PORT_SAMPLE_RATE_44_1K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_176_4K
+ * - #AFE_PORT_SAMPLE_RATE_192K
+ */
+ u32 sample_rate;
+
+/* data format
+ * Supported values:
+ * - #AFE_LINEAR_PCM_DATA
+ * - #AFE_NON_LINEAR_DATA
+ */
+ u16 data_format;
+/* Number of channels supported by the port
+ * - PCM - 1, Compressed Case - 2
+ */
+ u16 num_channels;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+ u16 bit_width;
+/* This field must be set to zero. */
+ u16 reserved;
+} __packed;
+
+struct afe_param_id_spdif_ch_status_cfg {
+ u32 ch_status_cfg_minor_version;
+/* Minor version used for tracking the version of channel
+ * status configuration. Current supported version is 1
+ */
+
+ u32 status_type;
+/* Indicate if the channel status is for channel A or B
+ * Supported values:
+ * - #AFE_CH_STATUS_A
+ * - #AFE_CH_STATUS_B
+ */
+
+ u8 status_bits[24];
+/* Channel status - 192 bits for channel
+ * Byte ordering as defined by IEC60958-3
+ */
+
+ u8 status_mask[24];
+/* Channel status with mask bits 1 will be applied.
+ * Byte ordering as defined by IEC60958-3
+ */
+} __packed;
+
+struct afe_param_id_spdif_clk_cfg {
+ u32 clk_cfg_minor_version;
+/* Minor version used for tracking the version of SPDIF
+ * interface clock configuration. Current supported version
+ * is 1
+ */
+
+ u32 clk_value;
+/* Specifies the clock frequency in Hz to set
+ * Supported values:
+ * 0 - Disable the clock
+ * 2 (byphase) * 32 (60958 subframe size) * sampling rate * 2
+ * (channels A and B)
+ */
+
+ u32 clk_root;
+/* Specifies SPDIF root clk source
+ * Supported Values:
+ * - #AFE_PORT_CLK_ROOT_LPAPLL
+ * - #AFE_PORT_CLK_ROOT_LPAQ6PLL
+ */
+} __packed;
+
+struct afe_spdif_clk_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_spdif_clk_cfg clk_cfg;
+} __packed;
+
+struct afe_spdif_chstatus_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_spdif_ch_status_cfg ch_status;
+} __packed;
+
+struct afe_spdif_port_config {
+ struct afe_param_id_spdif_cfg cfg;
+ struct afe_param_id_spdif_ch_status_cfg ch_status;
+} __packed;
+
+#define AFE_PARAM_ID_PCM_CONFIG 0x0001020E
+#define AFE_API_VERSION_PCM_CONFIG 0x1
+/* Enumeration for the auxiliary PCM synchronization signal
+ * provided by an external source.
+ */
+
+#define AFE_PORT_PCM_SYNC_SRC_EXTERNAL 0x0
+/* Enumeration for the auxiliary PCM synchronization signal
+ * provided by an internal source.
+ */
+#define AFE_PORT_PCM_SYNC_SRC_INTERNAL 0x1
+/* Enumeration for the PCM configuration aux_mode parameter,
+ * which configures the auxiliary PCM interface to use
+ * short synchronization.
+ */
+#define AFE_PORT_PCM_AUX_MODE_PCM 0x0
+/*
+ * Enumeration for the PCM configuration aux_mode parameter,
+ * which configures the auxiliary PCM interface to use long
+ * synchronization.
+ */
+#define AFE_PORT_PCM_AUX_MODE_AUX 0x1
+/*
+ * Enumeration for setting the PCM configuration frame to 8.
+ */
+#define AFE_PORT_PCM_BITS_PER_FRAME_8 0x0
+/*
+ * Enumeration for setting the PCM configuration frame to 16.
+ */
+#define AFE_PORT_PCM_BITS_PER_FRAME_16 0x1
+
+/* Enumeration for setting the PCM configuration frame to 32.*/
+#define AFE_PORT_PCM_BITS_PER_FRAME_32 0x2
+
+/* Enumeration for setting the PCM configuration frame to 64.*/
+#define AFE_PORT_PCM_BITS_PER_FRAME_64 0x3
+
+/* Enumeration for setting the PCM configuration frame to 128.*/
+#define AFE_PORT_PCM_BITS_PER_FRAME_128 0x4
+
+/* Enumeration for setting the PCM configuration frame to 256.*/
+#define AFE_PORT_PCM_BITS_PER_FRAME_256 0x5
+
+/* Enumeration for setting the PCM configuration
+ * quantype parameter to A-law with no padding.
+ */
+#define AFE_PORT_PCM_ALAW_NOPADDING 0x0
+
+/* Enumeration for setting the PCM configuration quantype
+ * parameter to mu-law with no padding.
+ */
+#define AFE_PORT_PCM_MULAW_NOPADDING 0x1
+/* Enumeration for setting the PCM configuration quantype
+ * parameter to linear with no padding.
+ */
+#define AFE_PORT_PCM_LINEAR_NOPADDING 0x2
+/* Enumeration for setting the PCM configuration quantype
+ * parameter to A-law with padding.
+ */
+#define AFE_PORT_PCM_ALAW_PADDING 0x3
+/* Enumeration for setting the PCM configuration quantype
+ * parameter to mu-law with padding.
+ */
+#define AFE_PORT_PCM_MULAW_PADDING 0x4
+/* Enumeration for setting the PCM configuration quantype
+ * parameter to linear with padding.
+ */
+#define AFE_PORT_PCM_LINEAR_PADDING 0x5
+/* Enumeration for disabling the PCM configuration
+ * ctrl_data_out_enable parameter.
+ * The PCM block is the only master.
+ */
+#define AFE_PORT_PCM_CTRL_DATA_OE_DISABLE 0x0
+/*
+ * Enumeration for enabling the PCM configuration
+ * ctrl_data_out_enable parameter. The PCM block shares
+ * the signal with other masters.
+ */
+#define AFE_PORT_PCM_CTRL_DATA_OE_ENABLE 0x1
+
+/* Payload of the #AFE_PARAM_ID_PCM_CONFIG command's
+ * (PCM configuration parameter).
+ */
+
+struct afe_param_id_pcm_cfg {
+ u32 pcm_cfg_minor_version;
+/* Minor version used for tracking the version of the AUX PCM
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_PCM_CONFIG
+ */
+
+ u16 aux_mode;
+/* PCM synchronization setting.
+ * Supported values:
+ * - #AFE_PORT_PCM_AUX_MODE_PCM
+ * - #AFE_PORT_PCM_AUX_MODE_AUX
+ */
+
+ u16 sync_src;
+/* Synchronization source.
+ * Supported values:
+ * - #AFE_PORT_PCM_SYNC_SRC_EXTERNAL
+ * - #AFE_PORT_PCM_SYNC_SRC_INTERNAL
+ */
+
+ u16 frame_setting;
+/* Number of bits per frame.
+ * Supported values:
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_8
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_16
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_32
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_64
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_128
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_256
+ */
+
+ u16 quantype;
+/* PCM quantization type.
+ * Supported values:
+ * - #AFE_PORT_PCM_ALAW_NOPADDING
+ * - #AFE_PORT_PCM_MULAW_NOPADDING
+ * - #AFE_PORT_PCM_LINEAR_NOPADDING
+ * - #AFE_PORT_PCM_ALAW_PADDING
+ * - #AFE_PORT_PCM_MULAW_PADDING
+ * - #AFE_PORT_PCM_LINEAR_PADDING
+ */
+
+ u16 ctrl_data_out_enable;
+/* Specifies whether the PCM block shares the data-out
+ * signal to the drive with other masters.
+ * Supported values:
+ * - #AFE_PORT_PCM_CTRL_DATA_OE_DISABLE
+ * - #AFE_PORT_PCM_CTRL_DATA_OE_ENABLE
+ */
+ u16 reserved;
+ /* This field must be set to zero. */
+
+ u32 sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ */
+
+ u16 bit_width;
+/* Bit width of the sample.
+ * Supported values: 16
+ */
+
+ u16 num_channels;
+/* Number of channels.
+ * Supported values: 1 to 4
+ */
+
+ u16 slot_number_mapping[4];
+/* Specifies the slot number for the each channel in
+ * multi channel scenario.
+ * Supported values: 1 to 32
+ */
+} __packed;
+
+/*
+ * This param id is used to configure DIGI MIC interface
+ */
+#define AFE_PARAM_ID_DIGI_MIC_CONFIG 0x0001020F
+/* This version information is used to handle the new
+ * additions to the config interface in future in backward
+ * compatible manner.
+ */
+#define AFE_API_VERSION_DIGI_MIC_CONFIG 0x1
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to left 0.
+ */
+
+#define AFE_PORT_DIGI_MIC_MODE_LEFT0 0x1
+
+/*Enumeration for setting the digital mic configuration
+ * channel_mode parameter to right 0.
+ */
+
+
+#define AFE_PORT_DIGI_MIC_MODE_RIGHT0 0x2
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to left 1.
+ */
+
+#define AFE_PORT_DIGI_MIC_MODE_LEFT1 0x3
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to right 1.
+ */
+
+#define AFE_PORT_DIGI_MIC_MODE_RIGHT1 0x4
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to stereo 0.
+ */
+#define AFE_PORT_DIGI_MIC_MODE_STEREO0 0x5
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to stereo 1.
+ */
+
+
+#define AFE_PORT_DIGI_MIC_MODE_STEREO1 0x6
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to quad.
+ */
+
+#define AFE_PORT_DIGI_MIC_MODE_QUAD 0x7
+
+/* Payload of the #AFE_PARAM_ID_DIGI_MIC_CONFIG command's
+ * (DIGI MIC configuration
+ * parameter).
+ */
+struct afe_param_id_digi_mic_cfg {
+ u32 digi_mic_cfg_minor_version;
+/* Minor version used for tracking the version of the DIGI Mic
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_DIGI_MIC_CONFIG
+ */
+
+ u16 bit_width;
+/* Bit width of the sample.
+ * Supported values: 16
+ */
+
+ u16 channel_mode;
+/* Digital mic and multichannel operation.
+ * Supported values:
+ * - #AFE_PORT_DIGI_MIC_MODE_LEFT0
+ * - #AFE_PORT_DIGI_MIC_MODE_RIGHT0
+ * - #AFE_PORT_DIGI_MIC_MODE_LEFT1
+ * - #AFE_PORT_DIGI_MIC_MODE_RIGHT1
+ * - #AFE_PORT_DIGI_MIC_MODE_STEREO0
+ * - #AFE_PORT_DIGI_MIC_MODE_STEREO1
+ * - #AFE_PORT_DIGI_MIC_MODE_QUAD
+ */
+
+ u32 sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ */
+} __packed;
+
+/* This param id is used to configure HDMI interface */
+#define AFE_PARAM_ID_HDMI_CONFIG 0x00010210
+
+/* This version information is used to handle the new
+ * additions to the config interface in future in backward
+ * compatible manner.
+ */
+#define AFE_API_VERSION_HDMI_CONFIG 0x1
+
+/* Payload of the #AFE_PARAM_ID_HDMI_CONFIG command,
+ * which configures a multichannel HDMI audio interface.
+ */
+struct afe_param_id_hdmi_multi_chan_audio_cfg {
+ u32 hdmi_cfg_minor_version;
+/* Minor version used for tracking the version of the HDMI
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_HDMI_CONFIG
+ */
+
+u16 datatype;
+/* data type
+ * Supported values:
+ * - #LINEAR_PCM_DATA
+ * - #NON_LINEAR_DATA
+ * - #LINEAR_PCM_DATA_PACKED_IN_60958
+ * - #NON_LINEAR_DATA_PACKED_IN_60958
+ */
+
+u16 channel_allocation;
+/* HDMI channel allocation information for programming an HDMI
+ * frame. The default is 0 (Stereo).
+ *
+ * This information is defined in the HDMI standard, CEA 861-D
+ * (refer to @xhyperref{S1,[S1]}). The number of channels is also
+ * inferred from this parameter.
+ */
+
+
+u32 sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - 22050, 44100, 176400 for compressed streams
+ */
+
+ u16 bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+ u16 reserved;
+ /* This field must be set to zero. */
+} __packed;
+
+/* This param id is used to configure BT or FM(RIVA) interface */
+#define AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG 0x00010211
+
+/* This version information is used to handle the new
+ * additions to the config interface in future in backward
+ * compatible manner.
+ */
+#define AFE_API_VERSION_INTERNAL_BT_FM_CONFIG 0x1
+
+/* Payload of the #AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG
+ * command's BT voice/BT audio/FM configuration parameter.
+ */
+struct afe_param_id_internal_bt_fm_cfg {
+ u32 bt_fm_cfg_minor_version;
+/* Minor version used for tracking the version of the BT and FM
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_INTERNAL_BT_FM_CONFIG
+ */
+
+ u16 num_channels;
+/* Number of channels.
+ * Supported values: 1 to 2
+ */
+
+ u16 bit_width;
+/* Bit width of the sample.
+ * Supported values: 16
+ */
+
+ u32 sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K (only for BTSCO)
+ * - #AFE_PORT_SAMPLE_RATE_16K (only for BTSCO)
+ * - #AFE_PORT_SAMPLE_RATE_48K (FM and A2DP)
+ */
+} __packed;
+
+/* This param id is used to configure SLIMBUS interface using
+ * shared channel approach.
+ */
+
+
+#define AFE_PARAM_ID_SLIMBUS_CONFIG 0x00010212
+
+/* This version information is used to handle the new
+ * additions to the config interface in future in backward
+ * compatible manner.
+ */
+#define AFE_API_VERSION_SLIMBUS_CONFIG 0x1
+
+/* Enumeration for setting SLIMbus device ID 1. */
+#define AFE_SLIMBUS_DEVICE_1 0x0
+
+/* Enumeration for setting SLIMbus device ID 2. */
+#define AFE_SLIMBUS_DEVICE_2 0x1
+
+/* Enumeration for setting the SLIMbus data formats. */
+#define AFE_SB_DATA_FORMAT_NOT_INDICATED 0x0
+
+/* Enumeration for setting the maximum number of streams per
+ * device.
+ */
+
+#define AFE_PORT_MAX_AUDIO_CHAN_CNT 0x8
+
+/* Payload of the #AFE_PORT_CMD_SLIMBUS_CONFIG command's SLIMbus
+ * port configuration parameter.
+ */
+
+struct afe_param_id_slimbus_cfg {
+ u32 sb_cfg_minor_version;
+/* Minor version used for tracking the version of the SLIMBUS
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_SLIMBUS_CONFIG
+ */
+
+ u16 slimbus_dev_id;
+/* SLIMbus hardware device ID, which is required to handle
+ * multiple SLIMbus hardware blocks.
+ * Supported values: - #AFE_SLIMBUS_DEVICE_1 - #AFE_SLIMBUS_DEVICE_2
+ */
+
+
+ u16 bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+
+ u16 data_format;
+/* Data format supported by the SLIMbus hardware. The default is
+ * 0 (#AFE_SB_DATA_FORMAT_NOT_INDICATED), which indicates the
+ * hardware does not perform any format conversions before the data
+ * transfer.
+ */
+
+
+ u16 num_channels;
+/* Number of channels.
+ * Supported values: 1 to #AFE_PORT_MAX_AUDIO_CHAN_CNT
+ */
+
+ u8 shared_ch_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+/* Mapping of shared channel IDs (128 to 255) to which the
+ * master port is to be connected.
+ * Shared_channel_mapping[i] represents the shared channel assigned
+ * for audio channel i in multichannel audio data.
+ */
+
+ u32 sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K
+ */
+} __packed;
+
+
+/* ID of the parameter used by AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS to configure
+ * USB audio device parameter. It should be used with
+ * AFE_MODULE_AUDIO_DEV_INTERFACE
+ */
+#define AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS 0x000102A5
+
+/* Minor version used for tracking USB audio configuration */
+#define AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG 0x1
+
+/* Payload of the AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS parameter used by
+ * AFE_MODULE_AUDIO_DEV_INTERFACE.
+ */
+struct afe_param_id_usb_audio_dev_params {
+/* Minor version used for tracking USB audio device parameter.
+ * Supported values: AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG
+ */
+ u32 cfg_minor_version;
+/* Token of actual end USB aduio device */
+ u32 dev_token;
+} __packed;
+
+/* ID of the parameter used by AFE_PARAM_ID_USB_AUDIO_CONFIG to configure
+ * USB audio interface. It should be used with AFE_MODULE_AUDIO_DEV_INTERFACE
+ */
+#define AFE_PARAM_ID_USB_AUDIO_CONFIG 0x000102A4
+
+/* Payload of the AFE_PARAM_ID_USB_AUDIO_CONFIG parameter used by
+ * AFE_MODULE_AUDIO_DEV_INTERFACE.
+ */
+struct afe_param_id_usb_audio_cfg {
+/* Minor version used for tracking USB audio device configuration.
+ * Supported values: AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG
+ */
+ u32 cfg_minor_version;
+/* Sampling rate of the port.
+ * Supported values:
+ * - AFE_PORT_SAMPLE_RATE_8K
+ * - AFE_PORT_SAMPLE_RATE_11025
+ * - AFE_PORT_SAMPLE_RATE_12K
+ * - AFE_PORT_SAMPLE_RATE_16K
+ * - AFE_PORT_SAMPLE_RATE_22050
+ * - AFE_PORT_SAMPLE_RATE_24K
+ * - AFE_PORT_SAMPLE_RATE_32K
+ * - AFE_PORT_SAMPLE_RATE_44P1K
+ * - AFE_PORT_SAMPLE_RATE_48K
+ * - AFE_PORT_SAMPLE_RATE_96K
+ * - AFE_PORT_SAMPLE_RATE_192K
+ */
+ u32 sample_rate;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+ u16 bit_width;
+/* Number of channels.
+ * Supported values: 1 and 2
+ */
+ u16 num_channels;
+/* Data format supported by the USB. The supported value is
+ * 0 (#AFE_USB_AUDIO_DATA_FORMAT_LINEAR_PCM).
+ */
+ u16 data_format;
+/* this field must be 0 */
+ u16 reserved;
+/* device token of actual end USB aduio device */
+ u32 dev_token;
+} __packed;
+
+struct afe_usb_audio_dev_param_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_usb_audio_dev_params usb_dev;
+} __packed;
+
+/* This param id is used to configure Real Time Proxy interface. */
+#define AFE_PARAM_ID_RT_PROXY_CONFIG 0x00010213
+
+/* This version information is used to handle the new
+ * additions to the config interface in future in backward
+ * compatible manner.
+ */
+#define AFE_API_VERSION_RT_PROXY_CONFIG 0x1
+
+/* Payload of the #AFE_PARAM_ID_RT_PROXY_CONFIG
+ * command (real-time proxy port configuration parameter).
+ */
+struct afe_param_id_rt_proxy_port_cfg {
+ u32 rt_proxy_cfg_minor_version;
+/* Minor version used for tracking the version of rt-proxy
+ * config interface.
+ */
+
+ u16 bit_width;
+/* Bit width of the sample.
+ * Supported values: 16
+ */
+
+ u16 interleaved;
+/* Specifies whether the data exchanged between the AFE
+ * interface and real-time port is interleaved.
+ * Supported values: - 0 -- Non-interleaved (samples from each
+ * channel are contiguous in the buffer) - 1 -- Interleaved
+ * (corresponding samples from each input channel are interleaved
+ * within the buffer)
+ */
+
+
+ u16 frame_size;
+/* Size of the frames that are used for PCM exchanges with this
+ * port.
+ * Supported values: > 0, in bytes
+ * For example, 5 ms buffers of 16 bits and 16 kHz stereo samples
+ * is 5 ms * 16 samples/ms * 2 bytes/sample * 2 channels = 320
+ * bytes.
+ */
+ u16 jitter_allowance;
+/* Configures the amount of jitter that the port will allow.
+ * Supported values: > 0
+ * For example, if +/-10 ms of jitter is anticipated in the timing
+ * of sending frames to the port, and the configuration is 16 kHz
+ * mono with 16-bit samples, this field is 10 ms * 16 samples/ms * 2
+ * bytes/sample = 320.
+ */
+
+ u16 low_water_mark;
+/* Low watermark in bytes (including all channels).
+ * Supported values:
+ * - 0 -- Do not send any low watermark events
+ * - > 0 -- Low watermark for triggering an event
+ * If the number of bytes in an internal circular buffer is lower
+ * than this low_water_mark parameter, a LOW_WATER_MARK event is
+ * sent to applications (via the #AFE_EVENT_RT_PROXY_PORT_STATUS
+ * event).
+ * Use of watermark events is optional for debugging purposes.
+ */
+
+ u16 high_water_mark;
+/* High watermark in bytes (including all channels).
+ * Supported values:
+ * - 0 -- Do not send any high watermark events
+ * - > 0 -- High watermark for triggering an event
+ * If the number of bytes in an internal circular buffer exceeds
+ * TOTAL_CIRC_BUF_SIZE minus high_water_mark, a high watermark event
+ * is sent to applications (via the #AFE_EVENT_RT_PROXY_PORT_STATUS
+ * event).
+ * The use of watermark events is optional and for debugging
+ * purposes.
+ */
+
+
+ u32 sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ */
+
+ u16 num_channels;
+/* Number of channels.
+ * Supported values: 1 to #AFE_PORT_MAX_AUDIO_CHAN_CNT
+ */
+
+ u16 reserved;
+ /* For 32 bit alignment. */
+} __packed;
+
+
+/* This param id is used to configure the Pseudoport interface */
+
+#define AFE_PARAM_ID_PSEUDO_PORT_CONFIG 0x00010219
+
+/* Version information used to handle future additions to the configuration
+ * interface (for backward compatibility).
+ */
+#define AFE_API_VERSION_PSEUDO_PORT_CONFIG 0x1
+
+/* Enumeration for setting the timing_mode parameter to faster than real
+ * time.
+ */
+#define AFE_PSEUDOPORT_TIMING_MODE_FTRT 0x0
+
+/* Enumeration for setting the timing_mode parameter to real time using
+ * timers.
+ */
+#define AFE_PSEUDOPORT_TIMING_MODE_TIMER 0x1
+
+/* Payload of the AFE_PARAM_ID_PSEUDO_PORT_CONFIG parameter used by
+ * AFE_MODULE_AUDIO_DEV_INTERFACE.
+ */
+struct afe_param_id_pseudo_port_cfg {
+ u32 pseud_port_cfg_minor_version;
+ /*
+ * Minor version used for tracking the version of the pseudoport
+ * configuration interface.
+ */
+
+ u16 bit_width;
+ /* Bit width of the sample at values 16, 24 */
+
+ u16 num_channels;
+ /* Number of channels at values 1 to 8 */
+
+ u16 data_format;
+ /* Non-linear data format supported by the pseudoport (for future use).
+ * At values #AFE_LINEAR_PCM_DATA
+ */
+
+ u16 timing_mode;
+ /* Indicates whether the pseudoport synchronizes to the clock or
+ * operates faster than real time.
+ * at values
+ * - #AFE_PSEUDOPORT_TIMING_MODE_FTRT
+ * - #AFE_PSEUDOPORT_TIMING_MODE_TIMER @tablebulletend
+ */
+
+ u32 sample_rate;
+ /* Sample rate at which the pseudoport will run.
+ * at values
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_32K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K @tablebulletend
+ */
+} __packed;
+
+#define AFE_PARAM_ID_TDM_CONFIG 0x0001029D
+
+#define AFE_API_VERSION_TDM_CONFIG 1
+
+#define AFE_PORT_TDM_SHORT_SYNC_BIT_MODE 0
+#define AFE_PORT_TDM_LONG_SYNC_MODE 1
+#define AFE_PORT_TDM_SHORT_SYNC_SLOT_MODE 2
+
+#define AFE_PORT_TDM_SYNC_SRC_EXTERNAL 0
+#define AFE_PORT_TDM_SYNC_SRC_INTERNAL 1
+
+#define AFE_PORT_TDM_CTRL_DATA_OE_DISABLE 0
+#define AFE_PORT_TDM_CTRL_DATA_OE_ENABLE 1
+
+#define AFE_PORT_TDM_SYNC_NORMAL 0
+#define AFE_PORT_TDM_SYNC_INVERT 1
+
+#define AFE_PORT_TDM_DATA_DELAY_0_BCLK_CYCLE 0
+#define AFE_PORT_TDM_DATA_DELAY_1_BCLK_CYCLE 1
+#define AFE_PORT_TDM_DATA_DELAY_2_BCLK_CYCLE 2
+
+/* Payload of the AFE_PARAM_ID_TDM_CONFIG parameter used by
+ * AFE_MODULE_AUDIO_DEV_INTERFACE.
+ */
+struct afe_param_id_tdm_cfg {
+ u32 tdm_cfg_minor_version;
+ /* < Minor version used to track TDM configuration.
+ * @values #AFE_API_VERSION_TDM_CONFIG
+ */
+
+ u32 num_channels;
+ /* < Number of enabled slots for TDM frame.
+ * @values 1 to 8
+ */
+
+ u32 sample_rate;
+ /* < Sampling rate of the port.
+ * @values
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_24K
+ * - #AFE_PORT_SAMPLE_RATE_32K
+ * - #AFE_PORT_SAMPLE_RATE_48K @tablebulletend
+ */
+
+ u32 bit_width;
+ /* < Bit width of the sample.
+ * @values 16, 24
+ */
+
+ u16 data_format;
+ /* < Data format: linear and compressed
+ * @values
+ * - #AFE_LINEAR_PCM_DATA
+ * - #AFE_NON_LINEAR_DATA @tablebulletend
+ */
+
+ u16 sync_mode;
+ /* < TDM synchronization setting.
+ * @values (short, long, slot) sync mode
+ * - #AFE_PORT_TDM_SHORT_SYNC_BIT_MODE
+ * - #AFE_PORT_TDM_LONG_SYNC_MODE
+ * - #AFE_PORT_TDM_SHORT_SYNC_SLOT_MODE @tablebulletend
+ */
+
+ u16 sync_src;
+ /* < Synchronization source.
+ * @values
+ * - #AFE_PORT_TDM_SYNC_SRC_EXTERNAL
+ * - #AFE_PORT_TDM_SYNC_SRC_INTERNAL @tablebulletend
+ */
+
+ u16 nslots_per_frame;
+ /* < Number of slots per frame. Typical : 1, 2, 4, 8, 16, 32.
+ * @values 1 - 32
+ */
+
+ u16 ctrl_data_out_enable;
+ /* < Specifies whether the TDM block shares the data-out signal to the
+ * drive with other masters.
+ * @values
+ * - #AFE_PORT_TDM_CTRL_DATA_OE_DISABLE
+ * - #AFE_PORT_TDM_CTRL_DATA_OE_ENABLE @tablebulletend
+ */
+
+ u16 ctrl_invert_sync_pulse;
+ /* < Specifies whether to invert the sync or not.
+ * @values
+ * - #AFE_PORT_TDM_SYNC_NORMAL
+ * - #AFE_PORT_TDM_SYNC_INVERT @tablebulletend
+ */
+
+ u16 ctrl_sync_data_delay;
+ /* < Specifies the number of bit clock to delay data with respect to
+ * sync edge.
+ * @values
+ * - #AFE_PORT_TDM_DATA_DELAY_0_BCLK_CYCLE
+ * - #AFE_PORT_TDM_DATA_DELAY_1_BCLK_CYCLE
+ * - #AFE_PORT_TDM_DATA_DELAY_2_BCLK_CYCLE @tablebulletend
+ */
+
+ u16 slot_width;
+ /* < Slot width of the slot in a TDM frame. (slot_width >= bit_width)
+ * have to be satisfied.
+ * @values 16, 24, 32
+ */
+
+ u32 slot_mask;
+ /* < Position of active slots. When that bit is set,
+ * that paricular slot is active.
+ * Number of active slots can be inferred by number of
+ * bits set in the mask. Only 8 individual bits can be enabled.
+ * Bits 0..31 corresponding to slot 0..31
+ * @values 1 to 2^32 - 1
+ */
+} __packed;
+
+/* ID of Time Divsion Multiplexing (TDM) module,
+ * which is used for configuring the AFE TDM.
+ *
+ * This module supports following parameter IDs:
+ * - #AFE_PORT_TDM_SLOT_CONFIG
+ *
+ * To configure the TDM interface, the client must use the
+ * #AFE_PORT_CMD_SET_PARAM command, and fill the module ID with the
+ * respective parameter IDs as listed above.
+ */
+
+#define AFE_MODULE_TDM 0x0001028A
+
+/* ID of the parameter used by #AFE_MODULE_TDM to configure
+ * the TDM slot mapping. #AFE_PORT_CMD_SET_PARAM can use this parameter ID.
+ */
+#define AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG 0x00010297
+
+/* Version information used to handle future additions to slot mapping
+ * configuration (for backward compatibility).
+ */
+#define AFE_API_VERSION_SLOT_MAPPING_CONFIG 0x1
+
+/* Data align type */
+#define AFE_SLOT_MAPPING_DATA_ALIGN_MSB 0
+#define AFE_SLOT_MAPPING_DATA_ALIGN_LSB 1
+
+#define AFE_SLOT_MAPPING_OFFSET_INVALID 0xFFFF
+
+/* Payload of the AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG
+ * command's TDM configuration parameter.
+ */
+struct afe_param_id_slot_mapping_cfg {
+ u32 minor_version;
+ /* < Minor version used for tracking TDM slot configuration.
+ * @values #AFE_API_VERSION_TDM_SLOT_CONFIG
+ */
+
+ u16 num_channel;
+ /* < number of channel of the audio sample.
+ * @values 1, 2, 4, 6, 8 @tablebulletend
+ */
+
+ u16 bitwidth;
+ /* < Slot bit width for each channel
+ * @values 16, 24, 32
+ */
+
+ u32 data_align_type;
+ /* < indicate how data packed from slot_offset for 32 slot bit width
+ * in case of sample bit width is 24.
+ * @values
+ * #AFE_SLOT_MAPPING_DATA_ALIGN_MSB
+ * #AFE_SLOT_MAPPING_DATA_ALIGN_LSB
+ */
+
+ u16 offset[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+ /* < Array of the slot mapping start offset in bytes for this frame.
+ * The bytes is counted from 0. The 0 is mapped to the 1st byte
+ * in or out of the digital serial data line this sub-frame belong to.
+ * slot_offset[] setting is per-channel based.
+ * The max num of channel supported is 8.
+ * The valid offset value must always be continuly placed in from
+ * index 0.
+ * Set offset as AFE_SLOT_MAPPING_OFFSET_INVALID for not used arrays.
+ * If "slot_bitwidth_per_channel" is 32 and "sample_bitwidth" is 24,
+ * "data_align_type" is used to indicate how 24 bit sample data in
+ * aligning with 32 bit slot width per-channel.
+ * @values, in byte
+ */
+} __packed;
+
+/* ID of the parameter used by #AFE_MODULE_TDM to configure
+ * the customer TDM header. #AFE_PORT_CMD_SET_PARAM can use this parameter ID.
+ */
+#define AFE_PARAM_ID_CUSTOM_TDM_HEADER_CONFIG 0x00010298
+
+/* Version information used to handle future additions to custom TDM header
+ * configuration (for backward compatibility).
+ */
+#define AFE_API_VERSION_CUSTOM_TDM_HEADER_CONFIG 0x1
+
+#define AFE_CUSTOM_TDM_HEADER_TYPE_INVALID 0x0
+#define AFE_CUSTOM_TDM_HEADER_TYPE_DEFAULT 0x1
+#define AFE_CUSTOM_TDM_HEADER_TYPE_ENTERTAINMENT_MOST 0x2
+
+#define AFE_CUSTOM_TDM_HEADER_MAX_CNT 0x8
+
+/* Payload of the AFE_PARAM_ID_CUSTOM_TDM_HEADER_CONFIG parameter ID */
+struct afe_param_id_custom_tdm_header_cfg {
+ u32 minor_version;
+ /* < Minor version used for tracking custom TDM header configuration.
+ * @values #AFE_API_VERSION_CUSTOM_TDM_HEADER_CONFIG
+ */
+
+ u16 start_offset;
+ /* < the slot mapping start offset in bytes from this sub-frame
+ * The bytes is counted from 0. The 0 is mapped to the 1st byte in or
+ * out of the digital serial data line this sub-frame belong to.
+ * @values, in byte,
+ * supported values are 0, 4, 8
+ */
+
+ u16 header_width;
+ /* < the header width per-frame followed.
+ * 2 bytes for MOST/TDM case
+ * @values, in byte
+ * supported value is 2
+ */
+
+ u16 header_type;
+ /* < Indicate what kind of custom TDM header it is.
+ * @values #AFE_CUSTOM_TDM_HEADER_TYPE_INVALID = 0
+ * #AFE_CUSTOM_TDM_HEADER_TYPE_DEFAULT = 1 (for AAN channel per MOST)
+ * #AFE_CUSTOM_TDM_HEADER_TYPE_ENTERTAINMENT_MOST = 2
+ * (for entertainment channel, which will overwrite
+ * AFE_API_VERSION_TDM_SAD_HEADER_TYPE_DEFAULT per MOST)
+ */
+
+ u16 num_frame_repeat;
+ /* < num of header followed.
+ * @values, supported value is 8
+ */
+ u16 header[AFE_CUSTOM_TDM_HEADER_MAX_CNT];
+ /* < SAD header for MOST/TDM case is followed as payload as below.
+ * The size of followed SAD header in bytes is num_of_frame_repeat *
+ * header_width_per_frame, which is 2 * 8 = 16 bytes here.
+ * the supported payload format is in uint16_t as below
+ * uint16_t header0; SyncHi 0x3C Info[4] - CodecType -> 0x3C00
+ * uint16_t header1; SyncLo 0xB2 Info[5] - SampleWidth -> 0xB218
+ * uint16_t header2; DTCP Info Info[6] - unused -> 0x0
+ * uint16_t header3; Extension Info[7] - ASAD-Value -> 0xC0
+ * uint16_t header4; Reserved Info[0] - Num of bytes following -> 0x7
+ * uint16_t header5; Reserved Info[1] - Media Type -> 0x0
+ * uint16_t header6; Reserved Info[2] - Bitrate[kbps] - High Byte -> 0x0
+ * uint16_t header7; Reserved Info[3] - Bitrate[kbps] - Low Byte -> 0x0
+ */
+} __packed;
+
+struct afe_slot_mapping_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_slot_mapping_cfg slot_mapping;
+} __packed;
+
+struct afe_custom_tdm_header_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_custom_tdm_header_cfg custom_tdm_header;
+} __packed;
+
+struct afe_tdm_port_config {
+ struct afe_param_id_tdm_cfg tdm;
+ struct afe_param_id_slot_mapping_cfg slot_mapping;
+ struct afe_param_id_custom_tdm_header_cfg custom_tdm_header;
+} __packed;
+
+#define AFE_PARAM_ID_DEVICE_HW_DELAY 0x00010243
+#define AFE_API_VERSION_DEVICE_HW_DELAY 0x1
+
+struct afe_param_id_device_hw_delay_cfg {
+ uint32_t device_hw_delay_minor_version;
+ uint32_t delay_in_us;
+} __packed;
+
+#define AFE_PARAM_ID_SET_TOPOLOGY 0x0001025A
+#define AFE_API_VERSION_TOPOLOGY_V1 0x1
+
+struct afe_param_id_set_topology_cfg {
+ /*
+ * Minor version used for tracking afe topology id configuration.
+ * @values #AFE_API_VERSION_TOPOLOGY_V1
+ */
+ u32 minor_version;
+ /*
+ * Id of the topology for the afe session.
+ * @values Any valid AFE topology ID
+ */
+ u32 topology_id;
+} __packed;
+
+
+/*
+ * Generic encoder module ID.
+ * This module supports the following parameter IDs:
+ * #AVS_ENCODER_PARAM_ID_ENC_FMT_ID (cannot be set run time)
+ * #AVS_ENCODER_PARAM_ID_ENC_CFG_BLK (may be set run time)
+ * #AVS_ENCODER_PARAM_ID_ENC_BITRATE (may be set run time)
+ * #AVS_ENCODER_PARAM_ID_PACKETIZER_ID (cannot be set run time)
+ * Opcode - AVS_MODULE_ID_ENCODER
+ * AFE Command AFE_PORT_CMD_SET_PARAM_V2 supports this module ID.
+ */
+#define AFE_MODULE_ID_ENCODER 0x00013229
+
+/* Macro for defining the packetizer ID: COP. */
+#define AFE_MODULE_ID_PACKETIZER_COP 0x0001322A
+
+/*
+ * Packetizer type parameter for the #AVS_MODULE_ID_ENCODER module.
+ * This parameter cannot be set runtime.
+ */
+#define AFE_ENCODER_PARAM_ID_PACKETIZER_ID 0x0001322E
+
+/*
+ * Encoder config block parameter for the #AVS_MODULE_ID_ENCODER module.
+ * This parameter may be set runtime.
+ */
+#define AFE_ENCODER_PARAM_ID_ENC_CFG_BLK 0x0001322C
+
+/*
+ * Encoder format ID parameter for the #AVS_MODULE_ID_ENCODER module.
+ * This parameter cannot be set runtime.
+ */
+#define AFE_ENCODER_PARAM_ID_ENC_FMT_ID 0x0001322B
+
+/*
+ * Data format to send compressed data
+ * is transmitted/received over Slimbus lines.
+ */
+#define AFE_SB_DATA_FORMAT_GENERIC_COMPRESSED 0x3
+
+/*
+ * ID for AFE port module. This will be used to define port properties.
+ * This module supports following parameter IDs:
+ * #AFE_PARAM_ID_PORT_MEDIA_TYPE
+ * To configure the port property, the client must use the
+ * #AFE_PORT_CMD_SET_PARAM_V2 command,
+ * and fill the module ID with the respective parameter IDs as listed above.
+ * @apr_hdr_fields
+ * Opcode -- AFE_MODULE_PORT
+ */
+#define AFE_MODULE_PORT 0x000102a6
+
+/*
+ * ID of the parameter used by #AFE_MODULE_PORT to set the port media type.
+ * parameter ID is currently supported using#AFE_PORT_CMD_SET_PARAM_V2 command.
+ */
+#define AFE_PARAM_ID_PORT_MEDIA_TYPE 0x000102a7
+
+/*
+ * Macros for defining the "data_format" field in the
+ * #AFE_PARAM_ID_PORT_MEDIA_TYPE
+ */
+#define AFE_PORT_DATA_FORMAT_PCM 0x0
+#define AFE_PORT_DATA_FORMAT_GENERIC_COMPRESSED 0x1
+
+/*
+ * Macro for defining the "minor_version" field in the
+ * #AFE_PARAM_ID_PORT_MEDIA_TYPE
+ */
+#define AFE_API_VERSION_PORT_MEDIA_TYPE 0x1
+
+#define ASM_MEDIA_FMT_NONE 0x0
+
+/*
+ * Media format ID for SBC encode configuration.
+ * @par SBC encode configuration (asm_sbc_enc_cfg_t)
+ * @table{weak__asm__sbc__enc__cfg__t}
+ */
+#define ASM_MEDIA_FMT_SBC 0x00010BF2
+
+/* SBC channel Mono mode.*/
+#define ASM_MEDIA_FMT_SBC_CHANNEL_MODE_MONO 1
+
+/* SBC channel Stereo mode. */
+#define ASM_MEDIA_FMT_SBC_CHANNEL_MODE_STEREO 2
+
+/* SBC channel Dual Mono mode. */
+#define ASM_MEDIA_FMT_SBC_CHANNEL_MODE_DUAL_MONO 8
+
+/* SBC channel Joint Stereo mode. */
+#define ASM_MEDIA_FMT_SBC_CHANNEL_MODE_JOINT_STEREO 9
+
+/* SBC bit allocation method = loudness. */
+#define ASM_MEDIA_FMT_SBC_ALLOCATION_METHOD_LOUDNESS 0
+
+/* SBC bit allocation method = SNR. */
+#define ASM_MEDIA_FMT_SBC_ALLOCATION_METHOD_SNR 1
+
+
+/*
+ * Payload of the SBC encoder configuration parameters in the
+ * #ASM_MEDIA_FMT_SBC media format.
+ */
+struct asm_sbc_enc_cfg_t {
+ /*
+ * Number of subbands.
+ * @values 4, 8
+ */
+ uint32_t num_subbands;
+
+ /*
+ * Size of the encoded block in samples.
+ * @values 4, 8, 12, 16
+ */
+ uint32_t blk_len;
+
+ /*
+ * Mode used to allocate bits between channels.
+ * @values
+ * 0 (Native mode)
+ * #ASM_MEDIA_FMT_SBC_CHANNEL_MODE_MONO
+ * #ASM_MEDIA_FMT_SBC_CHANNEL_MODE_STEREO
+ * #ASM_MEDIA_FMT_SBC_CHANNEL_MODE_DUAL_MONO
+ * #ASM_MEDIA_FMT_SBC_CHANNEL_MODE_JOINT_STEREO
+ * Native mode indicates that encoding must be performed with the number
+ * of channels at the input.
+ * If postprocessing outputs one-channel data, Mono mode is used. If
+ * postprocessing outputs two-channel data, Stereo mode is used.
+ * The number of channels must not change during encoding.
+ */
+ uint32_t channel_mode;
+
+ /*
+ * Encoder bit allocation method.
+ * @values
+ * #ASM_MEDIA_FMT_SBC_ALLOCATION_METHOD_LOUDNESS
+ * #ASM_MEDIA_FMT_SBC_ALLOCATION_METHOD_SNR @tablebulletend
+ */
+ uint32_t alloc_method;
+
+ /*
+ * Number of encoded bits per second.
+ * @values
+ * Mono channel -- Maximum of 320 kbps
+ * Stereo channel -- Maximum of 512 kbps @tablebulletend
+ */
+ uint32_t bit_rate;
+
+ /*
+ * Number of samples per second.
+ * @values 0 (Native mode), 16000, 32000, 44100, 48000 Hz
+ * Native mode indicates that encoding must be performed with the
+ * sampling rate at the input.
+ * The sampling rate must not change during encoding.
+ */
+ uint32_t sample_rate;
+};
+
+#define ASM_MEDIA_FMT_AAC_AOT_LC 2
+#define ASM_MEDIA_FMT_AAC_AOT_SBR 5
+#define ASM_MEDIA_FMT_AAC_AOT_PS 29
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS 0
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW 3
+
+struct asm_aac_enc_cfg_v2_t {
+
+ /* Encoding rate in bits per second.*/
+ uint32_t bit_rate;
+
+ /*
+ * Encoding mode.
+ * Supported values:
+ * #ASM_MEDIA_FMT_AAC_AOT_LC
+ * #ASM_MEDIA_FMT_AAC_AOT_SBR
+ * #ASM_MEDIA_FMT_AAC_AOT_PS
+ */
+ uint32_t enc_mode;
+
+ /*
+ * AAC format flag.
+ * Supported values:
+ * #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS
+ * #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW
+ */
+ uint16_t aac_fmt_flag;
+
+ /*
+ * Number of channels to encode.
+ * Supported values:
+ * 0 - Native mode
+ * 1 - Mono
+ * 2 - Stereo
+ * Other values are not supported.
+ * @note1hang The eAAC+ encoder mode supports only stereo.
+ * Native mode indicates that encoding must be performed with the
+ * number of channels at the input.
+ * The number of channels must not change during encoding.
+ */
+ uint16_t channel_cfg;
+
+ /*
+ * Number of samples per second.
+ * Supported values: - 0 -- Native mode - For other values,
+ * Native mode indicates that encoding must be performed with the
+ * sampling rate at the input.
+ * The sampling rate must not change during encoding.
+ */
+ uint32_t sample_rate;
+} __packed;
+
+/* FMT ID for apt-X Classic */
+#define ASM_MEDIA_FMT_APTX 0x000131ff
+
+/* FMT ID for apt-X HD */
+#define ASM_MEDIA_FMT_APTX_HD 0x00013200
+
+#define PCM_CHANNEL_L 1
+#define PCM_CHANNEL_R 2
+#define PCM_CHANNEL_C 3
+
+struct asm_custom_enc_cfg_aptx_t {
+ uint32_t sample_rate;
+ /* Mono or stereo */
+ uint16_t num_channels;
+ uint16_t reserved;
+ /* num_ch == 1, then PCM_CHANNEL_C,
+ * num_ch == 2, then {PCM_CHANNEL_L, PCM_CHANNEL_R}
+ */
+ uint8_t channel_mapping[8];
+ uint32_t custom_size;
+} __packed;
+
+struct afe_enc_fmt_id_param_t {
+ /*
+ * Supported values:
+ * #ASM_MEDIA_FMT_SBC
+ * #ASM_MEDIA_FMT_AAC_V2
+ * Any OpenDSP supported values
+ */
+ uint32_t fmt_id;
+} __packed;
+
+struct afe_port_media_type_t {
+ /*
+ * Minor version
+ * @values #AFE_API_VERSION_PORT_MEDIA_TYPE.
+ */
+ uint32_t minor_version;
+
+ /*
+ * Sampling rate of the port.
+ * @values
+ * #AFE_PORT_SAMPLE_RATE_8K
+ * #AFE_PORT_SAMPLE_RATE_11_025K
+ * #AFE_PORT_SAMPLE_RATE_12K
+ * #AFE_PORT_SAMPLE_RATE_16K
+ * #AFE_PORT_SAMPLE_RATE_22_05K
+ * #AFE_PORT_SAMPLE_RATE_24K
+ * #AFE_PORT_SAMPLE_RATE_32K
+ * #AFE_PORT_SAMPLE_RATE_44_1K
+ * #AFE_PORT_SAMPLE_RATE_48K
+ * #AFE_PORT_SAMPLE_RATE_88_2K
+ * #AFE_PORT_SAMPLE_RATE_96K
+ * #AFE_PORT_SAMPLE_RATE_176_4K
+ * #AFE_PORT_SAMPLE_RATE_192K
+ * #AFE_PORT_SAMPLE_RATE_352_8K
+ * #AFE_PORT_SAMPLE_RATE_384K
+ */
+ uint32_t sample_rate;
+
+ /*
+ * Bit width of the sample.
+ * @values 16, 24
+ */
+ uint16_t bit_width;
+
+ /*
+ * Number of channels.
+ * @values 1 to #AFE_PORT_MAX_AUDIO_CHAN_CNT
+ */
+ uint16_t num_channels;
+
+ /*
+ * Data format supported by this port.
+ * If the port media type and device media type are different,
+ * it signifies a encoding/decoding use case
+ * @values
+ * #AFE_PORT_DATA_FORMAT_PCM
+ * #AFE_PORT_DATA_FORMAT_GENERIC_COMPRESSED
+ */
+ uint16_t data_format;
+
+ /*This field must be set to zero.*/
+ uint16_t reserved;
+} __packed;
+
+union afe_enc_config_data {
+ struct asm_sbc_enc_cfg_t sbc_config;
+ struct asm_aac_enc_cfg_v2_t aac_config;
+ struct asm_custom_enc_cfg_aptx_t aptx_config;
+};
+
+struct afe_enc_config {
+ u32 format;
+ union afe_enc_config_data data;
+};
+
+struct afe_enc_cfg_blk_param_t {
+ uint32_t enc_cfg_blk_size;
+ /*
+ *Size of the encoder configuration block that follows this member
+ */
+ union afe_enc_config_data enc_blk_config;
+};
+
+/*
+ * Payload of the AVS_ENCODER_PARAM_ID_PACKETIZER_ID parameter.
+ */
+struct avs_enc_packetizer_id_param_t {
+ /*
+ * Supported values:
+ * #AVS_MODULE_ID_PACKETIZER_COP
+ * Any OpenDSP supported values
+ */
+ uint32_t enc_packetizer_id;
+};
+
+union afe_port_config {
+ struct afe_param_id_pcm_cfg pcm;
+ struct afe_param_id_i2s_cfg i2s;
+ struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
+ struct afe_param_id_slimbus_cfg slim_sch;
+ struct afe_param_id_rt_proxy_port_cfg rtproxy;
+ struct afe_param_id_internal_bt_fm_cfg int_bt_fm;
+ struct afe_param_id_pseudo_port_cfg pseudo_port;
+ struct afe_param_id_device_hw_delay_cfg hw_delay;
+ struct afe_param_id_spdif_cfg spdif;
+ struct afe_param_id_set_topology_cfg topology;
+ struct afe_param_id_tdm_cfg tdm;
+ struct afe_param_id_usb_audio_cfg usb_audio;
+ struct afe_enc_fmt_id_param_t enc_fmt;
+ struct afe_port_media_type_t media_type;
+ struct afe_enc_cfg_blk_param_t enc_blk_param;
+ struct avs_enc_packetizer_id_param_t enc_pkt_id_param;
+} __packed;
+
+struct afe_audioif_config_command_no_payload {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+} __packed;
+
+struct afe_audioif_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ union afe_port_config port;
+} __packed;
+
+#define AFE_PORT_CMD_DEVICE_START 0x000100E5
+
+/* Payload of the #AFE_PORT_CMD_DEVICE_START.*/
+struct afe_port_cmd_device_start {
+ struct apr_hdr hdr;
+ u16 port_id;
+/* Port interface and direction (Rx or Tx) to start. An even
+ * number represents the Rx direction, and an odd number represents
+ * the Tx direction.
+ */
+
+
+ u16 reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.*/
+
+} __packed;
+
+#define AFE_PORT_CMD_DEVICE_STOP 0x000100E6
+
+/* Payload of the #AFE_PORT_CMD_DEVICE_STOP. */
+struct afe_port_cmd_device_stop {
+ struct apr_hdr hdr;
+ u16 port_id;
+/* Port interface and direction (Rx or Tx) to start. An even
+ * number represents the Rx direction, and an odd number represents
+ * the Tx direction.
+ */
+
+ u16 reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.*/
+} __packed;
+
+#define AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS 0x000100EA
+
+/* Memory map regions command payload used by the
+ * #AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS .
+ * This structure allows clients to map multiple shared memory
+ * regions in a single command. Following this structure are
+ * num_regions of afe_service_shared_map_region_payload.
+ */
+struct afe_service_cmd_shared_mem_map_regions {
+ struct apr_hdr hdr;
+u16 mem_pool_id;
+/* Type of memory on which this memory region is mapped.
+ * Supported values:
+ * - #ADSP_MEMORY_MAP_EBI_POOL
+ * - #ADSP_MEMORY_MAP_SMI_POOL
+ * - #ADSP_MEMORY_MAP_SHMEM8_4K_POOL
+ * - Other values are reserved
+ *
+ * The memory pool ID implicitly defines the characteristics of the
+ * memory. Characteristics may include alignment type, permissions,
+ * etc.
+ *
+ * ADSP_MEMORY_MAP_EBI_POOL is External Buffer Interface type memory
+ * ADSP_MEMORY_MAP_SMI_POOL is Shared Memory Interface type memory
+ * ADSP_MEMORY_MAP_SHMEM8_4K_POOL is shared memory, byte
+ * addressable, and 4 KB aligned.
+ */
+
+
+ u16 num_regions;
+/* Number of regions to map.
+ * Supported values:
+ * - Any value greater than zero
+ */
+
+ u32 property_flag;
+/* Configures one common property for all the regions in the
+ * payload.
+ *
+ * Supported values: - 0x00000000 to 0x00000001
+ *
+ * b0 - bit 0 indicates physical or virtual mapping 0 Shared memory
+ * address provided in afe_service_shared_map_region_payloadis a
+ * physical address. The shared memory needs to be mapped( hardware
+ * TLB entry) and a software entry needs to be added for internal
+ * book keeping.
+ *
+ * 1 Shared memory address provided in
+ * afe_service_shared_map_region_payloadis a virtual address. The
+ * shared memory must not be mapped (since hardware TLB entry is
+ * already available) but a software entry needs to be added for
+ * internal book keeping. This can be useful if two services with in
+ * ADSP is communicating via APR. They can now directly communicate
+ * via the Virtual address instead of Physical address. The virtual
+ * regions must be contiguous. num_regions must be 1 in this case.
+ *
+ * b31-b1 - reserved bits. must be set to zero
+ */
+
+
+} __packed;
+/* Map region payload used by the
+ * afe_service_shared_map_region_payloadstructure.
+ */
+struct afe_service_shared_map_region_payload {
+ u32 shm_addr_lsw;
+/* least significant word of starting address in the memory
+ * region to map. It must be contiguous memory, and it must be 4 KB
+ * aligned.
+ * Supported values: - Any 32 bit value
+ */
+
+
+ u32 shm_addr_msw;
+/* most significant word of startng address in the memory region
+ * to map. For 32 bit shared memory address, this field must be set
+ * to zero. For 36 bit shared memory address, bit31 to bit 4 must be
+ * set to zero
+ *
+ * Supported values: - For 32 bit shared memory address, this field
+ * must be set to zero. - For 36 bit shared memory address, bit31 to
+ * bit 4 must be set to zero - For 64 bit shared memory address, any
+ * 32 bit value
+ */
+
+
+ u32 mem_size_bytes;
+/* Number of bytes in the region. The aDSP will always map the
+ * regions as virtual contiguous memory, but the memory size must be
+ * in multiples of 4 KB to avoid gaps in the virtually contiguous
+ * mapped memory.
+ *
+ * Supported values: - multiples of 4KB
+ */
+
+} __packed;
+
+#define AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS 0x000100EB
+struct afe_service_cmdrsp_shared_mem_map_regions {
+ u32 mem_map_handle;
+/* A memory map handle encapsulating shared memory attributes is
+ * returned iff AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS command is
+ * successful. In the case of failure , a generic APR error response
+ * is returned to the client.
+ *
+ * Supported Values: - Any 32 bit value
+ */
+
+} __packed;
+#define AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS 0x000100EC
+/* Memory unmap regions command payload used by the
+ * #AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS
+ *
+ * This structure allows clients to unmap multiple shared memory
+ * regions in a single command.
+ */
+
+
+struct afe_service_cmd_shared_mem_unmap_regions {
+ struct apr_hdr hdr;
+u32 mem_map_handle;
+/* memory map handle returned by
+ * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS commands
+ *
+ * Supported Values:
+ * - Any 32 bit value
+ */
+} __packed;
+
+#define AFE_PORT_CMD_GET_PARAM_V2 0x000100F0
+
+/* Payload of the #AFE_PORT_CMD_GET_PARAM_V2 command,
+ * which queries for one post/preprocessing parameter of a
+ * stream.
+ */
+struct afe_port_cmd_get_param_v2 {
+ u16 port_id;
+/* Port interface and direction (Rx or Tx) to start. */
+
+ u16 payload_size;
+/* Maximum data size of the parameter ID/module ID combination.
+ * This is a multiple of four bytes
+ * Supported values: > 0
+ */
+
+ u32 payload_address_lsw;
+/* LSW of 64 bit Payload address. Address should be 32-byte,
+ * 4kbyte aligned and must be contig memory.
+ */
+
+
+ u32 payload_address_msw;
+/* MSW of 64 bit Payload address. In case of 32-bit shared
+ * memory address, this field must be set to zero. In case of 36-bit
+ * shared memory address, bit-4 to bit-31 must be set to zero.
+ * Address should be 32-byte, 4kbyte aligned and must be contiguous
+ * memory.
+ */
+
+ u32 mem_map_handle;
+/* Memory map handle returned by
+ * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS commands.
+ * Supported Values: - NULL -- Message. The parameter data is
+ * in-band. - Non-NULL -- The parameter data is Out-band.Pointer to
+ * - the physical address in shared memory of the payload data.
+ * For detailed payload content, see the afe_port_param_data_v2
+ * structure
+ */
+
+
+ u32 module_id;
+/* ID of the module to be queried.
+ * Supported values: Valid module ID
+ */
+
+ u32 param_id;
+/* ID of the parameter to be queried.
+ * Supported values: Valid parameter ID
+ */
+} __packed;
+
+#define AFE_PORT_CMDRSP_GET_PARAM_V2 0x00010106
+
+/* Payload of the #AFE_PORT_CMDRSP_GET_PARAM_V2 message, which
+ * responds to an #AFE_PORT_CMD_GET_PARAM_V2 command.
+ *
+ * Immediately following this structure is the parameters structure
+ * (afe_port_param_data) containing the response(acknowledgment)
+ * parameter payload. This payload is included for an in-band
+ * scenario. For an address/shared memory-based set parameter, this
+ * payload is not needed.
+ */
+
+
+struct afe_port_cmdrsp_get_param_v2 {
+ u32 status;
+} __packed;
+
+#define AFE_PARAM_ID_LPASS_CORE_SHARED_CLOCK_CONFIG 0x0001028C
+#define AFE_API_VERSION_LPASS_CORE_SHARED_CLK_CONFIG 0x1
+
+/* Payload of the AFE_PARAM_ID_LPASS_CORE_SHARED_CLOCK_CONFIG parameter used by
+ * AFE_MODULE_AUDIO_DEV_INTERFACE.
+ */
+struct afe_param_id_lpass_core_shared_clk_cfg {
+ u32 lpass_core_shared_clk_cfg_minor_version;
+/*
+ * Minor version used for lpass core shared clock configuration
+ * Supported value: AFE_API_VERSION_LPASS_CORE_SHARED_CLK_CONFIG
+ */
+ u32 enable;
+/*
+ * Specifies whether the lpass core shared clock is
+ * enabled (1) or disabled (0).
+ */
+} __packed;
+
+struct afe_lpass_core_shared_clk_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_lpass_core_shared_clk_cfg clk_cfg;
+} __packed;
+
+/* adsp_afe_service_commands.h */
+
+#define ADSP_MEMORY_MAP_EBI_POOL 0
+
+#define ADSP_MEMORY_MAP_SMI_POOL 1
+#define ADSP_MEMORY_MAP_IMEM_POOL 2
+#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3
+
+/* Definition of virtual memory flag */
+#define ADSP_MEMORY_MAP_VIRTUAL_MEMORY 1
+
+/* Definition of physical memory flag */
+#define ADSP_MEMORY_MAP_PHYSICAL_MEMORY 0
+
+#define NULL_POPP_TOPOLOGY 0x00010C68
+#define NULL_COPP_TOPOLOGY 0x00010312
+#define DEFAULT_COPP_TOPOLOGY 0x00010314
+#define DEFAULT_POPP_TOPOLOGY 0x00010BE4
+#define COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY 0x0001076B
+#define COMPRESS_PASSTHROUGH_NONE_TOPOLOGY 0x00010774
+#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
+#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
+#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
+#define VPM_TX_DM_RFECNS_COPP_TOPOLOGY 0x00010F86
+#define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX 0x10015002
+#define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE 0x10028000
+
+/* Memory map regions command payload used by the
+ * #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS
+ * commands.
+ *
+ * This structure allows clients to map multiple shared memory
+ * regions in a single command. Following this structure are
+ * num_regions of avs_shared_map_region_payload.
+ */
+
+
+struct avs_cmd_shared_mem_map_regions {
+ struct apr_hdr hdr;
+ u16 mem_pool_id;
+/* Type of memory on which this memory region is mapped.
+ *
+ * Supported values: - #ADSP_MEMORY_MAP_EBI_POOL -
+ * #ADSP_MEMORY_MAP_SMI_POOL - #ADSP_MEMORY_MAP_IMEM_POOL
+ * (unsupported) - #ADSP_MEMORY_MAP_SHMEM8_4K_POOL - Other values
+ * are reserved
+ *
+ * The memory ID implicitly defines the characteristics of the
+ * memory. Characteristics may include alignment type, permissions,
+ * etc.
+ *
+ * SHMEM8_4K is shared memory, byte addressable, and 4 KB aligned.
+ */
+
+
+ u16 num_regions;
+ /* Number of regions to map.*/
+
+ u32 property_flag;
+/* Configures one common property for all the regions in the
+ * payload. No two regions in the same memory map regions cmd can
+ * have differnt property. Supported values: - 0x00000000 to
+ * 0x00000001
+ *
+ * b0 - bit 0 indicates physical or virtual mapping 0 shared memory
+ * address provided in avs_shared_map_regions_payload is physical
+ * address. The shared memory needs to be mapped( hardware TLB
+ * entry)
+ *
+ * and a software entry needs to be added for internal book keeping.
+ *
+ * 1 Shared memory address provided in MayPayload[usRegions] is
+ * virtual address. The shared memory must not be mapped (since
+ * hardware TLB entry is already available) but a software entry
+ * needs to be added for internal book keeping. This can be useful
+ * if two services with in ADSP is communicating via APR. They can
+ * now directly communicate via the Virtual address instead of
+ * Physical address. The virtual regions must be contiguous.
+ *
+ * b31-b1 - reserved bits. must be set to zero
+ */
+
+} __packed;
+
+struct avs_shared_map_region_payload {
+ u32 shm_addr_lsw;
+/* least significant word of shared memory address of the memory
+ * region to map. It must be contiguous memory, and it must be 4 KB
+ * aligned.
+ */
+
+ u32 shm_addr_msw;
+/* most significant word of shared memory address of the memory
+ * region to map. For 32 bit shared memory address, this field must
+ * tbe set to zero. For 36 bit shared memory address, bit31 to bit 4
+ * must be set to zero
+ */
+
+ u32 mem_size_bytes;
+/* Number of bytes in the region.
+ *
+ * The aDSP will always map the regions as virtual contiguous
+ * memory, but the memory size must be in multiples of 4 KB to avoid
+ * gaps in the virtually contiguous mapped memory.
+ */
+
+} __packed;
+
+struct avs_cmd_shared_mem_unmap_regions {
+ struct apr_hdr hdr;
+ u32 mem_map_handle;
+/* memory map handle returned by ASM_CMD_SHARED_MEM_MAP_REGIONS
+ * , ADM_CMD_SHARED_MEM_MAP_REGIONS, commands
+ */
+
+} __packed;
+
+/* Memory map command response payload used by the
+ * #ASM_CMDRSP_SHARED_MEM_MAP_REGIONS
+ * ,#ADM_CMDRSP_SHARED_MEM_MAP_REGIONS
+ */
+
+
+struct avs_cmdrsp_shared_mem_map_regions {
+ u32 mem_map_handle;
+/* A memory map handle encapsulating shared memory attributes is
+ * returned
+ */
+
+} __packed;
+
+/*adsp_audio_memmap_api.h*/
+
+/* ASM related data structures */
+struct asm_wma_cfg {
+ u16 format_tag;
+ u16 ch_cfg;
+ u32 sample_rate;
+ u32 avg_bytes_per_sec;
+ u16 block_align;
+ u16 valid_bits_per_sample;
+ u32 ch_mask;
+ u16 encode_opt;
+ u16 adv_encode_opt;
+ u32 adv_encode_opt2;
+ u32 drc_peak_ref;
+ u32 drc_peak_target;
+ u32 drc_ave_ref;
+ u32 drc_ave_target;
+} __packed;
+
+struct asm_wmapro_cfg {
+ u16 format_tag;
+ u16 ch_cfg;
+ u32 sample_rate;
+ u32 avg_bytes_per_sec;
+ u16 block_align;
+ u16 valid_bits_per_sample;
+ u32 ch_mask;
+ u16 encode_opt;
+ u16 adv_encode_opt;
+ u32 adv_encode_opt2;
+ u32 drc_peak_ref;
+ u32 drc_peak_target;
+ u32 drc_ave_ref;
+ u32 drc_ave_target;
+} __packed;
+
+struct asm_aac_cfg {
+ u16 format;
+ u16 aot;
+ u16 ep_config;
+ u16 section_data_resilience;
+ u16 scalefactor_data_resilience;
+ u16 spectral_data_resilience;
+ u16 ch_cfg;
+ u16 reserved;
+ u32 sample_rate;
+} __packed;
+
+struct asm_amrwbplus_cfg {
+ u32 size_bytes;
+ u32 version;
+ u32 num_channels;
+ u32 amr_band_mode;
+ u32 amr_dtx_mode;
+ u32 amr_frame_fmt;
+ u32 amr_lsf_idx;
+} __packed;
+
+struct asm_flac_cfg {
+ u32 sample_rate;
+ u32 ext_sample_rate;
+ u32 min_frame_size;
+ u32 max_frame_size;
+ u16 stream_info_present;
+ u16 min_blk_size;
+ u16 max_blk_size;
+ u16 ch_cfg;
+ u16 sample_size;
+ u16 md5_sum;
+};
+
+struct asm_alac_cfg {
+ u32 frame_length;
+ u8 compatible_version;
+ u8 bit_depth;
+ u8 pb;
+ u8 mb;
+ u8 kb;
+ u8 num_channels;
+ u16 max_run;
+ u32 max_frame_bytes;
+ u32 avg_bit_rate;
+ u32 sample_rate;
+ u32 channel_layout_tag;
+};
+
+struct asm_g711_dec_cfg {
+ u32 sample_rate;
+};
+
+struct asm_vorbis_cfg {
+ u32 bit_stream_fmt;
+};
+
+struct asm_ape_cfg {
+ u16 compatible_version;
+ u16 compression_level;
+ u32 format_flags;
+ u32 blocks_per_frame;
+ u32 final_frame_blocks;
+ u32 total_frames;
+ u16 bits_per_sample;
+ u16 num_channels;
+ u32 sample_rate;
+ u32 seek_table_present;
+};
+
+struct asm_dsd_cfg {
+ u16 num_version;
+ u16 is_bitwise_big_endian;
+ u16 dsd_channel_block_size;
+ u16 num_channels;
+ u8 channel_mapping[8];
+ u32 dsd_data_rate;
+};
+
+struct asm_softpause_params {
+ u32 enable;
+ u32 period;
+ u32 step;
+ u32 rampingcurve;
+} __packed;
+
+struct asm_softvolume_params {
+ u32 period;
+ u32 step;
+ u32 rampingcurve;
+} __packed;
+
+#define ASM_END_POINT_DEVICE_MATRIX 0
+
+#define PCM_CHANNEL_NULL 0
+
+/* Front left channel. */
+#define PCM_CHANNEL_FL 1
+
+/* Front right channel. */
+#define PCM_CHANNEL_FR 2
+
+/* Front center channel. */
+#define PCM_CHANNEL_FC 3
+
+/* Left surround channel.*/
+#define PCM_CHANNEL_LS 4
+
+/* Right surround channel.*/
+#define PCM_CHANNEL_RS 5
+
+/* Low frequency effect channel. */
+#define PCM_CHANNEL_LFE 6
+
+/* Center surround channel; Rear center channel. */
+#define PCM_CHANNEL_CS 7
+
+/* Left back channel; Rear left channel. */
+#define PCM_CHANNEL_LB 8
+
+/* Right back channel; Rear right channel. */
+#define PCM_CHANNEL_RB 9
+
+/* Top surround channel. */
+#define PCM_CHANNELS 10
+
+/* Center vertical height channel.*/
+#define PCM_CHANNEL_CVH 11
+
+/* Mono surround channel.*/
+#define PCM_CHANNEL_MS 12
+
+/* Front left of center. */
+#define PCM_CHANNEL_FLC 13
+
+/* Front right of center. */
+#define PCM_CHANNEL_FRC 14
+
+/* Rear left of center. */
+#define PCM_CHANNEL_RLC 15
+
+/* Rear right of center. */
+#define PCM_CHANNEL_RRC 16
+
+#define PCM_FORMAT_MAX_NUM_CHANNEL 8
+
+#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5
+
+#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 0x00010DDC
+
+#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 0x0001320C
+
+#define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF
+
+#define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
+
+#define ASM_MAX_EQ_BANDS 12
+
+#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98
+
+struct asm_data_cmd_media_fmt_update_v2 {
+u32 fmt_blk_size;
+ /* Media format block size in bytes.*/
+} __packed;
+
+struct asm_multi_channel_pcm_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+
+ u16 num_channels;
+ /* Number of channels. Supported values: 1 to 8 */
+ u16 bits_per_sample;
+/* Number of bits per sample per channel. * Supported values:
+ * 16, 24 * When used for playback, the client must send 24-bit
+ * samples packed in 32-bit words. The 24-bit samples must be placed
+ * in the most significant 24 bits of the 32-bit word. When used for
+ * recording, the aDSP sends 24-bit samples packed in 32-bit words.
+ * The 24-bit samples are placed in the most significant 24 bits of
+ * the 32-bit word.
+ */
+
+
+ u32 sample_rate;
+/* Number of samples per second (in Hertz).
+ * Supported values: 2000 to 48000
+ */
+
+ u16 is_signed;
+ /* Flag that indicates the samples are signed (1). */
+
+ u16 reserved;
+ /* reserved field for 32 bit alignment. must be set to zero. */
+
+ u8 channel_mapping[8];
+/* Channel array of size 8.
+ * Supported values:
+ * - #PCM_CHANNEL_L
+ * - #PCM_CHANNEL_R
+ * - #PCM_CHANNEL_C
+ * - #PCM_CHANNEL_LS
+ * - #PCM_CHANNEL_RS
+ * - #PCM_CHANNEL_LFE
+ * - #PCM_CHANNEL_CS
+ * - #PCM_CHANNEL_LB
+ * - #PCM_CHANNEL_RB
+ * - #PCM_CHANNELS
+ * - #PCM_CHANNEL_CVH
+ * - #PCM_CHANNEL_MS
+ * - #PCM_CHANNEL_FLC
+ * - #PCM_CHANNEL_FRC
+ * - #PCM_CHANNEL_RLC
+ * - #PCM_CHANNEL_RRC
+ *
+ * Channel[i] mapping describes channel I. Each element i of the
+ * array describes channel I inside the buffer where 0 @le I <
+ * num_channels. An unused channel is set to zero.
+ */
+} __packed;
+
+struct asm_multi_channel_pcm_fmt_blk_v3 {
+ uint16_t num_channels;
+/*
+ * Number of channels
+ * Supported values: 1 to 8
+ */
+
+ uint16_t bits_per_sample;
+/*
+ * Number of bits per sample per channel
+ * Supported values: 16, 24
+ */
+
+ uint32_t sample_rate;
+/*
+ * Number of samples per second
+ * Supported values: 2000 to 48000, 96000,192000 Hz
+ */
+
+ uint16_t is_signed;
+/* Flag that indicates that PCM samples are signed (1) */
+
+ uint16_t sample_word_size;
+/*
+ * Size in bits of the word that holds a sample of a channel.
+ * Supported values: 12,24,32
+ */
+
+ uint8_t channel_mapping[8];
+/*
+ * Each element, i, in the array describes channel i inside the buffer where
+ * 0 <= i < num_channels. Unused channels are set to 0.
+ */
+} __packed;
+
+struct asm_multi_channel_pcm_fmt_blk_v4 {
+ uint16_t num_channels;
+/*
+ * Number of channels
+ * Supported values: 1 to 8
+ */
+
+ uint16_t bits_per_sample;
+/*
+ * Number of bits per sample per channel
+ * Supported values: 16, 24, 32
+ */
+
+ uint32_t sample_rate;
+/*
+ * Number of samples per second
+ * Supported values: 2000 to 48000, 96000,192000 Hz
+ */
+
+ uint16_t is_signed;
+/* Flag that indicates that PCM samples are signed (1) */
+
+ uint16_t sample_word_size;
+/*
+ * Size in bits of the word that holds a sample of a channel.
+ * Supported values: 12,24,32
+ */
+
+ uint8_t channel_mapping[8];
+/*
+ * Each element, i, in the array describes channel i inside the buffer where
+ * 0 <= i < num_channels. Unused channels are set to 0.
+ */
+ uint16_t endianness;
+/*
+ * Flag to indicate the endianness of the pcm sample
+ * Supported values: 0 - Little endian (all other formats)
+ * 1 - Big endian (AIFF)
+ */
+ uint16_t mode;
+/*
+ * Mode to provide additional info about the pcm input data.
+ * Supported values: 0 - Default QFs (Q15 for 16b, Q23 for packed 24b,
+ * Q31 for unpacked 24b or 32b)
+ * 15 - for 16 bit
+ * 23 - for 24b packed or 8.24 format
+ * 31 - for 24b unpacked or 32bit
+ */
+} __packed;
+
+/*
+ * Payload of the multichannel PCM configuration parameters in
+ * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 media format.
+ */
+struct asm_multi_channel_pcm_fmt_blk_param_v3 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+ struct asm_multi_channel_pcm_fmt_blk_v3 param;
+} __packed;
+
+/*
+ * Payload of the multichannel PCM configuration parameters in
+ * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 media format.
+ */
+struct asm_multi_channel_pcm_fmt_blk_param_v4 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+ struct asm_multi_channel_pcm_fmt_blk_v4 param;
+} __packed;
+
+struct asm_stream_cmd_set_encdec_param {
+ u32 param_id;
+ /* ID of the parameter. */
+
+ u32 param_size;
+/* Data size of this parameter, in bytes. The size is a multiple
+ * of 4 bytes.
+ */
+
+} __packed;
+
+struct asm_enc_cfg_blk_param_v2 {
+ u32 frames_per_buf;
+/* Number of encoded frames to pack into each buffer.
+ *
+ * @note1hang This is only guidance information for the aDSP. The
+ * number of encoded frames put into each buffer (specified by the
+ * client) is less than or equal to this number.
+ */
+
+ u32 enc_cfg_blk_size;
+/* Size in bytes of the encoder configuration block that follows
+ * this member.
+ */
+
+} __packed;
+
+/* @brief Dolby Digital Plus end point configuration structure
+ */
+struct asm_dec_ddp_endp_param_v2 {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ int endp_param_value;
+} __packed;
+
+/*
+ * Payload of the multichannel PCM encoder configuration parameters in
+ * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 media format.
+ */
+
+struct asm_multi_channel_pcm_enc_cfg_v4 {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+ uint16_t num_channels;
+ /*
+ * Number of PCM channels.
+ * @values
+ * - 0 -- Native mode
+ * - 1 -- 8 channels
+ * Native mode indicates that encoding must be performed with the number
+ * of channels at the input.
+ */
+ uint16_t bits_per_sample;
+ /*
+ * Number of bits per sample per channel.
+ * @values 16, 24
+ */
+ uint32_t sample_rate;
+ /*
+ * Number of samples per second.
+ * @values 0, 8000 to 48000 Hz
+ * A value of 0 indicates the native sampling rate. Encoding is
+ * performed at the input sampling rate.
+ */
+ uint16_t is_signed;
+ /*
+ * Flag that indicates the PCM samples are signed (1). Currently, only
+ * signed PCM samples are supported.
+ */
+ uint16_t sample_word_size;
+ /*
+ * The size in bits of the word that holds a sample of a channel.
+ * @values 16, 24, 32
+ * 16-bit samples are always placed in 16-bit words:
+ * sample_word_size = 1.
+ * 24-bit samples can be placed in 32-bit words or in consecutive
+ * 24-bit words.
+ * - If sample_word_size = 32, 24-bit samples are placed in the
+ * most significant 24 bits of a 32-bit word.
+ * - If sample_word_size = 24, 24-bit samples are placed in
+ * 24-bit words. @tablebulletend
+ */
+ uint8_t channel_mapping[8];
+ /*
+ * Channel mapping array expected at the encoder output.
+ * Channel[i] mapping describes channel i inside the buffer, where
+ * 0 @le i < num_channels. All valid used channels must be present at
+ * the beginning of the array.
+ * If Native mode is set for the channels, this field is ignored.
+ * @values See Section @xref{dox:PcmChannelDefs}
+ */
+ uint16_t endianness;
+ /*
+ * Flag to indicate the endianness of the pcm sample
+ * Supported values: 0 - Little endian (all other formats)
+ * 1 - Big endian (AIFF)
+ */
+ uint16_t mode;
+ /*
+ * Mode to provide additional info about the pcm input data.
+ * Supported values: 0 - Default QFs (Q15 for 16b, Q23 for packed 24b,
+ * Q31 for unpacked 24b or 32b)
+ * 15 - for 16 bit
+ * 23 - for 24b packed or 8.24 format
+ * 31 - for 24b unpacked or 32bit
+ */
+} __packed;
+
+/*
+ * Payload of the multichannel PCM encoder configuration parameters in
+ * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 media format.
+ */
+
+struct asm_multi_channel_pcm_enc_cfg_v3 {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+ uint16_t num_channels;
+ /*
+ * Number of PCM channels.
+ * @values
+ * - 0 -- Native mode
+ * - 1 -- 8 channels
+ * Native mode indicates that encoding must be performed with the number
+ * of channels at the input.
+ */
+ uint16_t bits_per_sample;
+ /*
+ * Number of bits per sample per channel.
+ * @values 16, 24
+ */
+ uint32_t sample_rate;
+ /*
+ * Number of samples per second.
+ * @values 0, 8000 to 48000 Hz
+ * A value of 0 indicates the native sampling rate. Encoding is
+ * performed at the input sampling rate.
+ */
+ uint16_t is_signed;
+ /*
+ * Flag that indicates the PCM samples are signed (1). Currently, only
+ * signed PCM samples are supported.
+ */
+ uint16_t sample_word_size;
+ /*
+ * The size in bits of the word that holds a sample of a channel.
+ * @values 16, 24, 32
+ * 16-bit samples are always placed in 16-bit words:
+ * sample_word_size = 1.
+ * 24-bit samples can be placed in 32-bit words or in consecutive
+ * 24-bit words.
+ * - If sample_word_size = 32, 24-bit samples are placed in the
+ * most significant 24 bits of a 32-bit word.
+ * - If sample_word_size = 24, 24-bit samples are placed in
+ * 24-bit words. @tablebulletend
+ */
+ uint8_t channel_mapping[8];
+ /*
+ * Channel mapping array expected at the encoder output.
+ * Channel[i] mapping describes channel i inside the buffer, where
+ * 0 @le i < num_channels. All valid used channels must be present at
+ * the beginning of the array.
+ * If Native mode is set for the channels, this field is ignored.
+ * @values See Section @xref{dox:PcmChannelDefs}
+ */
+};
+
+/* @brief Multichannel PCM encoder configuration structure used
+ * in the #ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 command.
+ */
+
+struct asm_multi_channel_pcm_enc_cfg_v2 {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+ uint16_t num_channels;
+/*< Number of PCM channels.
+ *
+ * Supported values: - 0 -- Native mode - 1 -- 8 Native mode
+ * indicates that encoding must be performed with the number of
+ * channels at the input.
+ */
+
+ uint16_t bits_per_sample;
+/*< Number of bits per sample per channel.
+ * Supported values: 16, 24
+ */
+
+ uint32_t sample_rate;
+/*< Number of samples per second (in Hertz).
+ *
+ * Supported values: 0, 8000 to 48000 A value of 0 indicates the
+ * native sampling rate. Encoding is performed at the input sampling
+ * rate.
+ */
+
+ uint16_t is_signed;
+/*< Specifies whether the samples are signed (1). Currently,
+ * only signed samples are supported.
+ */
+
+ uint16_t reserved;
+/*< reserved field for 32 bit alignment. must be set to zero.*/
+
+
+ uint8_t channel_mapping[8];
+} __packed;
+
+#define ASM_MEDIA_FMT_MP3 0x00010BE9
+#define ASM_MEDIA_FMT_AAC_V2 0x00010DA6
+
+/* @xreflabel
+ * {hdr:AsmMediaFmtDolbyAac} Media format ID for the
+ * Dolby AAC decoder. This format ID is be used if the client wants
+ * to use the Dolby AAC decoder to decode MPEG2 and MPEG4 AAC
+ * contents.
+ */
+
+#define ASM_MEDIA_FMT_DOLBY_AAC 0x00010D86
+
+/* Enumeration for the audio data transport stream AAC format. */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS 0
+
+/* Enumeration for low overhead audio stream AAC format. */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_LOAS 1
+
+/* Enumeration for the audio data interchange format
+ * AAC format.
+ */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADIF 2
+
+/* Enumeration for the raw AAC format. */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW 3
+
+#define ASM_MEDIA_FMT_AAC_AOT_LC 2
+#define ASM_MEDIA_FMT_AAC_AOT_SBR 5
+#define ASM_MEDIA_FMT_AAC_AOT_PS 29
+#define ASM_MEDIA_FMT_AAC_AOT_BSAC 22
+
+struct asm_aac_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+
+ u16 aac_fmt_flag;
+/* Bitstream format option.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_LOAS
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADIF
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW
+ */
+
+ u16 audio_objype;
+/* Audio Object Type (AOT) present in the AAC stream.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AAC_AOT_LC
+ * - #ASM_MEDIA_FMT_AAC_AOT_SBR
+ * - #ASM_MEDIA_FMT_AAC_AOT_BSAC
+ * - #ASM_MEDIA_FMT_AAC_AOT_PS
+ * - Otherwise -- Not supported
+ */
+
+ u16 channel_config;
+/* Number of channels present in the AAC stream.
+ * Supported values:
+ * - 1 -- Mono
+ * - 2 -- Stereo
+ * - 6 -- 5.1 content
+ */
+
+ u16 total_size_of_PCE_bits;
+/* greater or equal to zero. * -In case of RAW formats and
+ * channel config = 0 (PCE), client can send * the bit stream
+ * containing PCE immediately following this structure * (in-band).
+ * -This number does not include bits included for 32 bit alignment.
+ * -If zero, then the PCE info is assumed to be available in the
+ * audio -bit stream & not in-band.
+ */
+
+ u32 sample_rate;
+/* Number of samples per second (in Hertz).
+ *
+ * Supported values: 8000, 11025, 12000, 16000, 22050, 24000, 32000,
+ * 44100, 48000
+ *
+ * This field must be equal to the sample rate of the AAC-LC
+ * decoder's output. - For MP4 or 3GP containers, this is indicated
+ * by the samplingFrequencyIndex field in the AudioSpecificConfig
+ * element. - For ADTS format, this is indicated by the
+ * samplingFrequencyIndex in the ADTS fixed header. - For ADIF
+ * format, this is indicated by the samplingFrequencyIndex in the
+ * program_config_element present in the ADIF header.
+ */
+
+} __packed;
+
+struct asm_aac_enc_cfg_v2 {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+
+ u32 bit_rate;
+ /* Encoding rate in bits per second. */
+ u32 enc_mode;
+/* Encoding mode.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AAC_AOT_LC
+ * - #ASM_MEDIA_FMT_AAC_AOT_SBR
+ * - #ASM_MEDIA_FMT_AAC_AOT_PS
+ */
+ u16 aac_fmt_flag;
+/* AAC format flag.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW
+ */
+ u16 channel_cfg;
+/* Number of channels to encode.
+ * Supported values:
+ * - 0 -- Native mode
+ * - 1 -- Mono
+ * - 2 -- Stereo
+ * - Other values are not supported.
+ * @note1hang The eAAC+ encoder mode supports only stereo.
+ * Native mode indicates that encoding must be performed with the
+ * number of channels at the input.
+ * The number of channels must not change during encoding.
+ */
+
+ u32 sample_rate;
+/* Number of samples per second.
+ * Supported values: - 0 -- Native mode - For other values,
+ * Native mode indicates that encoding must be performed with the
+ * sampling rate at the input.
+ * The sampling rate must not change during encoding.
+ */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_G711_ALAW_FS 0x00010BF7
+#define ASM_MEDIA_FMT_G711_MLAW_FS 0x00010C2E
+
+struct asm_g711_enc_cfg_v2 {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+
+ u32 sample_rate;
+/*
+ * Number of samples per second.
+ * Supported values: 8000, 16000 Hz
+ */
+
+} __packed;
+
+struct asm_vorbis_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+ u32 bit_stream_fmt;
+/* Bit stream format.
+ * Supported values:
+ * - 0 -- Raw bitstream
+ * - 1 -- Transcoded bitstream
+ *
+ * Transcoded bitstream containing the size of the frame as the first
+ * word in each frame.
+ */
+
+} __packed;
+
+struct asm_flac_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+
+ u16 is_stream_info_present;
+/* Specifies whether stream information is present in the FLAC format
+ * block.
+ *
+ * Supported values:
+ * - 0 -- Stream information is not present in this message
+ * - 1 -- Stream information is present in this message
+ *
+ * When set to 1, the FLAC bitstream was successfully parsed by the
+ * client, and other fields in the FLAC format block can be read by the
+ * decoder to get metadata stream information.
+ */
+
+ u16 num_channels;
+/* Number of channels for decoding.
+ * Supported values: 1 to 2
+ */
+
+ u16 min_blk_size;
+/* Minimum block size (in samples) used in the stream. It must be less
+ * than or equal to max_blk_size.
+ */
+
+ u16 max_blk_size;
+/* Maximum block size (in samples) used in the stream. If the
+ * minimum block size equals the maximum block size, a fixed block
+ * size stream is implied.
+ */
+
+ u16 md5_sum[8];
+/* MD5 signature array of the unencoded audio data. This allows the
+ * decoder to determine if an error exists in the audio data, even when
+ * the error does not result in an invalid bitstream.
+ */
+
+ u32 sample_rate;
+/* Number of samples per second.
+ * Supported values: 8000 to 48000 Hz
+ */
+
+ u32 min_frame_size;
+/* Minimum frame size used in the stream.
+ * Supported values:
+ * - > 0 bytes
+ * - 0 -- The value is unknown
+ */
+
+ u32 max_frame_size;
+/* Maximum frame size used in the stream.
+ * Supported values:
+ * -- > 0 bytes
+ * -- 0 . The value is unknown
+ */
+
+ u16 sample_size;
+/* Bits per sample.Supported values: 8, 16 */
+
+ u16 reserved;
+/* Clients must set this field to zero
+ */
+
+} __packed;
+
+struct asm_alac_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+
+ u32 frame_length;
+ u8 compatible_version;
+ u8 bit_depth;
+ u8 pb;
+ u8 mb;
+ u8 kb;
+ u8 num_channels;
+ u16 max_run;
+ u32 max_frame_bytes;
+ u32 avg_bit_rate;
+ u32 sample_rate;
+ u32 channel_layout_tag;
+
+} __packed;
+
+struct asm_g711_dec_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+ u32 sample_rate;
+} __packed;
+
+struct asm_ape_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+
+ u16 compatible_version;
+ u16 compression_level;
+ u32 format_flags;
+ u32 blocks_per_frame;
+ u32 final_frame_blocks;
+ u32 total_frames;
+ u16 bits_per_sample;
+ u16 num_channels;
+ u32 sample_rate;
+ u32 seek_table_present;
+
+} __packed;
+
+struct asm_dsd_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+
+ u16 num_version;
+ u16 is_bitwise_big_endian;
+ u16 dsd_channel_block_size;
+ u16 num_channels;
+ u8 channel_mapping[8];
+ u32 dsd_data_rate;
+
+} __packed;
+
+#define ASM_MEDIA_FMT_AMRNB_FS 0x00010BEB
+
+/* Enumeration for 4.75 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MR475 0
+
+/* Enumeration for 5.15 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MR515 1
+
+/* Enumeration for 5.90 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR59 2
+
+/* Enumeration for 6.70 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR67 3
+
+/* Enumeration for 7.40 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR74 4
+
+/* Enumeration for 7.95 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR795 5
+
+/* Enumeration for 10.20 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR102 6
+
+/* Enumeration for 12.20 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR122 7
+
+/* Enumeration for AMR-NB Discontinuous Transmission mode off. */
+#define ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_OFF 0
+
+/* Enumeration for AMR-NB DTX mode VAD1. */
+#define ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_VAD1 1
+
+/* Enumeration for AMR-NB DTX mode VAD2. */
+#define ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_VAD2 2
+
+/* Enumeration for AMR-NB DTX mode auto. */
+#define ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_AUTO 3
+
+struct asm_amrnb_enc_cfg {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+
+ u16 enc_mode;
+/* AMR-NB encoding rate.
+ * Supported values:
+ * Use the ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_*
+ * macros
+ */
+
+ u16 dtx_mode;
+/* Specifies whether DTX mode is disabled or enabled.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_OFF
+ * - #ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_VAD1
+ */
+} __packed;
+
+#define ASM_MEDIA_FMT_AMRWB_FS 0x00010BEC
+
+/* Enumeration for 6.6 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR66 0
+
+/* Enumeration for 8.85 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR885 1
+
+/* Enumeration for 12.65 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1265 2
+
+/* Enumeration for 14.25 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1425 3
+
+/* Enumeration for 15.85 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1585 4
+
+/* Enumeration for 18.25 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1825 5
+
+/* Enumeration for 19.85 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1985 6
+
+/* Enumeration for 23.05 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR2305 7
+
+/* Enumeration for 23.85 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR2385 8
+
+struct asm_amrwb_enc_cfg {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+
+ u16 enc_mode;
+/* AMR-WB encoding rate.
+ * Suupported values:
+ * Use the ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_*
+ * macros
+ */
+
+ u16 dtx_mode;
+/* Specifies whether DTX mode is disabled or enabled.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_OFF
+ * - #ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_VAD1
+ */
+} __packed;
+
+#define ASM_MEDIA_FMT_V13K_FS 0x00010BED
+
+/* Enumeration for 14.4 kbps V13K Encoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1440 0
+
+/* Enumeration for 12.2 kbps V13K Encoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1220 1
+
+/* Enumeration for 11.2 kbps V13K Encoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1120 2
+
+/* Enumeration for 9.0 kbps V13K Encoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR90 3
+
+/* Enumeration for 7.2 kbps V13K eEncoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR720 4
+
+/* Enumeration for 1/8 vocoder rate.*/
+#define ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE 1
+
+/* Enumeration for 1/4 vocoder rate. */
+#define ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE 2
+
+/* Enumeration for 1/2 vocoder rate. */
+#define ASM_MEDIA_FMT_VOC_HALF_RATE 3
+
+/* Enumeration for full vocoder rate. */
+#define ASM_MEDIA_FMT_VOC_FULL_RATE 4
+
+struct asm_v13k_enc_cfg {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+ u16 max_rate;
+/* Maximum allowed encoder frame rate.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_HALF_RATE
+ * - #ASM_MEDIA_FMT_VOC_FULL_RATE
+ */
+
+ u16 min_rate;
+/* Minimum allowed encoder frame rate.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_HALF_RATE
+ * - #ASM_MEDIA_FMT_VOC_FULL_RATE
+ */
+
+ u16 reduced_rate_cmd;
+/* Reduced rate command, used to change
+ * the average bitrate of the V13K
+ * vocoder.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1440 (Default)
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1220
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1120
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR90
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR720
+ */
+
+ u16 rate_mod_cmd;
+/* Rate modulation command. Default = 0.
+ *- If bit 0=1, rate control is enabled.
+ *- If bit 1=1, the maximum number of consecutive full rate
+ * frames is limited with numbers supplied in
+ * bits 2 to 10.
+ *- If bit 1=0, the minimum number of non-full rate frames
+ * in between two full rate frames is forced to
+ * the number supplied in bits 2 to 10. In both cases, if necessary,
+ * half rate is used to substitute full rate. - Bits 15 to 10 are
+ * reserved and must all be set to zero.
+ */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_EVRC_FS 0x00010BEE
+
+/* EVRC encoder configuration structure used in the
+ * #ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 command.
+ */
+struct asm_evrc_enc_cfg {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+ u16 max_rate;
+/* Maximum allowed encoder frame rate.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_HALF_RATE
+ * - #ASM_MEDIA_FMT_VOC_FULL_RATE
+ */
+
+ u16 min_rate;
+/* Minimum allowed encoder frame rate.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_HALF_RATE
+ * - #ASM_MEDIA_FMT_VOC_FULL_RATE
+ */
+
+ u16 rate_mod_cmd;
+/* Rate modulation command. Default: 0.
+ * - If bit 0=1, rate control is enabled.
+ * - If bit 1=1, the maximum number of consecutive full rate frames
+ * is limited with numbers supplied in bits 2 to 10.
+ *
+ * - If bit 1=0, the minimum number of non-full rate frames in
+ * between two full rate frames is forced to the number supplied in
+ * bits 2 to 10. In both cases, if necessary, half rate is used to
+ * substitute full rate.
+ *
+ * - Bits 15 to 10 are reserved and must all be set to zero.
+ */
+
+ u16 reserved;
+ /* Reserved. Clients must set this field to zero. */
+} __packed;
+
+#define ASM_MEDIA_FMT_WMA_V10PRO_V2 0x00010DA7
+
+struct asm_wmaprov10_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+
+ u16 fmtag;
+/* WMA format type.
+ * Supported values:
+ * - 0x162 -- WMA 9 Pro
+ * - 0x163 -- WMA 9 Pro Lossless
+ * - 0x166 -- WMA 10 Pro
+ * - 0x167 -- WMA 10 Pro Lossless
+ */
+
+ u16 num_channels;
+/* Number of channels encoded in the input stream.
+ * Supported values: 1 to 8
+ */
+
+ u32 sample_rate;
+/* Number of samples per second (in Hertz).
+ * Supported values: 11025, 16000, 22050, 32000, 44100, 48000,
+ * 88200, 96000
+ */
+
+ u32 avg_bytes_per_sec;
+/* Bitrate expressed as the average bytes per second.
+ * Supported values: 2000 to 96000
+ */
+
+ u16 blk_align;
+/* Size of the bitstream packet size in bytes. WMA Pro files
+ * have a payload of one block per bitstream packet.
+ * Supported values: @le 13376
+ */
+
+ u16 bits_per_sample;
+/* Number of bits per sample in the encoded WMA stream.
+ * Supported values: 16, 24
+ */
+
+ u32 channel_mask;
+/* Bit-packed double word (32-bits) that indicates the
+ * recommended speaker positions for each source channel.
+ */
+
+ u16 enc_options;
+/* Bit-packed word with values that indicate whether certain
+ * features of the bitstream are used.
+ * Supported values: - 0x0001 -- ENCOPT3_PURE_LOSSLESS - 0x0006 --
+ * ENCOPT3_FRM_SIZE_MOD - 0x0038 -- ENCOPT3_SUBFRM_DIV - 0x0040 --
+ * ENCOPT3_WRITE_FRAMESIZE_IN_HDR - 0x0080 --
+ * ENCOPT3_GENERATE_DRC_PARAMS - 0x0100 -- ENCOPT3_RTMBITS
+ */
+
+
+ u16 usAdvancedEncodeOpt;
+ /* Advanced encoding option. */
+
+ u32 advanced_enc_options2;
+ /* Advanced encoding option 2. */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_WMA_V9_V2 0x00010DA8
+struct asm_wmastdv9_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+ u16 fmtag;
+/* WMA format tag.
+ * Supported values: 0x161 (WMA 9 standard)
+ */
+
+ u16 num_channels;
+/* Number of channels in the stream.
+ * Supported values: 1, 2
+ */
+
+ u32 sample_rate;
+/* Number of samples per second (in Hertz).
+ * Supported values: 48000
+ */
+
+ u32 avg_bytes_per_sec;
+ /* Bitrate expressed as the average bytes per second. */
+
+ u16 blk_align;
+/* Block align. All WMA files with a maximum packet size of
+ * 13376 are supported.
+ */
+
+
+ u16 bits_per_sample;
+/* Number of bits per sample in the output.
+ * Supported values: 16
+ */
+
+ u32 channel_mask;
+/* Channel mask.
+ * Supported values:
+ * - 3 -- Stereo (front left/front right)
+ * - 4 -- Mono (center)
+ */
+
+ u16 enc_options;
+ /* Options used during encoding. */
+
+ u16 reserved;
+
+} __packed;
+
+#define ASM_MEDIA_FMT_WMA_V8 0x00010D91
+
+struct asm_wmastdv8_enc_cfg {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+ u32 bit_rate;
+ /* Encoding rate in bits per second. */
+
+ u32 sample_rate;
+/* Number of samples per second.
+ *
+ * Supported values:
+ * - 0 -- Native mode
+ * - Other Supported values are 22050, 32000, 44100, and 48000.
+ *
+ * Native mode indicates that encoding must be performed with the
+ * sampling rate at the input.
+ * The sampling rate must not change during encoding.
+ */
+
+ u16 channel_cfg;
+/* Number of channels to encode.
+ * Supported values:
+ * - 0 -- Native mode
+ * - 1 -- Mono
+ * - 2 -- Stereo
+ * - Other values are not supported.
+ *
+ * Native mode indicates that encoding must be performed with the
+ * number of channels at the input.
+ * The number of channels must not change during encoding.
+ */
+
+ u16 reserved;
+ /* Reserved. Clients must set this field to zero.*/
+ } __packed;
+
+#define ASM_MEDIA_FMT_AMR_WB_PLUS_V2 0x00010DA9
+
+struct asm_amrwbplus_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+ u32 amr_frame_fmt;
+/* AMR frame format.
+ * Supported values:
+ * - 6 -- Transport Interface Format (TIF)
+ * - Any other value -- File storage format (FSF)
+ *
+ * TIF stream contains 2-byte header for each frame within the
+ * superframe. FSF stream contains one 2-byte header per superframe.
+ */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_AC3 0x00010DEE
+#define ASM_MEDIA_FMT_EAC3 0x00010DEF
+#define ASM_MEDIA_FMT_DTS 0x00010D88
+#define ASM_MEDIA_FMT_MP2 0x00010DE9
+#define ASM_MEDIA_FMT_FLAC 0x00010C16
+#define ASM_MEDIA_FMT_ALAC 0x00012F31
+#define ASM_MEDIA_FMT_VORBIS 0x00010C15
+#define ASM_MEDIA_FMT_APE 0x00012F32
+#define ASM_MEDIA_FMT_DSD 0x00012F3E
+
+
+/* Media format ID for adaptive transform acoustic coding. This
+ * ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED command
+ * only.
+ */
+
+#define ASM_MEDIA_FMT_ATRAC 0x00010D89
+
+/* Media format ID for metadata-enhanced audio transmission.
+ * This ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED
+ * command only.
+ */
+
+#define ASM_MEDIA_FMT_MAT 0x00010D8A
+
+/* adsp_media_fmt.h */
+
+#define ASM_DATA_CMD_WRITE_V2 0x00010DAB
+
+struct asm_data_cmd_write_v2 {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+/* The 64 bit address msw-lsw should be a valid, mapped address.
+ * 64 bit address should be a multiple of 32 bytes
+ */
+
+ u32 buf_addr_msw;
+/* The 64 bit address msw-lsw should be a valid, mapped address.
+ * 64 bit address should be a multiple of 32 bytes.
+ * -Address of the buffer containing the data to be decoded.
+ * The buffer should be aligned to a 32 byte boundary.
+ * -In the case of 32 bit Shared memory address, msw field must
+ * -be set to zero.
+ * -In the case of 36 bit shared memory address, bit 31 to bit 4
+ * -of msw must be set to zero.
+ */
+ u32 mem_map_handle;
+/* memory map handle returned by DSP through
+ * ASM_CMD_SHARED_MEM_MAP_REGIONS command
+ */
+ u32 buf_size;
+/* Number of valid bytes available in the buffer for decoding. The
+ * first byte starts at buf_addr.
+ */
+
+ u32 seq_id;
+ /* Optional buffer sequence ID. */
+
+ u32 timestamp_lsw;
+/* Lower 32 bits of the 64-bit session time in microseconds of the
+ * first buffer sample.
+ */
+
+ u32 timestamp_msw;
+/* Upper 32 bits of the 64-bit session time in microseconds of the
+ * first buffer sample.
+ */
+
+ u32 flags;
+/* Bitfield of flags.
+ * Supported values for bit 31:
+ * - 1 -- Valid timestamp.
+ * - 0 -- Invalid timestamp.
+ * - Use #ASM_BIT_MASKIMESTAMP_VALID_FLAG as the bitmask and
+ * #ASM_SHIFTIMESTAMP_VALID_FLAG as the shift value to set this bit.
+ * Supported values for bit 30:
+ * - 1 -- Last buffer.
+ * - 0 -- Not the last buffer.
+ *
+ * Supported values for bit 29:
+ * - 1 -- Continue the timestamp from the previous buffer.
+ * - 0 -- Timestamp of the current buffer is not related
+ * to the timestamp of the previous buffer.
+ * - Use #ASM_BIT_MASKS_CONTINUE_FLAG and #ASM_SHIFTS_CONTINUE_FLAG
+ * to set this bit.
+ *
+ * Supported values for bit 4:
+ * - 1 -- End of the frame.
+ * - 0 -- Not the end of frame, or this information is not known.
+ * - Use #ASM_BIT_MASK_EOF_FLAG as the bitmask and #ASM_SHIFT_EOF_FLAG
+ * as the shift value to set this bit.
+ *
+ * All other bits are reserved and must be set to 0.
+ *
+ * If bit 31=0 and bit 29=1: The timestamp of the first sample in
+ * this buffer continues from the timestamp of the last sample in
+ * the previous buffer. If there is no previous buffer (i.e., this
+ * is the first buffer sent after opening the stream or after a
+ * flush operation), or if the previous buffer does not have a valid
+ * timestamp, the samples in the current buffer also do not have a
+ * valid timestamp. They are played out as soon as possible.
+ *
+ *
+ * If bit 31=0 and bit 29=0: No timestamp is associated with the
+ * first sample in this buffer. The samples are played out as soon
+ * as possible.
+ *
+ *
+ * If bit 31=1 and bit 29 is ignored: The timestamp specified in
+ * this payload is honored.
+ *
+ *
+ * If bit 30=0: Not the last buffer in the stream. This is useful
+ * in removing trailing samples.
+ *
+ *
+ * For bit 4: The client can set this flag for every buffer sent in
+ * which the last byte is the end of a frame. If this flag is set,
+ * the buffer can contain data from multiple frames, but it should
+ * always end at a frame boundary. Restrictions allow the aDSP to
+ * detect an end of frame without requiring additional processing.
+ */
+
+} __packed;
+
+#define ASM_DATA_CMD_READ_V2 0x00010DAC
+
+struct asm_data_cmd_read_v2 {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+/* the 64 bit address msw-lsw should be a valid mapped address
+ * and should be a multiple of 32 bytes
+ */
+
+
+ u32 buf_addr_msw;
+/* the 64 bit address msw-lsw should be a valid mapped address
+ * and should be a multiple of 32 bytes.
+ * - Address of the buffer where the DSP puts the encoded data,
+ * potentially, at an offset specified by the uOffset field in
+ * ASM_DATA_EVENT_READ_DONE structure. The buffer should be aligned
+ * to a 32 byte boundary.
+ * - In the case of 32 bit Shared memory address, msw field must
+ * - be set to zero.
+ * - In the case of 36 bit shared memory address, bit 31 to bit
+ * - 4 of msw must be set to zero.
+ */
+ u32 mem_map_handle;
+/* memory map handle returned by DSP through
+ * ASM_CMD_SHARED_MEM_MAP_REGIONS command.
+ */
+
+ u32 buf_size;
+/* Number of bytes available for the aDSP to write. The aDSP
+ * starts writing from buf_addr.
+ */
+
+ u32 seq_id;
+ /* Optional buffer sequence ID. */
+} __packed;
+
+#define ASM_DATA_CMD_EOS 0x00010BDB
+#define ASM_DATA_EVENT_RENDERED_EOS 0x00010C1C
+#define ASM_DATA_EVENT_EOS 0x00010BDD
+
+#define ASM_DATA_EVENT_WRITE_DONE_V2 0x00010D99
+struct asm_data_event_write_done_v2 {
+ u32 buf_addr_lsw;
+ /* lsw of the 64 bit address */
+ u32 buf_addr_msw;
+ /* msw of the 64 bit address. address given by the client in
+ * ASM_DATA_CMD_WRITE_V2 command.
+ */
+ u32 mem_map_handle;
+ /* memory map handle in the ASM_DATA_CMD_WRITE_V2 */
+
+ u32 status;
+/* Status message (error code) that indicates whether the
+ * referenced buffer has been successfully consumed.
+ * Supported values: Refer to @xhyperref{Q3,[Q3]}
+ */
+} __packed;
+
+#define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
+
+/* Definition of the frame metadata flag bitmask.*/
+#define ASM_BIT_MASK_FRAME_METADATA_FLAG (0x40000000UL)
+
+/* Definition of the frame metadata flag shift value. */
+#define ASM_SHIFT_FRAME_METADATA_FLAG 30
+
+struct asm_data_event_read_done_v2 {
+ u32 status;
+/* Status message (error code).
+ * Supported values: Refer to @xhyperref{Q3,[Q3]}
+ */
+
+u32 buf_addr_lsw;
+/* 64 bit address msw-lsw is a valid, mapped address. 64 bit
+ * address is a multiple of 32 bytes.
+ */
+
+u32 buf_addr_msw;
+/* 64 bit address msw-lsw is a valid, mapped address. 64 bit
+ * address is a multiple of 32 bytes.
+ *
+ * -Same address provided by the client in ASM_DATA_CMD_READ_V2
+ * -In the case of 32 bit Shared memory address, msw field is set to
+ * zero.
+ * -In the case of 36 bit shared memory address, bit 31 to bit 4
+ * -of msw is set to zero.
+ */
+
+u32 mem_map_handle;
+/* memory map handle in the ASM_DATA_CMD_READ_V2 */
+
+u32 enc_framesotal_size;
+/* Total size of the encoded frames in bytes.
+ * Supported values: >0
+ */
+
+u32 offset;
+/* Offset (from buf_addr) to the first byte of the first encoded
+ * frame. All encoded frames are consecutive, starting from this
+ * offset.
+ * Supported values: > 0
+ */
+
+u32 timestamp_lsw;
+/* Lower 32 bits of the 64-bit session time in microseconds of
+ * the first sample in the buffer. If Bit 5 of mode_flags flag of
+ * ASM_STREAM_CMD_OPEN_READ_V2 is 1 then the 64 bit timestamp is
+ * absolute capture time otherwise it is relative session time. The
+ * absolute timestamp doesn't reset unless the system is reset.
+ */
+
+
+u32 timestamp_msw;
+/* Upper 32 bits of the 64-bit session time in microseconds of
+ * the first sample in the buffer.
+ */
+
+
+u32 flags;
+/* Bitfield of flags. Bit 30 indicates whether frame metadata is
+ * present. If frame metadata is present, num_frames consecutive
+ * instances of @xhyperref{hdr:FrameMetaData,Frame metadata} start
+ * at the buffer address.
+ * Supported values for bit 31:
+ * - 1 -- Timestamp is valid.
+ * - 0 -- Timestamp is invalid.
+ * - Use #ASM_BIT_MASKIMESTAMP_VALID_FLAG and
+ * #ASM_SHIFTIMESTAMP_VALID_FLAG to set this bit.
+ *
+ * Supported values for bit 30:
+ * - 1 -- Frame metadata is present.
+ * - 0 -- Frame metadata is absent.
+ * - Use #ASM_BIT_MASK_FRAME_METADATA_FLAG and
+ * #ASM_SHIFT_FRAME_METADATA_FLAG to set this bit.
+ *
+ * All other bits are reserved; the aDSP sets them to 0.
+ */
+
+u32 num_frames;
+/* Number of encoded frames in the buffer. */
+
+u32 seq_id;
+/* Optional buffer sequence ID. */
+} __packed;
+
+struct asm_data_read_buf_metadata_v2 {
+ u32 offset;
+/* Offset from buf_addr in #ASM_DATA_EVENT_READ_DONE_PAYLOAD to
+ * the frame associated with this metadata.
+ * Supported values: > 0
+ */
+
+u32 frm_size;
+/* Size of the encoded frame in bytes.
+ * Supported values: > 0
+ */
+
+u32 num_encoded_pcm_samples;
+/* Number of encoded PCM samples (per channel) in the frame
+ * associated with this metadata.
+ * Supported values: > 0
+ */
+
+u32 timestamp_lsw;
+/* Lower 32 bits of the 64-bit session time in microseconds of the
+ * first sample for this frame.
+ * If Bit 5 of mode_flags flag of ASM_STREAM_CMD_OPEN_READ_V2 is 1
+ * then the 64 bit timestamp is absolute capture time otherwise it
+ * is relative session time. The absolute timestamp doesn't reset
+ * unless the system is reset.
+ */
+
+
+u32 timestamp_msw;
+/* Lower 32 bits of the 64-bit session time in microseconds of the
+ * first sample for this frame.
+ */
+
+u32 flags;
+/* Frame flags.
+ * Supported values for bit 31:
+ * - 1 -- Time stamp is valid
+ * - 0 -- Time stamp is not valid
+ * - All other bits are reserved; the aDSP sets them to 0.
+ */
+} __packed;
+
+/* Notifies the client of a change in the data sampling rate or
+ * Channel mode. This event is raised by the decoder service. The
+ * event is enabled through the mode flags of
+ * #ASM_STREAM_CMD_OPEN_WRITE_V2 or
+ * #ASM_STREAM_CMD_OPEN_READWRITE_V2. - The decoder detects a change
+ * in the output sampling frequency or the number/positioning of
+ * output channels, or if it is the first frame decoded.The new
+ * sampling frequency or the new channel configuration is
+ * communicated back to the client asynchronously.
+ */
+
+#define ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY 0x00010C65
+
+/* Payload of the #ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY event.
+ * This event is raised when the following conditions are both true:
+ * - The event is enabled through the mode_flags of
+ * #ASM_STREAM_CMD_OPEN_WRITE_V2 or
+ * #ASM_STREAM_CMD_OPEN_READWRITE_V2. - The decoder detects a change
+ * in either the output sampling frequency or the number/positioning
+ * of output channels, or if it is the first frame decoded.
+ * This event is not raised (even if enabled) if the decoder is
+ * MIDI, because
+ */
+
+
+struct asm_data_event_sr_cm_change_notify {
+ u32 sample_rate;
+/* New sampling rate (in Hertz) after detecting a change in the
+ * bitstream.
+ * Supported values: 2000 to 48000
+ */
+
+ u16 num_channels;
+/* New number of channels after detecting a change in the
+ * bitstream.
+ * Supported values: 1 to 8
+ */
+
+
+ u16 reserved;
+ /* Reserved for future use. This field must be set to 0.*/
+
+ u8 channel_mapping[8];
+
+} __packed;
+
+/* Notifies the client of a data sampling rate or channel mode
+ * change. This event is raised by the encoder service.
+ * This event is raised when :
+ * - Native mode encoding was requested in the encoder
+ * configuration (i.e., the channel number was 0), the sample rate
+ * was 0, or both were 0.
+ *
+ * - The input data frame at the encoder is the first one, or the
+ * sampling rate/channel mode is different from the previous input
+ * data frame.
+ *
+ */
+#define ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY 0x00010BDE
+
+struct asm_data_event_enc_sr_cm_change_notify {
+ u32 sample_rate;
+/* New sampling rate (in Hertz) after detecting a change in the
+ * input data.
+ * Supported values: 2000 to 48000
+ */
+
+
+ u16 num_channels;
+/* New number of channels after detecting a change in the input
+ * data. Supported values: 1 to 8
+ */
+
+
+ u16 bits_per_sample;
+/* New bits per sample after detecting a change in the input
+ * data.
+ * Supported values: 16, 24
+ */
+
+
+ u8 channel_mapping[8];
+
+} __packed;
+#define ASM_DATA_CMD_IEC_60958_FRAME_RATE 0x00010D87
+
+
+/* Payload of the #ASM_DATA_CMD_IEC_60958_FRAME_RATE command,
+ * which is used to indicate the IEC 60958 frame rate of a given
+ * packetized audio stream.
+ */
+
+struct asm_data_cmd_iec_60958_frame_rate {
+ u32 frame_rate;
+/* IEC 60958 frame rate of the incoming IEC 61937 packetized stream.
+ * Supported values: Any valid frame rate
+ */
+} __packed;
+
+/* adsp_asm_data_commands.h*/
+/* Definition of the stream ID bitmask.*/
+#define ASM_BIT_MASK_STREAM_ID (0x000000FFUL)
+
+/* Definition of the stream ID shift value.*/
+#define ASM_SHIFT_STREAM_ID 0
+
+/* Definition of the session ID bitmask.*/
+#define ASM_BIT_MASK_SESSION_ID (0x0000FF00UL)
+
+/* Definition of the session ID shift value.*/
+#define ASM_SHIFT_SESSION_ID 8
+
+/* Definition of the service ID bitmask.*/
+#define ASM_BIT_MASK_SERVICE_ID (0x00FF0000UL)
+
+/* Definition of the service ID shift value.*/
+#define ASM_SHIFT_SERVICE_ID 16
+
+/* Definition of the domain ID bitmask.*/
+#define ASM_BIT_MASK_DOMAIN_ID (0xFF000000UL)
+
+/* Definition of the domain ID shift value.*/
+#define ASM_SHIFT_DOMAIN_ID 24
+
+#define ASM_CMD_SHARED_MEM_MAP_REGIONS 0x00010D92
+#define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010D93
+#define ASM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010D94
+
+/* adsp_asm_service_commands.h */
+
+#define ASM_MAX_SESSION_ID (15)
+
+/* Maximum number of sessions.*/
+#define ASM_MAX_NUM_SESSIONS ASM_MAX_SESSION_ID
+
+/* Maximum number of streams per session.*/
+#define ASM_MAX_STREAMS_PER_SESSION (8)
+#define ASM_SESSION_CMD_RUN_V2 0x00010DAA
+#define ASM_SESSION_CMD_RUN_STARTIME_RUN_IMMEDIATE 0
+#define ASM_SESSION_CMD_RUN_STARTIME_RUN_AT_ABSOLUTEIME 1
+#define ASM_SESSION_CMD_RUN_STARTIME_RUN_AT_RELATIVEIME 2
+#define ASM_SESSION_CMD_RUN_STARTIME_RUN_WITH_DELAY 3
+
+#define ASM_BIT_MASK_RUN_STARTIME (0x00000003UL)
+
+/* Bit shift value used to specify the start time for the
+ * ASM_SESSION_CMD_RUN_V2 command.
+ */
+#define ASM_SHIFT_RUN_STARTIME 0
+struct asm_session_cmd_run_v2 {
+ struct apr_hdr hdr;
+ u32 flags;
+/* Specifies whether to run immediately or at a specific
+ * rendering time or with a specified delay. Run with delay is
+ * useful for delaying in case of ASM loopback opened through
+ * ASM_STREAM_CMD_OPEN_LOOPBACK_V2. Use #ASM_BIT_MASK_RUN_STARTIME
+ * and #ASM_SHIFT_RUN_STARTIME to set this 2-bit flag.
+ *
+ *
+ *Bits 0 and 1 can take one of four possible values:
+ *
+ *- #ASM_SESSION_CMD_RUN_STARTIME_RUN_IMMEDIATE
+ *- #ASM_SESSION_CMD_RUN_STARTIME_RUN_AT_ABSOLUTEIME
+ *- #ASM_SESSION_CMD_RUN_STARTIME_RUN_AT_RELATIVEIME
+ *- #ASM_SESSION_CMD_RUN_STARTIME_RUN_WITH_DELAY
+ *
+ *All other bits are reserved; clients must set them to zero.
+ */
+
+ u32 time_lsw;
+/* Lower 32 bits of the time in microseconds used to align the
+ * session origin time. When bits 0-1 of flags is
+ * ASM_SESSION_CMD_RUN_START_RUN_WITH_DELAY, time lsw is the lsw of
+ * the delay in us. For ASM_SESSION_CMD_RUN_START_RUN_WITH_DELAY,
+ * maximum value of the 64 bit delay is 150 ms.
+ */
+
+ u32 time_msw;
+/* Upper 32 bits of the time in microseconds used to align the
+ * session origin time. When bits 0-1 of flags is
+ * ASM_SESSION_CMD_RUN_START_RUN_WITH_DELAY, time msw is the msw of
+ * the delay in us. For ASM_SESSION_CMD_RUN_START_RUN_WITH_DELAY,
+ * maximum value of the 64 bit delay is 150 ms.
+ */
+
+} __packed;
+
+#define ASM_SESSION_CMD_PAUSE 0x00010BD3
+#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
+#define ASM_SESSION_CMD_GET_SESSIONTIME_V3 0x00010D9D
+#define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
+
+struct asm_session_cmd_rgstr_rx_underflow {
+ struct apr_hdr hdr;
+ u16 enable_flag;
+/* Specifies whether a client is to receive events when an Rx
+ * session underflows.
+ * Supported values:
+ * - 0 -- Do not send underflow events
+ * - 1 -- Send underflow events
+ */
+ u16 reserved;
+ /* Reserved. This field must be set to zero.*/
+} __packed;
+
+#define ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS 0x00010BD6
+
+struct asm_session_cmd_regx_overflow {
+ struct apr_hdr hdr;
+ u16 enable_flag;
+/* Specifies whether a client is to receive events when a Tx
+ * session overflows.
+ * Supported values:
+ * - 0 -- Do not send overflow events
+ * - 1 -- Send overflow events
+ */
+
+ u16 reserved;
+ /* Reserved. This field must be set to zero.*/
+} __packed;
+
+#define ASM_SESSION_EVENT_RX_UNDERFLOW 0x00010C17
+#define ASM_SESSION_EVENTX_OVERFLOW 0x00010C18
+#define ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3 0x00010D9E
+
+struct asm_session_cmdrsp_get_sessiontime_v3 {
+ u32 status;
+ /* Status message (error code).
+ * Supported values: Refer to @xhyperref{Q3,[Q3]}
+ */
+
+ u32 sessiontime_lsw;
+ /* Lower 32 bits of the current session time in microseconds.*/
+
+ u32 sessiontime_msw;
+ /* Upper 32 bits of the current session time in microseconds.*/
+
+ u32 absolutetime_lsw;
+/* Lower 32 bits in micro seconds of the absolute time at which
+ * the * sample corresponding to the above session time gets
+ * rendered * to hardware. This absolute time may be slightly in the
+ * future or past.
+ */
+
+
+ u32 absolutetime_msw;
+/* Upper 32 bits in micro seconds of the absolute time at which
+ * the * sample corresponding to the above session time gets
+ * rendered to * hardware. This absolute time may be slightly in the
+ * future or past.
+ */
+
+} __packed;
+
+#define ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2 0x00010D9F
+
+struct asm_session_cmd_adjust_session_clock_v2 {
+ struct apr_hdr hdr;
+u32 adjustime_lsw;
+/* Lower 32 bits of the signed 64-bit quantity that specifies the
+ * adjustment time in microseconds to the session clock.
+ *
+ * Positive values indicate advancement of the session clock.
+ * Negative values indicate delay of the session clock.
+ */
+
+
+ u32 adjustime_msw;
+/* Upper 32 bits of the signed 64-bit quantity that specifies
+ * the adjustment time in microseconds to the session clock.
+ * Positive values indicate advancement of the session clock.
+ * Negative values indicate delay of the session clock.
+ */
+
+} __packed;
+
+#define ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 0x00010DA0
+
+struct asm_session_cmdrsp_adjust_session_clock_v2 {
+ u32 status;
+/* Status message (error code).
+ * Supported values: Refer to @xhyperref{Q3,[Q3]}
+ * An error means the session clock is not adjusted. In this case,
+ * the next two fields are irrelevant.
+ */
+
+
+ u32 actual_adjustime_lsw;
+/* Lower 32 bits of the signed 64-bit quantity that specifies
+ * the actual adjustment in microseconds performed by the aDSP.
+ * A positive value indicates advancement of the session clock. A
+ * negative value indicates delay of the session clock.
+ */
+
+
+ u32 actual_adjustime_msw;
+/* Upper 32 bits of the signed 64-bit quantity that specifies
+ * the actual adjustment in microseconds performed by the aDSP.
+ * A positive value indicates advancement of the session clock. A
+ * negative value indicates delay of the session clock.
+ */
+
+
+ u32 cmd_latency_lsw;
+/* Lower 32 bits of the unsigned 64-bit quantity that specifies
+ * the amount of time in microseconds taken to perform the session
+ * clock adjustment.
+ */
+
+
+ u32 cmd_latency_msw;
+/* Upper 32 bits of the unsigned 64-bit quantity that specifies
+ * the amount of time in microseconds taken to perform the session
+ * clock adjustment.
+ */
+
+} __packed;
+
+#define ASM_SESSION_CMD_GET_PATH_DELAY_V2 0x00010DAF
+#define ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 0x00010DB0
+
+struct asm_session_cmdrsp_get_path_delay_v2 {
+ u32 status;
+/* Status message (error code). Whether this get delay operation
+ * is successful or not. Delay value is valid only if status is
+ * success.
+ * Supported values: Refer to @xhyperref{Q5,[Q5]}
+ */
+
+ u32 audio_delay_lsw;
+ /* Upper 32 bits of the aDSP delay in microseconds. */
+
+ u32 audio_delay_msw;
+ /* Lower 32 bits of the aDSP delay in microseconds. */
+
+} __packed;
+
+/* adsp_asm_session_command.h*/
+#define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3
+
+#define ASM_LOW_LATENCY_STREAM_SESSION 0x10000000
+
+#define ASM_ULTRA_LOW_LATENCY_STREAM_SESSION 0x20000000
+
+#define ASM_ULL_POST_PROCESSING_STREAM_SESSION 0x40000000
+
+#define ASM_LEGACY_STREAM_SESSION 0
+
+
+struct asm_stream_cmd_open_write_v3 {
+ struct apr_hdr hdr;
+ uint32_t mode_flags;
+/* Mode flags that configure the stream to notify the client
+ * whenever it detects an SR/CM change at the input to its POPP.
+ * Supported values for bits 0 to 1:
+ * - Reserved; clients must set them to zero.
+ * Supported values for bit 2:
+ * - 0 -- SR/CM change notification event is disabled.
+ * - 1 -- SR/CM change notification event is enabled.
+ * - Use #ASM_BIT_MASK_SR_CM_CHANGE_NOTIFY_FLAG and
+ * #ASM_SHIFT_SR_CM_CHANGE_NOTIFY_FLAG to set or get this bit.
+ *
+ * Supported values for bit 31:
+ * - 0 -- Stream to be opened in on-Gapless mode.
+ * - 1 -- Stream to be opened in Gapless mode. In Gapless mode,
+ * successive streams must be opened with same session ID but
+ * different stream IDs.
+ *
+ * - Use #ASM_BIT_MASK_GAPLESS_MODE_FLAG and
+ * #ASM_SHIFT_GAPLESS_MODE_FLAG to set or get this bit.
+ *
+ *
+ * @note1hang MIDI and DTMF streams cannot be opened in Gapless mode.
+ */
+
+ uint16_t sink_endpointype;
+/*< Sink point type.
+ * Supported values:
+ * - 0 -- Device matrix
+ * - Other values are reserved.
+ *
+ * The device matrix is the gateway to the hardware ports.
+ */
+
+ uint16_t bits_per_sample;
+/*< Number of bits per sample processed by ASM modules.
+ * Supported values: 16 and 24 bits per sample
+ */
+
+ uint32_t postprocopo_id;
+/*< Specifies the topology (order of processing) of
+ * postprocessing algorithms. <i>None</i> means no postprocessing.
+ * Supported values:
+ * - #ASM_STREAM_POSTPROCOPO_ID_DEFAULT
+ * - #ASM_STREAM_POSTPROCOPO_ID_MCH_PEAK_VOL
+ * - #ASM_STREAM_POSTPROCOPO_ID_NONE
+ *
+ * This field can also be enabled through SetParams flags.
+ */
+
+ uint32_t dec_fmt_id;
+/*< Configuration ID of the decoder media format.
+ *
+ * Supported values:
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_ADPCM
+ * - #ASM_MEDIA_FMT_MP3
+ * - #ASM_MEDIA_FMT_AAC_V2
+ * - #ASM_MEDIA_FMT_DOLBY_AAC
+ * - #ASM_MEDIA_FMT_AMRNB_FS
+ * - #ASM_MEDIA_FMT_AMRWB_FS
+ * - #ASM_MEDIA_FMT_AMR_WB_PLUS_V2
+ * - #ASM_MEDIA_FMT_V13K_FS
+ * - #ASM_MEDIA_FMT_EVRC_FS
+ * - #ASM_MEDIA_FMT_EVRCB_FS
+ * - #ASM_MEDIA_FMT_EVRCWB_FS
+ * - #ASM_MEDIA_FMT_SBC
+ * - #ASM_MEDIA_FMT_WMA_V10PRO_V2
+ * - #ASM_MEDIA_FMT_WMA_V9_V2
+ * - #ASM_MEDIA_FMT_AC3
+ * - #ASM_MEDIA_FMT_EAC3
+ * - #ASM_MEDIA_FMT_G711_ALAW_FS
+ * - #ASM_MEDIA_FMT_G711_MLAW_FS
+ * - #ASM_MEDIA_FMT_G729A_FS
+ * - #ASM_MEDIA_FMT_FR_FS
+ * - #ASM_MEDIA_FMT_VORBIS
+ * - #ASM_MEDIA_FMT_FLAC
+ * - #ASM_MEDIA_FMT_ALAC
+ * - #ASM_MEDIA_FMT_APE
+ * - #ASM_MEDIA_FMT_EXAMPLE
+ */
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE 0x00010DD9
+
+/* Bitmask for the stream_perf_mode subfield. */
+#define ASM_BIT_MASK_STREAM_PERF_FLAG_PULL_MODE_WRITE 0xE0000000UL
+
+/* Bitmask for the stream_perf_mode subfield. */
+#define ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE 29
+
+#define ASM_STREAM_CMD_OPEN_PUSH_MODE_READ 0x00010DDA
+
+#define ASM_BIT_MASK_STREAM_PERF_FLAG_PUSH_MODE_READ 0xE0000000UL
+
+#define ASM_SHIFT_STREAM_PERF_FLAG_PUSH_MODE_READ 29
+
+#define ASM_DATA_EVENT_WATERMARK 0x00010DDB
+
+struct asm_shared_position_buffer {
+ volatile uint32_t frame_counter;
+/* Counter used to handle interprocessor synchronization issues.
+ * When frame_counter is 0: read_index, wall_clock_us_lsw, and
+ * wall_clock_us_msw are invalid.
+ * Supported values: >= 0.
+ */
+
+ volatile uint32_t index;
+/* Index in bytes from where the aDSP is reading/writing.
+ * Supported values: 0 to circular buffer size - 1
+ */
+
+ volatile uint32_t wall_clock_us_lsw;
+/* Lower 32 bits of the 64-bit wall clock time in microseconds when the
+ * read index was updated.
+ * Supported values: >= 0
+ */
+
+ volatile uint32_t wall_clock_us_msw;
+/* Upper 32 bits of the 64 bit wall clock time in microseconds when the
+ * read index was updated
+ * Supported values: >= 0
+ */
+} __packed;
+
+struct asm_shared_watermark_level {
+ uint32_t watermark_level_bytes;
+} __packed;
+
+struct asm_stream_cmd_open_shared_io {
+ struct apr_hdr hdr;
+ uint32_t mode_flags;
+ uint16_t endpoint_type;
+ uint16_t topo_bits_per_sample;
+ uint32_t topo_id;
+ uint32_t fmt_id;
+ uint32_t shared_pos_buf_phy_addr_lsw;
+ uint32_t shared_pos_buf_phy_addr_msw;
+ uint16_t shared_pos_buf_mem_pool_id;
+ uint16_t shared_pos_buf_num_regions;
+ uint32_t shared_pos_buf_property_flag;
+ uint32_t shared_circ_buf_start_phy_addr_lsw;
+ uint32_t shared_circ_buf_start_phy_addr_msw;
+ uint32_t shared_circ_buf_size;
+ uint16_t shared_circ_buf_mem_pool_id;
+ uint16_t shared_circ_buf_num_regions;
+ uint32_t shared_circ_buf_property_flag;
+ uint32_t num_watermark_levels;
+ struct asm_multi_channel_pcm_fmt_blk_v3 fmt;
+ struct avs_shared_map_region_payload map_region_pos_buf;
+ struct avs_shared_map_region_payload map_region_circ_buf;
+ struct asm_shared_watermark_level watermark[0];
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4
+
+/* Definition of the timestamp type flag bitmask */
+#define ASM_BIT_MASKIMESTAMPYPE_FLAG (0x00000020UL)
+
+/* Definition of the timestamp type flag shift value. */
+#define ASM_SHIFTIMESTAMPYPE_FLAG 5
+
+/* Relative timestamp is identified by this value.*/
+#define ASM_RELATIVEIMESTAMP 0
+
+/* Absolute timestamp is identified by this value.*/
+#define ASM_ABSOLUTEIMESTAMP 1
+
+/* Bit value for Low Latency Tx stream subfield */
+#define ASM_LOW_LATENCY_TX_STREAM_SESSION 1
+
+/* Bit shift for the stream_perf_mode subfield. */
+#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29
+
+struct asm_stream_cmd_open_read_v3 {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode flags that indicate whether meta information per encoded
+ * frame is to be provided.
+ * Supported values for bit 4:
+ *
+ * - 0 -- Return data buffer contains all encoded frames only; it
+ * does not contain frame metadata.
+ *
+ * - 1 -- Return data buffer contains an array of metadata and
+ * encoded frames.
+ *
+ * - Use #ASM_BIT_MASK_META_INFO_FLAG as the bitmask and
+ * #ASM_SHIFT_META_INFO_FLAG as the shift value for this bit.
+ *
+ *
+ * Supported values for bit 5:
+ *
+ * - ASM_RELATIVEIMESTAMP -- ASM_DATA_EVENT_READ_DONE_V2 will have
+ * - relative time-stamp.
+ * - ASM_ABSOLUTEIMESTAMP -- ASM_DATA_EVENT_READ_DONE_V2 will
+ * - have absolute time-stamp.
+ *
+ * - Use #ASM_BIT_MASKIMESTAMPYPE_FLAG as the bitmask and
+ * #ASM_SHIFTIMESTAMPYPE_FLAG as the shift value for this bit.
+ *
+ * All other bits are reserved; clients must set them to zero.
+ */
+
+ u32 src_endpointype;
+/* Specifies the endpoint providing the input samples.
+ * Supported values:
+ * - 0 -- Device matrix
+ * - All other values are reserved; clients must set them to zero.
+ * Otherwise, an error is returned.
+ * The device matrix is the gateway from the tunneled Tx ports.
+ */
+
+ u32 preprocopo_id;
+/* Specifies the topology (order of processing) of preprocessing
+ * algorithms. <i>None</i> means no preprocessing.
+ * Supported values:
+ * - #ASM_STREAM_PREPROCOPO_ID_DEFAULT
+ * - #ASM_STREAM_PREPROCOPO_ID_NONE
+ *
+ * This field can also be enabled through SetParams flags.
+ */
+
+ u32 enc_cfg_id;
+/* Media configuration ID for encoded output.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_AAC_V2
+ * - #ASM_MEDIA_FMT_AMRNB_FS
+ * - #ASM_MEDIA_FMT_AMRWB_FS
+ * - #ASM_MEDIA_FMT_V13K_FS
+ * - #ASM_MEDIA_FMT_EVRC_FS
+ * - #ASM_MEDIA_FMT_EVRCB_FS
+ * - #ASM_MEDIA_FMT_EVRCWB_FS
+ * - #ASM_MEDIA_FMT_SBC
+ * - #ASM_MEDIA_FMT_G711_ALAW_FS
+ * - #ASM_MEDIA_FMT_G711_MLAW_FS
+ * - #ASM_MEDIA_FMT_G729A_FS
+ * - #ASM_MEDIA_FMT_EXAMPLE
+ * - #ASM_MEDIA_FMT_WMA_V8
+ */
+
+ u16 bits_per_sample;
+/* Number of bits per sample processed by ASM modules.
+ * Supported values: 16 and 24 bits per sample
+ */
+
+ u16 reserved;
+/* Reserved for future use. This field must be set to zero.*/
+} __packed;
+
+#define ASM_POPP_OUTPUT_SR_NATIVE_RATE 0
+
+/* Enumeration for the maximum sampling rate at the POPP output.*/
+#define ASM_POPP_OUTPUT_SR_MAX_RATE 48000
+
+#define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D
+#define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D
+
+struct asm_stream_cmd_open_readwrite_v2 {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode flags.
+ * Supported values for bit 2:
+ * - 0 -- SR/CM change notification event is disabled.
+ * - 1 -- SR/CM change notification event is enabled. Use
+ * #ASM_BIT_MASK_SR_CM_CHANGE_NOTIFY_FLAG and
+ * #ASM_SHIFT_SR_CM_CHANGE_NOTIFY_FLAG to set or
+ * getting this flag.
+ *
+ * Supported values for bit 4:
+ * - 0 -- Return read data buffer contains all encoded frames only; it
+ * does not contain frame metadata.
+ * - 1 -- Return read data buffer contains an array of metadata and
+ * encoded frames.
+ *
+ * All other bits are reserved; clients must set them to zero.
+ */
+
+ u32 postprocopo_id;
+/* Specifies the topology (order of processing) of postprocessing
+ * algorithms. <i>None</i> means no postprocessing.
+ *
+ * Supported values:
+ * - #ASM_STREAM_POSTPROCOPO_ID_DEFAULT
+ * - #ASM_STREAM_POSTPROCOPO_ID_MCH_PEAK_VOL
+ * - #ASM_STREAM_POSTPROCOPO_ID_NONE
+ */
+
+ u32 dec_fmt_id;
+/* Specifies the media type of the input data. PCM indicates that
+ * no decoding must be performed, e.g., this is an NT encoder
+ * session.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_ADPCM
+ * - #ASM_MEDIA_FMT_MP3
+ * - #ASM_MEDIA_FMT_AAC_V2
+ * - #ASM_MEDIA_FMT_DOLBY_AAC
+ * - #ASM_MEDIA_FMT_AMRNB_FS
+ * - #ASM_MEDIA_FMT_AMRWB_FS
+ * - #ASM_MEDIA_FMT_V13K_FS
+ * - #ASM_MEDIA_FMT_EVRC_FS
+ * - #ASM_MEDIA_FMT_EVRCB_FS
+ * - #ASM_MEDIA_FMT_EVRCWB_FS
+ * - #ASM_MEDIA_FMT_SBC
+ * - #ASM_MEDIA_FMT_WMA_V10PRO_V2
+ * - #ASM_MEDIA_FMT_WMA_V9_V2
+ * - #ASM_MEDIA_FMT_AMR_WB_PLUS_V2
+ * - #ASM_MEDIA_FMT_AC3
+ * - #ASM_MEDIA_FMT_G711_ALAW_FS
+ * - #ASM_MEDIA_FMT_G711_MLAW_FS
+ * - #ASM_MEDIA_FMT_G729A_FS
+ * - #ASM_MEDIA_FMT_EXAMPLE
+ */
+
+ u32 enc_cfg_id;
+/* Specifies the media type for the output of the stream. PCM
+ * indicates that no encoding must be performed, e.g., this is an NT
+ * decoder session.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_AAC_V2
+ * - #ASM_MEDIA_FMT_AMRNB_FS
+ * - #ASM_MEDIA_FMT_AMRWB_FS
+ * - #ASM_MEDIA_FMT_V13K_FS
+ * - #ASM_MEDIA_FMT_EVRC_FS
+ * - #ASM_MEDIA_FMT_EVRCB_FS
+ * - #ASM_MEDIA_FMT_EVRCWB_FS
+ * - #ASM_MEDIA_FMT_SBC
+ * - #ASM_MEDIA_FMT_G711_ALAW_FS
+ * - #ASM_MEDIA_FMT_G711_MLAW_FS
+ * - #ASM_MEDIA_FMT_G729A_FS
+ * - #ASM_MEDIA_FMT_EXAMPLE
+ * - #ASM_MEDIA_FMT_WMA_V8
+ */
+
+ u16 bits_per_sample;
+/* Number of bits per sample processed by ASM modules.
+ * Supported values: 16 and 24 bits per sample
+ */
+
+ u16 reserved;
+/* Reserved for future use. This field must be set to zero.*/
+
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_LOOPBACK_V2 0x00010D8E
+struct asm_stream_cmd_open_loopback_v2 {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+ u16 src_endpointype;
+ /* Endpoint type. 0 = Tx Matrix */
+ u16 sink_endpointype;
+ /* Endpoint type. 0 = Rx Matrix */
+ u32 postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+
+ u16 bits_per_sample;
+/* The number of bits per sample processed by ASM modules
+ * Supported values: 16 and 24 bits per sample
+ */
+ u16 reserved;
+/* Reserved for future use. This field must be set to zero. */
+} __packed;
+
+#define ASM_STREAM_CMD_CLOSE 0x00010BCD
+#define ASM_STREAM_CMD_FLUSH 0x00010BCE
+
+
+#define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09
+#define ASM_STREAM_CMD_SET_PP_PARAMS_V2 0x00010DA1
+
+struct asm_stream_cmd_set_pp_params_v2 {
+ u32 data_payload_addr_lsw;
+/* LSW of parameter data payload address. Supported values: any. */
+ u32 data_payload_addr_msw;
+/* MSW of Parameter data payload address. Supported values: any.
+ * - Must be set to zero for in-band data.
+ * - In the case of 32 bit Shared memory address, msw field must be
+ * - set to zero.
+ * - In the case of 36 bit shared memory address, bit 31 to bit 4 of
+ * msw
+ *
+ * - must be set to zero.
+ */
+ u32 mem_map_handle;
+/* Supported Values: Any.
+ * memory map handle returned by DSP through
+ * ASM_CMD_SHARED_MEM_MAP_REGIONS
+ * command.
+ * if mmhandle is NULL, the ParamData payloads are within the
+ * message payload (in-band).
+ * If mmhandle is non-NULL, the ParamData payloads begin at the
+ * address specified in the address msw and lsw (out-of-band).
+ */
+
+ u32 data_payload_size;
+/* Size in bytes of the variable payload accompanying the
+ * message, or in shared memory. This field is used for parsing the
+ * parameter payload.
+ */
+} __packed;
+
+
+struct asm_stream_param_data_v2 {
+ u32 module_id;
+ /* Unique module ID. */
+
+ u32 param_id;
+ /* Unique parameter ID. */
+
+ u16 param_size;
+/* Data size of the param_id/module_id combination. This is
+ * a multiple of 4 bytes.
+ */
+
+ u16 reserved;
+/* Reserved for future enhancements. This field must be set to
+ * zero.
+ */
+
+} __packed;
+
+#define ASM_STREAM_CMD_GET_PP_PARAMS_V2 0x00010DA2
+
+struct asm_stream_cmd_get_pp_params_v2 {
+ u32 data_payload_addr_lsw;
+ /* LSW of the parameter data payload address. */
+ u32 data_payload_addr_msw;
+/* MSW of the parameter data payload address.
+ * - Size of the shared memory, if specified, shall be large enough
+ * to contain the whole ParamData payload, including Module ID,
+ * Param ID, Param Size, and Param Values
+ * - Must be set to zero for in-band data
+ * - In the case of 32 bit Shared memory address, msw field must be
+ * set to zero.
+ * - In the case of 36 bit shared memory address, bit 31 to bit 4 of
+ * msw must be set to zero.
+ */
+
+ u32 mem_map_handle;
+/* Supported Values: Any.
+ * memory map handle returned by DSP through ASM_CMD_SHARED_MEM_MAP_REGIONS
+ * command.
+ * if mmhandle is NULL, the ParamData payloads in the ACK are within the
+ * message payload (in-band).
+ * If mmhandle is non-NULL, the ParamData payloads in the ACK begin at the
+ * address specified in the address msw and lsw.
+ * (out-of-band).
+ */
+
+ u32 module_id;
+/* Unique module ID. */
+
+ u32 param_id;
+/* Unique parameter ID. */
+
+ u16 param_max_size;
+/* Maximum data size of the module_id/param_id combination. This
+ * is a multiple of 4 bytes.
+ */
+
+
+ u16 reserved;
+/* Reserved for backward compatibility. Clients must set this
+ * field to zero.
+ */
+} __packed;
+
+#define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10
+
+#define ASM_PARAM_ID_ENCDEC_BITRATE 0x00010C13
+
+struct asm_bitrate_param {
+ u32 bitrate;
+/* Maximum supported bitrate. Only the AAC encoder is supported.*/
+
+} __packed;
+
+#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3
+#define ASM_PARAM_ID_AAC_SBR_PS_FLAG 0x00010C63
+
+/* Flag to turn off both SBR and PS processing, if they are
+ * present in the bitstream.
+ */
+
+#define ASM_AAC_SBR_OFF_PS_OFF (2)
+
+/* Flag to turn on SBR but turn off PS processing,if they are
+ * present in the bitstream.
+ */
+
+#define ASM_AAC_SBR_ON_PS_OFF (1)
+
+/* Flag to turn on both SBR and PS processing, if they are
+ * present in the bitstream (default behavior).
+ */
+
+
+#define ASM_AAC_SBR_ON_PS_ON (0)
+
+/* Structure for an AAC SBR PS processing flag. */
+
+/* Payload of the #ASM_PARAM_ID_AAC_SBR_PS_FLAG parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+struct asm_aac_sbr_ps_flag_param {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+
+ u32 sbr_ps_flag;
+/* Control parameter to enable or disable SBR/PS processing in
+ * the AAC bitstream. Use the following macros to set this field:
+ * - #ASM_AAC_SBR_OFF_PS_OFF -- Turn off both SBR and PS
+ * processing, if they are present in the bitstream.
+ * - #ASM_AAC_SBR_ON_PS_OFF -- Turn on SBR processing, but not PS
+ * processing, if they are present in the bitstream.
+ * - #ASM_AAC_SBR_ON_PS_ON -- Turn on both SBR and PS processing,
+ * if they are present in the bitstream (default behavior).
+ * - All other values are invalid.
+ * Changes are applied to the next decoded frame.
+ */
+} __packed;
+
+#define ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING 0x00010C64
+
+/* First single channel element in a dual mono bitstream.*/
+#define ASM_AAC_DUAL_MONO_MAP_SCE_1 (1)
+
+/* Second single channel element in a dual mono bitstream.*/
+#define ASM_AAC_DUAL_MONO_MAP_SCE_2 (2)
+
+/* Structure for AAC decoder dual mono channel mapping. */
+
+
+struct asm_aac_dual_mono_mapping_param {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ u16 left_channel_sce;
+ u16 right_channel_sce;
+
+} __packed;
+
+#define ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 0x00010DA4
+
+struct asm_stream_cmdrsp_get_pp_params_v2 {
+ u32 status;
+} __packed;
+
+#define ASM_PARAM_ID_AC3_KARAOKE_MODE 0x00010D73
+
+/* Enumeration for both vocals in a karaoke stream.*/
+#define AC3_KARAOKE_MODE_NO_VOCAL (0)
+
+/* Enumeration for only the left vocal in a karaoke stream.*/
+#define AC3_KARAOKE_MODE_LEFT_VOCAL (1)
+
+/* Enumeration for only the right vocal in a karaoke stream.*/
+#define AC3_KARAOKE_MODE_RIGHT_VOCAL (2)
+
+/* Enumeration for both vocal channels in a karaoke stream.*/
+#define AC3_KARAOKE_MODE_BOTH_VOCAL (3)
+#define ASM_PARAM_ID_AC3_DRC_MODE 0x00010D74
+/* Enumeration for the Custom Analog mode.*/
+#define AC3_DRC_MODE_CUSTOM_ANALOG (0)
+
+/* Enumeration for the Custom Digital mode.*/
+#define AC3_DRC_MODE_CUSTOM_DIGITAL (1)
+/* Enumeration for the Line Out mode (light compression).*/
+#define AC3_DRC_MODE_LINE_OUT (2)
+
+/* Enumeration for the RF remodulation mode (heavy compression).*/
+#define AC3_DRC_MODE_RF_REMOD (3)
+#define ASM_PARAM_ID_AC3_DUAL_MONO_MODE 0x00010D75
+
+/* Enumeration for playing dual mono in stereo mode.*/
+#define AC3_DUAL_MONO_MODE_STEREO (0)
+
+/* Enumeration for playing left mono.*/
+#define AC3_DUAL_MONO_MODE_LEFT_MONO (1)
+
+/* Enumeration for playing right mono.*/
+#define AC3_DUAL_MONO_MODE_RIGHT_MONO (2)
+
+/* Enumeration for mixing both dual mono channels and playing them.*/
+#define AC3_DUAL_MONO_MODE_MIXED_MONO (3)
+#define ASM_PARAM_ID_AC3_STEREO_DOWNMIX_MODE 0x00010D76
+
+/* Enumeration for using the Downmix mode indicated in the bitstream. */
+
+#define AC3_STEREO_DOWNMIX_MODE_AUTO_DETECT (0)
+
+/* Enumeration for Surround Compatible mode (preserves the
+ * surround information).
+ */
+
+#define AC3_STEREO_DOWNMIX_MODE_LT_RT (1)
+/* Enumeration for Mono Compatible mode (if the output is to be
+ * further downmixed to mono).
+ */
+
+#define AC3_STEREO_DOWNMIX_MODE_LO_RO (2)
+
+/* ID of the AC3 PCM scale factor parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+#define ASM_PARAM_ID_AC3_PCM_SCALEFACTOR 0x00010D78
+
+/* ID of the AC3 DRC boost scale factor parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+#define ASM_PARAM_ID_AC3_DRC_BOOST_SCALEFACTOR 0x00010D79
+
+/* ID of the AC3 DRC cut scale factor parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+#define ASM_PARAM_ID_AC3_DRC_CUT_SCALEFACTOR 0x00010D7A
+
+/* Structure for AC3 Generic Parameter. */
+
+/* Payload of the AC3 parameters in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+struct asm_ac3_generic_param {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+ u32 generic_parameter;
+/* AC3 generic parameter. Select from one of the following
+ * possible values.
+ *
+ * For #ASM_PARAM_ID_AC3_KARAOKE_MODE, supported values are:
+ * - AC3_KARAOKE_MODE_NO_VOCAL
+ * - AC3_KARAOKE_MODE_LEFT_VOCAL
+ * - AC3_KARAOKE_MODE_RIGHT_VOCAL
+ * - AC3_KARAOKE_MODE_BOTH_VOCAL
+ *
+ * For #ASM_PARAM_ID_AC3_DRC_MODE, supported values are:
+ * - AC3_DRC_MODE_CUSTOM_ANALOG
+ * - AC3_DRC_MODE_CUSTOM_DIGITAL
+ * - AC3_DRC_MODE_LINE_OUT
+ * - AC3_DRC_MODE_RF_REMOD
+ *
+ * For #ASM_PARAM_ID_AC3_DUAL_MONO_MODE, supported values are:
+ * - AC3_DUAL_MONO_MODE_STEREO
+ * - AC3_DUAL_MONO_MODE_LEFT_MONO
+ * - AC3_DUAL_MONO_MODE_RIGHT_MONO
+ * - AC3_DUAL_MONO_MODE_MIXED_MONO
+ *
+ * For #ASM_PARAM_ID_AC3_STEREO_DOWNMIX_MODE, supported values are:
+ * - AC3_STEREO_DOWNMIX_MODE_AUTO_DETECT
+ * - AC3_STEREO_DOWNMIX_MODE_LT_RT
+ * - AC3_STEREO_DOWNMIX_MODE_LO_RO
+ *
+ * For #ASM_PARAM_ID_AC3_PCM_SCALEFACTOR, supported values are
+ * 0 to 1 in Q31 format.
+ *
+ * For #ASM_PARAM_ID_AC3_DRC_BOOST_SCALEFACTOR, supported values are
+ * 0 to 1 in Q31 format.
+ *
+ * For #ASM_PARAM_ID_AC3_DRC_CUT_SCALEFACTOR, supported values are
+ * 0 to 1 in Q31 format.
+ */
+} __packed;
+
+/* Enumeration for Raw mode (no downmixing), which specifies
+ * that all channels in the bitstream are to be played out as is
+ * without any downmixing. (Default)
+ */
+
+#define WMAPRO_CHANNEL_MASK_RAW (-1)
+
+/* Enumeration for setting the channel mask to 0. The 7.1 mode
+ * (Home Theater) is assigned.
+ */
+
+
+#define WMAPRO_CHANNEL_MASK_ZERO 0x0000
+
+/* Speaker layout mask for one channel (Home Theater, mono).
+ * - Speaker front center
+ */
+#define WMAPRO_CHANNEL_MASK_1_C 0x0004
+
+/* Speaker layout mask for two channels (Home Theater, stereo).
+ * - Speaker front left
+ * - Speaker front right
+ */
+#define WMAPRO_CHANNEL_MASK_2_L_R 0x0003
+
+/* Speaker layout mask for three channels (Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ */
+#define WMAPRO_CHANNEL_MASK_3_L_C_R 0x0007
+
+/* Speaker layout mask for two channels (stereo).
+ * - Speaker back left
+ * - Speaker back right
+ */
+#define WMAPRO_CHANNEL_MASK_2_Bl_Br 0x0030
+
+/* Speaker layout mask for four channels.
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker back left
+ * - Speaker back right
+ */
+#define WMAPRO_CHANNEL_MASK_4_L_R_Bl_Br 0x0033
+
+/* Speaker layout mask for four channels (Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back center
+ */
+#define WMAPRO_CHANNEL_MASK_4_L_R_C_Bc_HT 0x0107
+/* Speaker layout mask for five channels.
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back left
+ * - Speaker back right
+ */
+#define WMAPRO_CHANNEL_MASK_5_L_C_R_Bl_Br 0x0037
+
+/* Speaker layout mask for five channels (5 mode, Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker side left
+ * - Speaker side right
+ */
+#define WMAPRO_CHANNEL_MASK_5_L_C_R_Sl_Sr_HT 0x0607
+/* Speaker layout mask for six channels (5.1 mode).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker low frequency
+ * - Speaker back left
+ * - Speaker back right
+ */
+#define WMAPRO_CHANNEL_MASK_5DOT1_L_C_R_Bl_Br_SLF 0x003F
+/* Speaker layout mask for six channels (5.1 mode, Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker low frequency
+ * - Speaker side left
+ * - Speaker side right
+ */
+#define WMAPRO_CHANNEL_MASK_5DOT1_L_C_R_Sl_Sr_SLF_HT 0x060F
+/* Speaker layout mask for six channels (5.1 mode, no LFE).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back left
+ * - Speaker back right
+ * - Speaker back center
+ */
+#define WMAPRO_CHANNEL_MASK_5DOT1_L_C_R_Bl_Br_Bc 0x0137
+/* Speaker layout mask for six channels (5.1 mode, Home Theater,
+ * no LFE).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back center
+ * - Speaker side left
+ * - Speaker side right
+ */
+#define WMAPRO_CHANNEL_MASK_5DOT1_L_C_R_Sl_Sr_Bc_HT 0x0707
+
+/* Speaker layout mask for seven channels (6.1 mode).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker low frequency
+ * - Speaker back left
+ * - Speaker back right
+ * - Speaker back center
+ */
+#define WMAPRO_CHANNEL_MASK_6DOT1_L_C_R_Bl_Br_Bc_SLF 0x013F
+
+/* Speaker layout mask for seven channels (6.1 mode, Home
+ * Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker low frequency
+ * - Speaker back center
+ * - Speaker side left
+ * - Speaker side right
+ */
+#define WMAPRO_CHANNEL_MASK_6DOT1_L_C_R_Sl_Sr_Bc_SLF_HT 0x070F
+
+/* Speaker layout mask for seven channels (6.1 mode, no LFE).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back left
+ * - Speaker back right
+ * - Speaker front left of center
+ * - Speaker front right of center
+ */
+#define WMAPRO_CHANNEL_MASK_6DOT1_L_C_R_Bl_Br_SFLOC_SFROC 0x00F7
+
+/* Speaker layout mask for seven channels (6.1 mode, Home
+ * Theater, no LFE).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker side left
+ * - Speaker side right
+ * - Speaker front left of center
+ * - Speaker front right of center
+ */
+#define WMAPRO_CHANNEL_MASK_6DOT1_L_C_R_Sl_Sr_SFLOC_SFROC_HT 0x0637
+
+/* Speaker layout mask for eight channels (7.1 mode).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back left
+ * - Speaker back right
+ * - Speaker low frequency
+ * - Speaker front left of center
+ * - Speaker front right of center
+ */
+#define WMAPRO_CHANNEL_MASK_7DOT1_L_C_R_Bl_Br_SLF_SFLOC_SFROC \
+ 0x00FF
+
+/* Speaker layout mask for eight channels (7.1 mode, Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker side left
+ * - Speaker side right
+ * - Speaker low frequency
+ * - Speaker front left of center
+ * - Speaker front right of center
+ *
+ */
+#define WMAPRO_CHANNEL_MASK_7DOT1_L_C_R_Sl_Sr_SLF_SFLOC_SFROC_HT \
+ 0x063F
+
+#define ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP 0x00010D82
+
+/* Maximum number of decoder output channels. */
+#define MAX_CHAN_MAP_CHANNELS 16
+
+/* Structure for decoder output channel mapping. */
+
+/* Payload of the #ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+struct asm_dec_out_chan_map_param {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ u32 num_channels;
+/* Number of decoder output channels.
+ * Supported values: 0 to #MAX_CHAN_MAP_CHANNELS
+ *
+ * A value of 0 indicates native channel mapping, which is valid
+ * only for NT mode. This means the output of the decoder is to be
+ * preserved as is.
+ */
+ u8 channel_mapping[MAX_CHAN_MAP_CHANNELS];
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED 0x00010D84
+
+/* Bitmask for the IEC 61937 enable flag.*/
+#define ASM_BIT_MASK_IEC_61937_STREAM_FLAG (0x00000001UL)
+
+/* Shift value for the IEC 61937 enable flag.*/
+#define ASM_SHIFT_IEC_61937_STREAM_FLAG 0
+
+/* Bitmask for the IEC 60958 enable flag.*/
+#define ASM_BIT_MASK_IEC_60958_STREAM_FLAG (0x00000002UL)
+
+/* Shift value for the IEC 60958 enable flag.*/
+#define ASM_SHIFT_IEC_60958_STREAM_FLAG 1
+
+/* Payload format for open write compressed command */
+
+/* Payload format for the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED
+ * command, which opens a stream for a given session ID and stream ID
+ * to be rendered in the compressed format.
+ */
+
+struct asm_stream_cmd_open_write_compressed {
+ struct apr_hdr hdr;
+ u32 flags;
+/* Mode flags that configure the stream for a specific format.
+ * Supported values:
+ * - Bit 0 -- IEC 61937 compatibility
+ * - 0 -- Stream is not in IEC 61937 format
+ * - 1 -- Stream is in IEC 61937 format
+ * - Bit 1 -- IEC 60958 compatibility
+ * - 0 -- Stream is not in IEC 60958 format
+ * - 1 -- Stream is in IEC 60958 format
+ * - Bits 2 to 31 -- 0 (Reserved)
+ *
+ * For the same stream, bit 0 cannot be set to 0 and bit 1 cannot
+ * be set to 1. A compressed stream connot have IEC 60958
+ * packetization applied without IEC 61937 packetization.
+ * @note1hang Currently, IEC 60958 packetized input streams are not
+ * supported.
+ */
+
+
+ u32 fmt_id;
+/* Specifies the media type of the HDMI stream to be opened.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AC3
+ * - #ASM_MEDIA_FMT_EAC3
+ * - #ASM_MEDIA_FMT_DTS
+ * - #ASM_MEDIA_FMT_ATRAC
+ * - #ASM_MEDIA_FMT_MAT
+ *
+ * @note1hang This field must be set to a valid media type even if
+ * IEC 61937 packetization is not performed by the aDSP.
+ */
+
+} __packed;
+
+
+/* Indicates the number of samples per channel to be removed from the
+ * beginning of the stream.
+ */
+#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE 0x00010D67
+
+/* Indicates the number of samples per channel to be removed from
+ * the end of the stream.
+ */
+#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE 0x00010D68
+
+struct asm_data_cmd_remove_silence {
+ struct apr_hdr hdr;
+ u32 num_samples_to_remove;
+ /* < Number of samples per channel to be removed.
+ * @values 0 to (2@sscr{32}-1)
+ */
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_READ_COMPRESSED 0x00010D95
+
+struct asm_stream_cmd_open_read_compressed {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode flags that indicate whether meta information per encoded
+ * frame is to be provided.
+ * Supported values for bit 4:
+ * - 0 -- Return data buffer contains all encoded frames only; it does
+ * not contain frame metadata.
+ * - 1 -- Return data buffer contains an array of metadata and encoded
+ * frames.
+ * - Use #ASM_BIT_MASK_META_INFO_FLAG to set the bitmask and
+ * #ASM_SHIFT_META_INFO_FLAG to set the shift value for this bit.
+ * All other bits are reserved; clients must set them to zero.
+ */
+
+ u32 frames_per_buf;
+/* Indicates the number of frames that need to be returned per
+ * read buffer
+ * Supported values: should be greater than 0
+ */
+
+} __packed;
+
+/* adsp_asm_stream_commands.h*/
+
+
+/* adsp_asm_api.h (no changes)*/
+#define ASM_STREAM_POSTPROCOPO_ID_DEFAULT \
+ 0x00010BE4
+#define ASM_STREAM_POSTPROCOPO_ID_PEAKMETER \
+ 0x00010D83
+#define ASM_STREAM_POSTPROCOPO_ID_NONE \
+ 0x00010C68
+#define ASM_STREAM_POSTPROCOPO_ID_MCH_PEAK_VOL \
+ 0x00010D8B
+#define ASM_STREAM_PREPROCOPO_ID_DEFAULT \
+ ASM_STREAM_POSTPROCOPO_ID_DEFAULT
+#define ASM_STREAM_PREPROCOPO_ID_NONE \
+ ASM_STREAM_POSTPROCOPO_ID_NONE
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_NONE_AUDIO_COPP \
+ 0x00010312
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_MONO_AUDIO_COPP \
+ 0x00010313
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP \
+ 0x00010314
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_IIR_AUDIO_COPP\
+ 0x00010704
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_MONO_AUDIO_COPP_MBDRCV2\
+ 0x0001070D
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP_MBDRCV2\
+ 0x0001070E
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_IIR_AUDIO_COPP_MBDRCV2\
+ 0x0001070F
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP_MBDRC_V3 \
+ 0x11000000
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_MCH_PEAK_VOL \
+ 0x0001031B
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_MIC_MONO_AUDIO_COPP 0x00010315
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_MIC_STEREO_AUDIO_COPP 0x00010316
+#define AUDPROC_COPPOPOLOGY_ID_MCHAN_IIR_AUDIO 0x00010715
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_DEFAULT_AUDIO_COPP 0x00010BE3
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_PEAKMETER_AUDIO_COPP 0x00010317
+#define AUDPROC_MODULE_ID_AIG 0x00010716
+#define AUDPROC_PARAM_ID_AIG_ENABLE 0x00010717
+#define AUDPROC_PARAM_ID_AIG_CONFIG 0x00010718
+
+struct Audio_AigParam {
+ uint16_t mode;
+/*< Mode word for enabling AIG/SIG mode .
+ * Byte offset: 0
+ */
+ int16_t staticGainL16Q12;
+/*< Static input gain when aigMode is set to 1.
+ * Byte offset: 2
+ */
+ int16_t initialGainDBL16Q7;
+/*<Initial value that the adaptive gain update starts from dB
+ * Q7 Byte offset: 4
+ */
+ int16_t idealRMSDBL16Q7;
+/*<Average RMS level that AIG attempts to achieve Q8.7
+ * Byte offset: 6
+ */
+ int32_t noiseGateL32;
+/*Threshold below which signal is considered as noise and AIG
+ * Byte offset: 8
+ */
+ int32_t minGainL32Q15;
+/*Minimum gain that can be provided by AIG Q16.15
+ * Byte offset: 12
+ */
+ int32_t maxGainL32Q15;
+/*Maximum gain that can be provided by AIG Q16.15
+ * Byte offset: 16
+ */
+ uint32_t gainAtRtUL32Q31;
+/*Attack/release time for AIG update Q1.31
+ * Byte offset: 20
+ */
+ uint32_t longGainAtRtUL32Q31;
+/*Long attack/release time while updating gain for
+ * noise/silence Q1.31 Byte offset: 24
+ */
+
+ uint32_t rmsTavUL32Q32;
+/* RMS smoothing time constant used for long-term RMS estimate
+ * Q0.32 Byte offset: 28
+ */
+
+ uint32_t gainUpdateStartTimMsUL32Q0;
+/* The waiting time before which AIG starts to apply adaptive
+ * gain update Q32.0 Byte offset: 32
+ */
+
+} __packed;
+
+
+#define ADM_MODULE_ID_EANS 0x00010C4A
+#define ADM_PARAM_ID_EANS_ENABLE 0x00010C4B
+#define ADM_PARAM_ID_EANS_PARAMS 0x00010C4C
+
+struct adm_eans_enable {
+
+ uint32_t enable_flag;
+/*< Specifies whether EANS is disabled (0) or enabled
+ * (nonzero).
+ * This is supported only for sampling rates of 8, 12, 16, 24, 32,
+ * and 48 kHz. It is not supported for sampling rates of 11.025,
+ * 22.05, or 44.1 kHz.
+ */
+
+} __packed;
+
+
+struct adm_eans_params {
+ int16_t eans_mode;
+/*< Mode word for enabling/disabling submodules.
+ * Byte offset: 0
+ */
+
+ int16_t eans_input_gain;
+/*< Q2.13 input gain to the EANS module.
+ * Byte offset: 2
+ */
+
+ int16_t eans_output_gain;
+/*< Q2.13 output gain to the EANS module.
+ * Byte offset: 4
+ */
+
+ int16_t eansarget_ns;
+/*< Target noise suppression level in dB.
+ * Byte offset: 6
+ */
+
+ int16_t eans_s_alpha;
+/*< Q3.12 over-subtraction factor for stationary noise
+ * suppression.
+ * Byte offset: 8
+ */
+
+ int16_t eans_n_alpha;
+/* < Q3.12 over-subtraction factor for nonstationary noise
+ * suppression.
+ * Byte offset: 10
+ */
+
+ int16_t eans_n_alphamax;
+/*< Q3.12 maximum over-subtraction factor for nonstationary
+ * noise suppression.
+ * Byte offset: 12
+ */
+ int16_t eans_e_alpha;
+/*< Q15 scaling factor for excess noise suppression.
+ * Byte offset: 14
+ */
+
+ int16_t eans_ns_snrmax;
+/*< Upper boundary in dB for SNR estimation.
+ * Byte offset: 16
+ */
+
+ int16_t eans_sns_block;
+/*< Quarter block size for stationary noise suppression.
+ * Byte offset: 18
+ */
+
+ int16_t eans_ns_i;
+/*< Initialization block size for noise suppression.
+ * Byte offset: 20
+ */
+ int16_t eans_np_scale;
+/*< Power scale factor for nonstationary noise update.
+ * Byte offset: 22
+ */
+
+ int16_t eans_n_lambda;
+/*< Smoothing factor for higher level nonstationary noise
+ * update.
+ * Byte offset: 24
+ */
+
+ int16_t eans_n_lambdaf;
+/*< Medium averaging factor for noise update.
+ * Byte offset: 26
+ */
+
+ int16_t eans_gs_bias;
+/*< Bias factor in dB for gain calculation.
+ * Byte offset: 28
+ */
+
+ int16_t eans_gs_max;
+/*< SNR lower boundary in dB for aggressive gain calculation.
+ * Byte offset: 30
+ */
+
+ int16_t eans_s_alpha_hb;
+/*< Q3.12 over-subtraction factor for high-band stationary
+ * noise suppression.
+ * Byte offset: 32
+ */
+
+ int16_t eans_n_alphamax_hb;
+/*< Q3.12 maximum over-subtraction factor for high-band
+ * nonstationary noise suppression.
+ * Byte offset: 34
+ */
+
+ int16_t eans_e_alpha_hb;
+/*< Q15 scaling factor for high-band excess noise suppression.
+ * Byte offset: 36
+ */
+
+ int16_t eans_n_lambda0;
+/*< Smoothing factor for nonstationary noise update during
+ * speech activity.
+ * Byte offset: 38
+ */
+
+ int16_t thresh;
+/*< Threshold for generating a binary VAD decision.
+ * Byte offset: 40
+ */
+
+ int16_t pwr_scale;
+/*< Indirect lower boundary of the noise level estimate.
+ * Byte offset: 42
+ */
+
+ int16_t hangover_max;
+/*< Avoids mid-speech clipping and reliably detects weak speech
+ * bursts at the end of speech activity.
+ * Byte offset: 44
+ */
+
+ int16_t alpha_snr;
+/*< Controls responsiveness of the VAD.
+ * Byte offset: 46
+ */
+
+ int16_t snr_diff_max;
+/*< Maximum SNR difference. Decreasing this parameter value may
+ * help in making correct decisions during abrupt changes; however,
+ * decreasing too much may increase false alarms during long
+ * pauses/silences.
+ * Byte offset: 48
+ */
+
+ int16_t snr_diff_min;
+/*< Minimum SNR difference. Decreasing this parameter value may
+ * help in making correct decisions during abrupt changes; however,
+ * decreasing too much may increase false alarms during long
+ * pauses/silences.
+ * Byte offset: 50
+ */
+
+ int16_t init_length;
+/*< Defines the number of frames for which a noise level
+ * estimate is set to a fixed value.
+ * Byte offset: 52
+ */
+
+ int16_t max_val;
+/*< Defines the upper limit of the noise level.
+ * Byte offset: 54
+ */
+
+ int16_t init_bound;
+/*< Defines the initial bounding value for the noise level
+ * estimate. This is used during the initial segment defined by the
+ * init_length parameter.
+ * Byte offset: 56
+ */
+
+ int16_t reset_bound;
+/*< Reset boundary for noise tracking.
+ * Byte offset: 58
+ */
+
+ int16_t avar_scale;
+/*< Defines the bias factor in noise estimation.
+ * Byte offset: 60
+ */
+
+ int16_t sub_nc;
+/*< Defines the window length for noise estimation.
+ * Byte offset: 62
+ */
+
+ int16_t spow_min;
+/*< Defines the minimum signal power required to update the
+ * boundaries for the noise floor estimate.
+ * Byte offset: 64
+ */
+
+ int16_t eans_gs_fast;
+/*< Fast smoothing factor for postprocessor gain.
+ * Byte offset: 66
+ */
+
+ int16_t eans_gs_med;
+/*< Medium smoothing factor for postprocessor gain.
+ * Byte offset: 68
+ */
+
+ int16_t eans_gs_slow;
+/*< Slow smoothing factor for postprocessor gain.
+ * Byte offset: 70
+ */
+
+ int16_t eans_swb_salpha;
+/*< Q3.12 super wideband aggressiveness factor for stationary
+ * noise suppression.
+ * Byte offset: 72
+ */
+
+ int16_t eans_swb_nalpha;
+/*< Q3.12 super wideband aggressiveness factor for
+ * nonstationary noise suppression.
+ * Byte offset: 74
+ */
+} __packed;
+#define ADM_MODULE_IDX_MIC_GAIN_CTRL 0x00010C35
+
+/* @addtogroup audio_pp_param_ids
+ * ID of the Tx mic gain control parameter used by the
+ * #ADM_MODULE_IDX_MIC_GAIN_CTRL module.
+ * @messagepayload
+ * @structure{admx_mic_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_IDX_MIC_GAIN.tex}
+ */
+#define ADM_PARAM_IDX_MIC_GAIN 0x00010C36
+
+/* Structure for a Tx mic gain parameter for the mic gain
+ * control module.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_IDX_MIC_GAIN parameter in the
+ * Tx Mic Gain Control module.
+ */
+struct admx_mic_gain {
+ uint16_t tx_mic_gain;
+ /*< Linear gain in Q13 format. */
+
+ uint16_t reserved;
+ /*< Clients must set this field to zero. */
+} __packed;
+
+/* end_addtogroup audio_pp_param_ids */
+
+/* @ingroup audio_pp_module_ids
+ * ID of the Rx Codec Gain Control module.
+ *
+ * This module supports the following parameter ID:
+ * - #ADM_PARAM_ID_RX_CODEC_GAIN
+ */
+#define ADM_MODULE_ID_RX_CODEC_GAIN_CTRL 0x00010C37
+
+/* @addtogroup audio_pp_param_ids
+ * ID of the Rx codec gain control parameter used by the
+ * #ADM_MODULE_ID_RX_CODEC_GAIN_CTRL module.
+ *
+ * @messagepayload
+ * @structure{adm_rx_codec_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_RX_CODEC_GAIN.tex}
+ */
+#define ADM_PARAM_ID_RX_CODEC_GAIN 0x00010C38
+
+/* Structure for the Rx common codec gain control module. */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_RX_CODEC_GAIN parameter
+ * in the Rx Codec Gain Control module.
+ */
+
+
+struct adm_rx_codec_gain {
+ uint16_t rx_codec_gain;
+ /* Linear gain in Q13 format. */
+
+ uint16_t reserved;
+ /* Clients must set this field to zero.*/
+} __packed;
+
+/* end_addtogroup audio_pp_param_ids */
+
+/* @ingroup audio_pp_module_ids
+ * ID of the HPF Tuning Filter module on the Tx path.
+ * This module supports the following parameter IDs:
+ * - #ADM_PARAM_ID_HPF_IIRX_FILTER_ENABLE_CONFIG
+ * - #ADM_PARAM_ID_HPF_IIRX_FILTER_PRE_GAIN
+ * - #ADM_PARAM_ID_HPF_IIRX_FILTER_CONFIG_PARAMS
+ */
+#define ADM_MODULE_ID_HPF_IIRX_FILTER 0x00010C3D
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the Tx HPF IIR filter enable parameter used by the
+ * #ADM_MODULE_ID_HPF_IIRX_FILTER module.
+ * @parspace Message payload
+ * @structure{adm_hpfx_iir_filter_enable_cfg}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_HPF_IIRX_FILTER_ENABLE_CONFIG.tex}
+ */
+#define ADM_PARAM_ID_HPF_IIRX_FILTER_ENABLE_CONFIG 0x00010C3E
+
+/* ID of the Tx HPF IIR filter pregain parameter used by the
+ * #ADM_MODULE_ID_HPF_IIRX_FILTER module.
+ * @parspace Message payload
+ * @structure{adm_hpfx_iir_filter_pre_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_HPF_IIRX_FILTER_PRE_GAIN.tex}
+ */
+#define ADM_PARAM_ID_HPF_IIRX_FILTER_PRE_GAIN 0x00010C3F
+
+/* ID of the Tx HPF IIR filter configuration parameters used by the
+ * #ADM_MODULE_ID_HPF_IIRX_FILTER module.
+ * @parspace Message payload
+ * @structure{adm_hpfx_iir_filter_cfg_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_HPF_IIRX_FILTER_CONFIG_PA
+ * RAMS.tex}
+ */
+#define ADM_PARAM_ID_HPF_IIRX_FILTER_CONFIG_PARAMS 0x00010C40
+
+/* Structure for enabling a configuration parameter for
+ * the HPF IIR tuning filter module on the Tx path.
+ */
+
+/* @brief Payload of the #ADM_PARAM_ID_HPF_IIRX_FILTER_ENABLE_CONFIG
+ * parameter in the Tx path HPF Tuning Filter module.
+ */
+struct adm_hpfx_iir_filter_enable_cfg {
+ uint32_t enable_flag;
+/* Specifies whether the HPF tuning filter is disabled (0) or
+ * enabled (nonzero).
+ */
+} __packed;
+
+
+/* Structure for the pregain parameter for the HPF
+ * IIR tuning filter module on the Tx path.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_HPF_IIRX_FILTER_PRE_GAIN parameter
+ * in the Tx path HPF Tuning Filter module.
+ */
+struct adm_hpfx_iir_filter_pre_gain {
+ uint16_t pre_gain;
+ /* Linear gain in Q13 format. */
+
+ uint16_t reserved;
+ /* Clients must set this field to zero.*/
+} __packed;
+
+
+/* Structure for the configuration parameter for the
+ * HPF IIR tuning filter module on the Tx path.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_HPF_IIRX_FILTER_CONFIG_PARAMS
+ * parameters in the Tx path HPF Tuning Filter module. \n
+ * \n
+ * This structure is followed by tuning filter coefficients as follows: \n
+ * - Sequence of int32_t FilterCoeffs.
+ * Each band has five coefficients, each in int32_t format in the order of
+ * b0, b1, b2, a1, a2.
+ * - Sequence of int16_t NumShiftFactor.
+ * One int16_t per band. The numerator shift factor is related to the Q
+ * factor of the filter coefficients.
+ * - Sequence of uint16_t PanSetting.
+ * One uint16_t for each band to indicate application of the filter to
+ * left (0), right (1), or both (2) channels.
+ */
+struct adm_hpfx_iir_filter_cfg_params {
+ uint16_t num_biquad_stages;
+/*< Number of bands.
+ * Supported values: 0 to 20
+ */
+
+ uint16_t reserved;
+ /*< Clients must set this field to zero.*/
+} __packed;
+
+/* end_addtogroup audio_pp_module_ids */
+
+/* @addtogroup audio_pp_module_ids */
+/* ID of the Tx path IIR Tuning Filter module.
+ * This module supports the following parameter IDs:
+ * - #ADM_PARAM_IDX_IIR_FILTER_ENABLE_CONFIG
+ */
+#define ADM_MODULE_IDX_IIR_FILTER 0x00010C41
+
+/* ID of the Rx path IIR Tuning Filter module for the left channel.
+ * The parameter IDs of the IIR tuning filter module
+ * (#ASM_MODULE_ID_IIRUNING_FILTER) are used for the left IIR Rx tuning
+ * filter.
+ *
+ * Pan parameters are not required for this per-channel IIR filter; the pan
+ * parameters are ignored by this module.
+ */
+#define ADM_MODULE_ID_LEFT_IIRUNING_FILTER 0x00010705
+
+/* ID of the the Rx path IIR Tuning Filter module for the right
+ * channel.
+ * The parameter IDs of the IIR tuning filter module
+ * (#ASM_MODULE_ID_IIRUNING_FILTER) are used for the right IIR Rx
+ * tuning filter.
+ *
+ * Pan parameters are not required for this per-channel IIR filter;
+ * the pan parameters are ignored by this module.
+ */
+#define ADM_MODULE_ID_RIGHT_IIRUNING_FILTER 0x00010706
+
+/* end_addtogroup audio_pp_module_ids */
+
+/* @addtogroup audio_pp_param_ids */
+
+/* ID of the Tx IIR filter enable parameter used by the
+ * #ADM_MODULE_IDX_IIR_FILTER module.
+ * @parspace Message payload
+ * @structure{admx_iir_filter_enable_cfg}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_IDX_IIR_FILTER_ENABLE_CONFIG.tex}
+ */
+#define ADM_PARAM_IDX_IIR_FILTER_ENABLE_CONFIG 0x00010C42
+
+/* ID of the Tx IIR filter pregain parameter used by the
+ * #ADM_MODULE_IDX_IIR_FILTER module.
+ * @parspace Message payload
+ * @structure{admx_iir_filter_pre_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_IDX_IIR_FILTER_PRE_GAIN.tex}
+ */
+#define ADM_PARAM_IDX_IIR_FILTER_PRE_GAIN 0x00010C43
+
+/* ID of the Tx IIR filter configuration parameters used by the
+ * #ADM_MODULE_IDX_IIR_FILTER module.
+ * @parspace Message payload
+ * @structure{admx_iir_filter_cfg_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_IDX_IIR_FILTER_CONFIG_PARAMS.tex}
+ */
+#define ADM_PARAM_IDX_IIR_FILTER_CONFIG_PARAMS 0x00010C44
+
+/* Structure for enabling the configuration parameter for the
+ * IIR filter module on the Tx path.
+ */
+
+/* @brief Payload of the #ADM_PARAM_IDX_IIR_FILTER_ENABLE_CONFIG
+ * parameter in the Tx Path IIR Tuning Filter module.
+ */
+
+struct admx_iir_filter_enable_cfg {
+ uint32_t enable_flag;
+/*< Specifies whether the IIR tuning filter is disabled (0) or
+ * enabled (nonzero).
+ */
+
+} __packed;
+
+
+/* Structure for the pregain parameter for the
+ * IIR filter module on the Tx path.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_IDX_IIR_FILTER_PRE_GAIN
+ * parameter in the Tx Path IIR Tuning Filter module.
+ */
+
+struct admx_iir_filter_pre_gain {
+ uint16_t pre_gain;
+ /*< Linear gain in Q13 format. */
+
+ uint16_t reserved;
+ /*< Clients must set this field to zero.*/
+} __packed;
+
+
+/* Structure for the configuration parameter for the
+ * IIR filter module on the Tx path.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_IDX_IIR_FILTER_CONFIG_PARAMS
+ * parameter in the Tx Path IIR Tuning Filter module. \n
+ * \n
+ * This structure is followed by the HPF IIR filter coefficients on
+ * the Tx path as follows: \n
+ * - Sequence of int32_t ulFilterCoeffs. Each band has five
+ * coefficients, each in int32_t format in the order of b0, b1, b2,
+ * a1, a2.
+ * - Sequence of int16_t sNumShiftFactor. One int16_t per band. The
+ * numerator shift factor is related to the Q factor of the filter
+ * coefficients.
+ * - Sequence of uint16_t usPanSetting. One uint16_t for each band
+ * to indicate if the filter is applied to left (0), right (1), or
+ * both (2) channels.
+ */
+struct admx_iir_filter_cfg_params {
+ uint16_t num_biquad_stages;
+/*< Number of bands.
+ * Supported values: 0 to 20
+ */
+
+ uint16_t reserved;
+ /*< Clients must set this field to zero.*/
+} __packed;
+
+/* end_addtogroup audio_pp_module_ids */
+
+/* @ingroup audio_pp_module_ids
+ * ID of the QEnsemble module.
+ * This module supports the following parameter IDs:
+ * - #ADM_PARAM_ID_QENSEMBLE_ENABLE
+ * - #ADM_PARAM_ID_QENSEMBLE_BACKGAIN
+ * - #ADM_PARAM_ID_QENSEMBLE_SET_NEW_ANGLE
+ */
+#define ADM_MODULE_ID_QENSEMBLE 0x00010C59
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the QEnsemble enable parameter used by the
+ * #ADM_MODULE_ID_QENSEMBLE module.
+ * @messagepayload
+ * @structure{adm_qensemble_enable}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_QENSEMBLE_ENABLE.tex}
+ */
+#define ADM_PARAM_ID_QENSEMBLE_ENABLE 0x00010C60
+
+/* ID of the QEnsemble back gain parameter used by the
+ * #ADM_MODULE_ID_QENSEMBLE module.
+ * @messagepayload
+ * @structure{adm_qensemble_param_backgain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_QENSEMBLE_BACKGAIN.tex}
+ */
+#define ADM_PARAM_ID_QENSEMBLE_BACKGAIN 0x00010C61
+
+/* ID of the QEnsemble new angle parameter used by the
+ * #ADM_MODULE_ID_QENSEMBLE module.
+ * @messagepayload
+ * @structure{adm_qensemble_param_set_new_angle}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_QENSEMBLE_SET_NEW_ANGLE.tex}
+ */
+#define ADM_PARAM_ID_QENSEMBLE_SET_NEW_ANGLE 0x00010C62
+
+/* Structure for enabling the configuration parameter for the
+ * QEnsemble module.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_QENSEMBLE_ENABLE
+ * parameter used by the QEnsemble module.
+ */
+struct adm_qensemble_enable {
+ uint32_t enable_flag;
+/*< Specifies whether the QEnsemble module is disabled (0) or enabled
+ * (nonzero).
+ */
+} __packed;
+
+
+/* Structure for the background gain for the QEnsemble module. */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_QENSEMBLE_BACKGAIN
+ * parameter used by
+ * the QEnsemble module.
+ */
+struct adm_qensemble_param_backgain {
+ int16_t back_gain;
+/*< Linear gain in Q15 format.
+ * Supported values: 0 to 32767
+ */
+
+ uint16_t reserved;
+ /*< Clients must set this field to zero.*/
+} __packed;
+/* Structure for setting a new angle for the QEnsemble module. */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_QENSEMBLE_SET_NEW_ANGLE
+ * parameter used
+ * by the QEnsemble module.
+ */
+struct adm_qensemble_param_set_new_angle {
+ int16_t new_angle;
+/*< New angle in degrees.
+ * Supported values: 0 to 359
+ */
+
+ int16_t time_ms;
+/*< Transition time in milliseconds to set the new angle.
+ * Supported values: 0 to 32767
+ */
+} __packed;
+
+
+#define ADM_CMD_GET_PP_TOPO_MODULE_LIST 0x00010349
+#define ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST 0x00010350
+#define AUDPROC_PARAM_ID_ENABLE 0x00010904
+ /*
+ * Payload of the ADM_CMD_GET_PP_TOPO_MODULE_LIST command.
+ */
+struct adm_cmd_get_pp_topo_module_list_t {
+ struct apr_hdr hdr;
+ /* Lower 32 bits of the 64-bit parameter data payload address. */
+ uint32_t data_payload_addr_lsw;
+ /*
+ * Upper 32 bits of the 64-bit parameter data payload address.
+ *
+ *
+ * The size of the shared memory, if specified, must be large enough to
+ * contain the entire parameter data payload, including the module ID,
+ * parameter ID, parameter size, and parameter values.
+ */
+ uint32_t data_payload_addr_msw;
+ /*
+ * Unique identifier for an address.
+ *
+ * This memory map handle is returned by the aDSP through the
+ * #ADM_CMD_SHARED_MEM_MAP_REGIONS command.
+ *
+ * @values
+ * - Non-NULL -- On acknowledgment, the parameter data payloads begin at
+ * the address specified (out-of-band)
+ * - NULL -- The acknowledgment's payload contains the parameter data
+ * (in-band) @tablebulletend
+ */
+ uint32_t mem_map_handle;
+ /*
+ * Maximum data size of the list of modules. This
+ * field is a multiple of 4 bytes.
+ */
+ uint16_t param_max_size;
+ /* This field must be set to zero. */
+ uint16_t reserved;
+} __packed;
+
+/*
+ * Payload of the ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST message, which returns
+ * module ids in response to an ADM_CMD_GET_PP_TOPO_MODULE_LIST command.
+ * Immediately following this structure is the acknowledgment <b>module id
+ * data variable payload</b> containing the pre/postprocessing module id
+ * values. For an in-band scenario, the variable payload depends on the size
+ * of the parameter.
+ */
+struct adm_cmd_rsp_get_pp_topo_module_list_t {
+ /* Status message (error code). */
+ uint32_t status;
+} __packed;
+
+struct audproc_topology_module_id_info_t {
+ uint32_t num_modules;
+} __packed;
+
+/* end_addtogroup audio_pp_module_ids */
+
+/* @ingroup audio_pp_module_ids
+ * ID of the Volume Control module pre/postprocessing block.
+ * This module supports the following parameter IDs:
+ * - #ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN
+ * - #ASM_PARAM_ID_MULTICHANNEL_GAIN
+ * - #ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG
+ * - #ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS
+ * - #ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS
+ * - #ASM_PARAM_ID_MULTICHANNEL_GAIN
+ * - #ASM_PARAM_ID_MULTICHANNEL_MUTE
+ */
+#define ASM_MODULE_ID_VOL_CTRL 0x00010BFE
+#define ASM_MODULE_ID_VOL_CTRL2 0x00010910
+#define AUDPROC_MODULE_ID_VOL_CTRL ASM_MODULE_ID_VOL_CTRL
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the master gain parameter used by the #ASM_MODULE_ID_VOL_CTRL
+ * module.
+ * @messagepayload
+ * @structure{asm_volume_ctrl_master_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN.tex}
+ */
+#define ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN 0x00010BFF
+#define AUDPROC_PARAM_ID_VOL_CTRL_MASTER_GAIN ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN
+
+/* ID of the left/right channel gain parameter used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ * @messagepayload
+ * @structure{asm_volume_ctrl_lr_chan_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_MULTICHANNEL_GAIN.tex}
+ */
+#define ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN 0x00010C00
+
+/* ID of the mute configuration parameter used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ * @messagepayload
+ * @structure{asm_volume_ctrl_mute_config}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG.tex}
+ */
+#define ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG 0x00010C01
+
+/* ID of the soft stepping volume parameters used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ * @messagepayload
+ * @structure{asm_soft_step_volume_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMET
+ * ERS.tex}
+ */
+#define ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS 0x00010C29
+#define AUDPROC_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS\
+ ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS
+
+/* ID of the soft pause parameters used by the #ASM_MODULE_ID_VOL_CTRL
+ * module.
+ */
+#define ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS 0x00010D6A
+
+/* ID of the multiple-channel volume control parameters used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ */
+#define ASM_PARAM_ID_MULTICHANNEL_GAIN 0x00010713
+
+/* ID of the multiple-channel mute configuration parameters used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ */
+
+#define ASM_PARAM_ID_MULTICHANNEL_MUTE 0x00010714
+
+/* Structure for the master gain parameter for a volume control
+ * module.
+ */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN
+ * parameter used by the Volume Control module.
+ */
+
+
+
+struct asm_volume_ctrl_master_gain {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ uint16_t master_gain;
+ /* Linear gain in Q13 format. */
+
+ uint16_t reserved;
+ /* Clients must set this field to zero. */
+} __packed;
+
+
+struct asm_volume_ctrl_lr_chan_gain {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+
+ uint16_t l_chan_gain;
+ /*< Linear gain in Q13 format for the left channel. */
+
+ uint16_t r_chan_gain;
+ /*< Linear gain in Q13 format for the right channel.*/
+} __packed;
+
+
+/* Structure for the mute configuration parameter for a
+ * volume control module.
+ */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG
+ * parameter used by the Volume Control module.
+ */
+
+
+struct asm_volume_ctrl_mute_config {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ uint32_t mute_flag;
+/*< Specifies whether mute is disabled (0) or enabled (nonzero).*/
+
+} __packed;
+
+/*
+ * Supported parameters for a soft stepping linear ramping curve.
+ */
+#define ASM_PARAM_SVC_RAMPINGCURVE_LINEAR 0
+
+/*
+ * Exponential ramping curve.
+ */
+#define ASM_PARAM_SVC_RAMPINGCURVE_EXP 1
+
+/*
+ * Logarithmic ramping curve.
+ */
+#define ASM_PARAM_SVC_RAMPINGCURVE_LOG 2
+
+/* Structure for holding soft stepping volume parameters. */
+
+
+/* Payload of the #ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS
+ * parameters used by the Volume Control module.
+ */
+struct asm_soft_step_volume_params {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ uint32_t period;
+/*< Period in milliseconds.
+ * Supported values: 0 to 15000
+ */
+
+ uint32_t step;
+/*< Step in microseconds.
+ * Supported values: 0 to 15000000
+ */
+
+ uint32_t ramping_curve;
+/*< Ramping curve type.
+ * Supported values:
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_LINEAR
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_EXP
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_LOG
+ */
+} __packed;
+
+
+/* Structure for holding soft pause parameters. */
+
+
+/* Payload of the #ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS
+ * parameters used by the Volume Control module.
+ */
+
+
+struct asm_soft_pause_params {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ uint32_t enable_flag;
+/*< Specifies whether soft pause is disabled (0) or enabled
+ * (nonzero).
+ */
+
+
+
+ uint32_t period;
+/*< Period in milliseconds.
+ * Supported values: 0 to 15000
+ */
+
+ uint32_t step;
+/*< Step in microseconds.
+ * Supported values: 0 to 15000000
+ */
+
+ uint32_t ramping_curve;
+/*< Ramping curve.
+ * Supported values:
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_LINEAR
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_EXP
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_LOG
+ */
+} __packed;
+
+
+/* Maximum number of channels.*/
+#define VOLUME_CONTROL_MAX_CHANNELS 8
+
+/* Structure for holding one channel type - gain pair. */
+
+
+/* Payload of the #ASM_PARAM_ID_MULTICHANNEL_GAIN channel
+ * type/gain pairs used by the Volume Control module. \n \n This
+ * structure immediately follows the
+ * asm_volume_ctrl_multichannel_gain structure.
+ */
+
+
+struct asm_volume_ctrl_channeltype_gain_pair {
+ uint8_t channeltype;
+ /*
+ * Channel type for which the gain setting is to be applied.
+ * Supported values:
+ * - #PCM_CHANNEL_L
+ * - #PCM_CHANNEL_R
+ * - #PCM_CHANNEL_C
+ * - #PCM_CHANNEL_LS
+ * - #PCM_CHANNEL_RS
+ * - #PCM_CHANNEL_LFE
+ * - #PCM_CHANNEL_CS
+ * - #PCM_CHANNEL_LB
+ * - #PCM_CHANNEL_RB
+ * - #PCM_CHANNELS
+ * - #PCM_CHANNEL_CVH
+ * - #PCM_CHANNEL_MS
+ * - #PCM_CHANNEL_FLC
+ * - #PCM_CHANNEL_FRC
+ * - #PCM_CHANNEL_RLC
+ * - #PCM_CHANNEL_RRC
+ */
+
+ uint8_t reserved1;
+ /* Clients must set this field to zero. */
+
+ uint8_t reserved2;
+ /* Clients must set this field to zero. */
+
+ uint8_t reserved3;
+ /* Clients must set this field to zero. */
+
+ uint32_t gain;
+ /*
+ * Gain value for this channel in Q28 format.
+ * Supported values: Any
+ */
+} __packed;
+
+
+/* Structure for the multichannel gain command */
+
+
+/* Payload of the #ASM_PARAM_ID_MULTICHANNEL_GAIN
+ * parameters used by the Volume Control module.
+ */
+
+
+struct asm_volume_ctrl_multichannel_gain {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ uint32_t num_channels;
+ /*
+ * Number of channels for which gain values are provided. Any
+ * channels present in the data for which gain is not provided are
+ * set to unity gain.
+ * Supported values: 1 to 8
+ */
+
+ struct asm_volume_ctrl_channeltype_gain_pair
+ gain_data[VOLUME_CONTROL_MAX_CHANNELS];
+ /* Array of channel type/gain pairs.*/
+} __packed;
+
+
+/* Structure for holding one channel type - mute pair. */
+
+
+/* Payload of the #ASM_PARAM_ID_MULTICHANNEL_MUTE channel
+ * type/mute setting pairs used by the Volume Control module. \n \n
+ * This structure immediately follows the
+ * asm_volume_ctrl_multichannel_mute structure.
+ */
+
+
+struct asm_volume_ctrl_channelype_mute_pair {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ uint8_t channelype;
+/*< Channel type for which the mute setting is to be applied.
+ * Supported values:
+ * - #PCM_CHANNEL_L
+ * - #PCM_CHANNEL_R
+ * - #PCM_CHANNEL_C
+ * - #PCM_CHANNEL_LS
+ * - #PCM_CHANNEL_RS
+ * - #PCM_CHANNEL_LFE
+ * - #PCM_CHANNEL_CS
+ * - #PCM_CHANNEL_LB
+ * - #PCM_CHANNEL_RB
+ * - #PCM_CHANNELS
+ * - #PCM_CHANNEL_CVH
+ * - #PCM_CHANNEL_MS
+ * - #PCM_CHANNEL_FLC
+ * - #PCM_CHANNEL_FRC
+ * - #PCM_CHANNEL_RLC
+ * - #PCM_CHANNEL_RRC
+ */
+
+ uint8_t reserved1;
+ /*< Clients must set this field to zero. */
+
+ uint8_t reserved2;
+ /*< Clients must set this field to zero. */
+
+ uint8_t reserved3;
+ /*< Clients must set this field to zero. */
+
+ uint32_t mute;
+/*< Mute setting for this channel.
+ * Supported values:
+ * - 0 = Unmute
+ * - Nonzero = Mute
+ */
+} __packed;
+
+
+/* Structure for the multichannel mute command */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_MULTICHANNEL_MUTE
+ * parameters used by the Volume Control module.
+ */
+
+
+struct asm_volume_ctrl_multichannel_mute {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ uint32_t num_channels;
+/*< Number of channels for which mute configuration is
+ * provided. Any channels present in the data for which mute
+ * configuration is not provided are set to unmute.
+ * Supported values: 1 to 8
+ */
+
+struct asm_volume_ctrl_channelype_mute_pair
+ mute_data[VOLUME_CONTROL_MAX_CHANNELS];
+ /*< Array of channel type/mute setting pairs.*/
+} __packed;
+/* end_addtogroup audio_pp_param_ids */
+
+/* audio_pp_module_ids
+ * ID of the IIR Tuning Filter module.
+ * This module supports the following parameter IDs:
+ * - #ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CONFIG
+ * - #ASM_PARAM_ID_IIRUNING_FILTER_PRE_GAIN
+ * - #ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS
+ */
+#define ASM_MODULE_ID_IIRUNING_FILTER 0x00010C02
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the IIR tuning filter enable parameter used by the
+ * #ASM_MODULE_ID_IIRUNING_FILTER module.
+ * @messagepayload
+ * @structure{asm_iiruning_filter_enable}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CO
+ * NFIG.tex}
+ */
+#define ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CONFIG 0x00010C03
+
+/* ID of the IIR tuning filter pregain parameter used by the
+ * #ASM_MODULE_ID_IIRUNING_FILTER module.
+ */
+#define ASM_PARAM_ID_IIRUNING_FILTER_PRE_GAIN 0x00010C04
+
+/* ID of the IIR tuning filter configuration parameters used by the
+ * #ASM_MODULE_ID_IIRUNING_FILTER module.
+ */
+#define ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS 0x00010C05
+
+/* Structure for an enable configuration parameter for an
+ * IIR tuning filter module.
+ */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CONFIG
+ * parameter used by the IIR Tuning Filter module.
+ */
+struct asm_iiruning_filter_enable {
+ uint32_t enable_flag;
+/*< Specifies whether the IIR tuning filter is disabled (0) or
+ * enabled (1).
+ */
+} __packed;
+
+/* Structure for the pregain parameter for an IIR tuning filter module. */
+
+
+/* Payload of the #ASM_PARAM_ID_IIRUNING_FILTER_PRE_GAIN
+ * parameters used by the IIR Tuning Filter module.
+ */
+struct asm_iiruning_filter_pregain {
+ uint16_t pregain;
+ /*< Linear gain in Q13 format. */
+
+ uint16_t reserved;
+ /*< Clients must set this field to zero.*/
+} __packed;
+
+/* Structure for the configuration parameter for an IIR tuning filter
+ * module.
+ */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS
+ * parameters used by the IIR Tuning Filter module. \n
+ * \n
+ * This structure is followed by the IIR filter coefficients: \n
+ * - Sequence of int32_t FilterCoeffs \n
+ * Five coefficients for each band. Each coefficient is in int32_t format, in
+ * the order of b0, b1, b2, a1, a2.
+ * - Sequence of int16_t NumShiftFactor \n
+ * One int16_t per band. The numerator shift factor is related to the Q
+ * factor of the filter coefficients.
+ * - Sequence of uint16_t PanSetting \n
+ * One uint16_t per band, indicating if the filter is applied to left (0),
+ * right (1), or both (2) channels.
+ */
+struct asm_iir_filter_config_params {
+ uint16_t num_biquad_stages;
+/*< Number of bands.
+ * Supported values: 0 to 20
+ */
+
+ uint16_t reserved;
+ /*< Clients must set this field to zero.*/
+} __packed;
+
+/* audio_pp_module_ids
+ * ID of the Multiband Dynamic Range Control (MBDRC) module on the Tx/Rx
+ * paths.
+ * This module supports the following parameter IDs:
+ * - #ASM_PARAM_ID_MBDRC_ENABLE
+ * - #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS
+ */
+#define ASM_MODULE_ID_MBDRC 0x00010C06
+
+/* audio_pp_param_ids */
+/* ID of the MBDRC enable parameter used by the #ASM_MODULE_ID_MBDRC module.
+ * @messagepayload
+ * @structure{asm_mbdrc_enable}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_MBDRC_ENABLE.tex}
+ */
+#define ASM_PARAM_ID_MBDRC_ENABLE 0x00010C07
+
+/* ID of the MBDRC configuration parameters used by the
+ * #ASM_MODULE_ID_MBDRC module.
+ * @messagepayload
+ * @structure{asm_mbdrc_config_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_MBDRC_CONFIG_PARAMS.tex}
+ *
+ * @parspace Sub-band DRC configuration parameters
+ * @structure{asm_subband_drc_config_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_MBDRC_CONFIG_PARAMS_subband_DRC.tex}
+ *
+ * @keep{6}
+ * To obtain legacy ADRC from MBDRC, use the calibration tool to:
+ *
+ * - Enable MBDRC (EnableFlag = TRUE)
+ * - Set number of bands to 1 (uiNumBands = 1)
+ * - Enable the first MBDRC band (DrcMode[0] = DRC_ENABLED = 1)
+ * - Clear the first band mute flag (MuteFlag[0] = 0)
+ * - Set the first band makeup gain to unity (compMakeUpGain[0] = 0x2000)
+ * - Use the legacy ADRC parameters to calibrate the rest of the MBDRC
+ * parameters.
+ */
+#define ASM_PARAM_ID_MBDRC_CONFIG_PARAMS 0x00010C08
+
+/* end_addtogroup audio_pp_param_ids */
+
+/* audio_pp_module_ids
+ * ID of the MMBDRC module version 2 pre/postprocessing block.
+ * This module differs from the original MBDRC (#ASM_MODULE_ID_MBDRC) in
+ * the length of the filters used in each sub-band.
+ * This module supports the following parameter ID:
+ * - #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS_IMPROVED_FILTBANK_V2
+ */
+#define ASM_MODULE_ID_MBDRCV2 0x0001070B
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the configuration parameters used by the
+ * #ASM_MODULE_ID_MBDRCV2 module for the improved filter structure
+ * of the MBDRC v2 pre/postprocessing block.
+ * The update to this configuration structure from the original
+ * MBDRC is the number of filter coefficients in the filter
+ * structure. The sequence for is as follows:
+ * - 1 band = 0 FIR coefficient + 1 mute flag + uint16_t padding
+ * - 2 bands = 141 FIR coefficients + 2 mute flags + uint16_t padding
+ * - 3 bands = 141+81 FIR coefficients + 3 mute flags + uint16_t padding
+ * - 4 bands = 141+81+61 FIR coefficients + 4 mute flags + uint16_t
+ * padding
+ * - 5 bands = 141+81+61+61 FIR coefficients + 5 mute flags +
+ * uint16_t padding
+ * This block uses the same parameter structure as
+ * #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS.
+ */
+#define ASM_PARAM_ID_MBDRC_CONFIG_PARAMS_IMPROVED_FILTBANK_V2 \
+ 0x0001070C
+
+#define ASM_MODULE_ID_MBDRCV3 0x0001090B
+/*
+ * ID of the MMBDRC module version 3 pre/postprocessing block.
+ * This module differs from MBDRCv2 (#ASM_MODULE_ID_MBDRCV2) in
+ * that it supports both 16- and 24-bit data.
+ * This module supports the following parameter ID:
+ * - #ASM_PARAM_ID_MBDRC_ENABLE
+ * - #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS
+ * - #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS_V3
+ * - #ASM_PARAM_ID_MBDRC_FILTER_XOVER_FREQS
+ */
+
+/* Structure for the enable parameter for an MBDRC module. */
+
+
+/* Payload of the #ASM_PARAM_ID_MBDRC_ENABLE parameter used by the
+ * MBDRC module.
+ */
+struct asm_mbdrc_enable {
+ uint32_t enable_flag;
+/*< Specifies whether MBDRC is disabled (0) or enabled (nonzero).*/
+} __packed;
+
+/* Structure for the configuration parameters for an MBDRC module. */
+
+
+/* Payload of the #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS
+ * parameters used by the MBDRC module. \n \n Following this
+ * structure is the payload for sub-band DRC configuration
+ * parameters (asm_subband_drc_config_params). This sub-band
+ * structure must be repeated for each band.
+ */
+
+
+struct asm_mbdrc_config_params {
+ uint16_t num_bands;
+/*< Number of bands.
+ * Supported values: 1 to 5
+ */
+
+ int16_t limiterhreshold;
+/*< Threshold in decibels for the limiter output.
+ * Supported values: -72 to 18 \n
+ * Recommended value: 3994 (-0.22 db in Q3.12 format)
+ */
+
+ int16_t limiter_makeup_gain;
+/*< Makeup gain in decibels for the limiter output.
+ * Supported values: -42 to 42 \n
+ * Recommended value: 256 (0 dB in Q7.8 format)
+ */
+
+ int16_t limiter_gc;
+/*< Limiter gain recovery coefficient.
+ * Supported values: 0.5 to 0.99 \n
+ * Recommended value: 32440 (0.99 in Q15 format)
+ */
+
+ int16_t limiter_delay;
+/*< Limiter delay in samples.
+ * Supported values: 0 to 10 \n
+ * Recommended value: 262 (0.008 samples in Q15 format)
+ */
+
+ int16_t limiter_max_wait;
+/*< Maximum limiter waiting time in samples.
+ * Supported values: 0 to 10 \n
+ * Recommended value: 262 (0.008 samples in Q15 format)
+ */
+} __packed;
+
+/* DRC configuration structure for each sub-band of an MBDRC module. */
+
+
+/* Payload of the #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS DRC
+ * configuration parameters for each sub-band in the MBDRC module.
+ * After this DRC structure is configured for valid bands, the next
+ * MBDRC setparams expects the sequence of sub-band MBDRC filter
+ * coefficients (the length depends on the number of bands) plus the
+ * mute flag for that band plus uint16_t padding.
+ *
+ * @keep{10}
+ * The filter coefficient and mute flag are of type int16_t:
+ * - FIR coefficient = int16_t firFilter
+ * - Mute flag = int16_t fMuteFlag
+ *
+ * The sequence is as follows:
+ * - 1 band = 0 FIR coefficient + 1 mute flag + uint16_t padding
+ * - 2 bands = 97 FIR coefficients + 2 mute flags + uint16_t padding
+ * - 3 bands = 97+33 FIR coefficients + 3 mute flags + uint16_t padding
+ * - 4 bands = 97+33+33 FIR coefficients + 4 mute flags + uint16_t padding
+ * - 5 bands = 97+33+33+33 FIR coefficients + 5 mute flags + uint16_t padding
+ *
+ * For improved filterbank, the sequence is as follows:
+ * - 1 band = 0 FIR coefficient + 1 mute flag + uint16_t padding
+ * - 2 bands = 141 FIR coefficients + 2 mute flags + uint16_t padding
+ * - 3 bands = 141+81 FIR coefficients + 3 mute flags + uint16_t padding
+ * - 4 bands = 141+81+61 FIR coefficients + 4 mute flags + uint16_t padding
+ * - 5 bands = 141+81+61+61 FIR coefficients + 5 mute flags + uint16_t padding
+ */
+struct asm_subband_drc_config_params {
+ int16_t drc_stereo_linked_flag;
+/*< Specifies whether all stereo channels have the same applied
+ * dynamics (1) or if they process their dynamics independently (0).
+ * Supported values:
+ * - 0 -- Not linked
+ * - 1 -- Linked
+ */
+
+ int16_t drc_mode;
+/*< Specifies whether DRC mode is bypassed for sub-bands.
+ * Supported values:
+ * - 0 -- Disabled
+ * - 1 -- Enabled
+ */
+
+ int16_t drc_down_sample_level;
+/*< DRC down sample level.
+ * Supported values: @ge 1
+ */
+
+ int16_t drc_delay;
+/*< DRC delay in samples.
+ * Supported values: 0 to 1200
+ */
+
+ uint16_t drc_rmsime_avg_const;
+/*< RMS signal energy time-averaging constant.
+ * Supported values: 0 to 2^16-1
+ */
+
+ uint16_t drc_makeup_gain;
+/*< DRC makeup gain in decibels.
+ * Supported values: 258 to 64917
+ */
+ /* Down expander settings */
+ int16_t down_expdrhreshold;
+/*< Down expander threshold.
+ * Supported Q7 format values: 1320 to up_cmpsrhreshold
+ */
+
+ int16_t down_expdr_slope;
+/*< Down expander slope.
+ * Supported Q8 format values: -32768 to 0.
+ */
+
+ uint32_t down_expdr_attack;
+/*< Down expander attack constant.
+ * Supported Q31 format values: 196844 to 2^31.
+ */
+
+ uint32_t down_expdr_release;
+/*< Down expander release constant.
+ * Supported Q31 format values: 19685 to 2^31
+ */
+
+ uint16_t down_expdr_hysteresis;
+/*< Down expander hysteresis constant.
+ * Supported Q14 format values: 1 to 32690
+ */
+
+ uint16_t reserved;
+ /*< Clients must set this field to zero. */
+
+ int32_t down_expdr_min_gain_db;
+/*< Down expander minimum gain.
+ * Supported Q23 format values: -805306368 to 0.
+ */
+
+ /* Up compressor settings */
+
+ int16_t up_cmpsrhreshold;
+/*< Up compressor threshold.
+ * Supported Q7 format values: down_expdrhreshold to
+ * down_cmpsrhreshold.
+ */
+
+ uint16_t up_cmpsr_slope;
+/*< Up compressor slope.
+ * Supported Q16 format values: 0 to 64881.
+ */
+
+ uint32_t up_cmpsr_attack;
+/*< Up compressor attack constant.
+ * Supported Q31 format values: 196844 to 2^31.
+ */
+
+ uint32_t up_cmpsr_release;
+/*< Up compressor release constant.
+ * Supported Q31 format values: 19685 to 2^31.
+ */
+
+ uint16_t up_cmpsr_hysteresis;
+/*< Up compressor hysteresis constant.
+ * Supported Q14 format values: 1 to 32690.
+ */
+
+ /* Down compressor settings */
+
+ int16_t down_cmpsrhreshold;
+/*< Down compressor threshold.
+ * Supported Q7 format values: up_cmpsrhreshold to 11560.
+ */
+
+ uint16_t down_cmpsr_slope;
+/*< Down compressor slope.
+ * Supported Q16 format values: 0 to 64881.
+ */
+
+ uint16_t reserved1;
+/*< Clients must set this field to zero. */
+
+ uint32_t down_cmpsr_attack;
+/*< Down compressor attack constant.
+ * Supported Q31 format values: 196844 to 2^31.
+ */
+
+ uint32_t down_cmpsr_release;
+/*< Down compressor release constant.
+ * Supported Q31 format values: 19685 to 2^31.
+ */
+
+ uint16_t down_cmpsr_hysteresis;
+/*< Down compressor hysteresis constant.
+ * Supported Q14 values: 1 to 32690.
+ */
+
+ uint16_t reserved2;
+/*< Clients must set this field to zero.*/
+} __packed;
+
+#define ASM_MODULE_ID_EQUALIZER 0x00010C27
+#define ASM_PARAM_ID_EQUALIZER_PARAMETERS 0x00010C28
+
+#define ASM_MAX_EQ_BANDS 12
+
+struct asm_eq_per_band_params {
+ uint32_t band_idx;
+/*< Band index.
+ * Supported values: 0 to 11
+ */
+
+ uint32_t filterype;
+/*< Type of filter.
+ * Supported values:
+ * - #ASM_PARAM_EQYPE_NONE
+ * - #ASM_PARAM_EQ_BASS_BOOST
+ * - #ASM_PARAM_EQ_BASS_CUT
+ * - #ASM_PARAM_EQREBLE_BOOST
+ * - #ASM_PARAM_EQREBLE_CUT
+ * - #ASM_PARAM_EQ_BAND_BOOST
+ * - #ASM_PARAM_EQ_BAND_CUT
+ */
+
+ uint32_t center_freq_hz;
+ /*< Filter band center frequency in Hertz. */
+
+ int32_t filter_gain;
+/*< Filter band initial gain.
+ * Supported values: +12 to -12 dB in 1 dB increments
+ */
+
+ int32_t q_factor;
+/*< Filter band quality factor expressed as a Q8 number, i.e., a
+ * fixed-point number with q factor of 8. For example, 3000/(2^8).
+ */
+} __packed;
+
+struct asm_eq_params {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ uint32_t enable_flag;
+/*< Specifies whether the equalizer module is disabled (0) or enabled
+ * (nonzero).
+ */
+
+ uint32_t num_bands;
+/*< Number of bands.
+ * Supported values: 1 to 12
+ */
+ struct asm_eq_per_band_params eq_bands[ASM_MAX_EQ_BANDS];
+
+} __packed;
+
+/* No equalizer effect.*/
+#define ASM_PARAM_EQYPE_NONE 0
+
+/* Bass boost equalizer effect.*/
+#define ASM_PARAM_EQ_BASS_BOOST 1
+
+/*Bass cut equalizer effect.*/
+#define ASM_PARAM_EQ_BASS_CUT 2
+
+/* Treble boost equalizer effect */
+#define ASM_PARAM_EQREBLE_BOOST 3
+
+/* Treble cut equalizer effect.*/
+#define ASM_PARAM_EQREBLE_CUT 4
+
+/* Band boost equalizer effect.*/
+#define ASM_PARAM_EQ_BAND_BOOST 5
+
+/* Band cut equalizer effect.*/
+#define ASM_PARAM_EQ_BAND_CUT 6
+
+/* Voice get & set params */
+#define VOICE_CMD_SET_PARAM 0x0001133D
+#define VOICE_CMD_GET_PARAM 0x0001133E
+#define VOICE_EVT_GET_PARAM_ACK 0x00011008
+
+
+/* ID of the Bass Boost module.
+ * This module supports the following parameter IDs:
+ * - #AUDPROC_PARAM_ID_BASS_BOOST_ENABLE
+ * - #AUDPROC_PARAM_ID_BASS_BOOST_MODE
+ * - #AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH
+ */
+#define AUDPROC_MODULE_ID_BASS_BOOST 0x000108A1
+/* ID of the Bass Boost enable parameter used by
+ * AUDPROC_MODULE_ID_BASS_BOOST.
+ */
+#define AUDPROC_PARAM_ID_BASS_BOOST_ENABLE 0x000108A2
+/* ID of the Bass Boost mode parameter used by
+ * AUDPROC_MODULE_ID_BASS_BOOST.
+ */
+#define AUDPROC_PARAM_ID_BASS_BOOST_MODE 0x000108A3
+/* ID of the Bass Boost strength parameter used by
+ * AUDPROC_MODULE_ID_BASS_BOOST.
+ */
+#define AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH 0x000108A4
+
+/* ID of the PBE module.
+ * This module supports the following parameter IDs:
+ * - #AUDPROC_PARAM_ID_PBE_ENABLE
+ * - #AUDPROC_PARAM_ID_PBE_PARAM_CONFIG
+ */
+#define AUDPROC_MODULE_ID_PBE 0x00010C2A
+/* ID of the Bass Boost enable parameter used by
+ * AUDPROC_MODULE_ID_BASS_BOOST.
+ */
+#define AUDPROC_PARAM_ID_PBE_ENABLE 0x00010C2B
+/* ID of the Bass Boost mode parameter used by
+ * AUDPROC_MODULE_ID_BASS_BOOST.
+ */
+#define AUDPROC_PARAM_ID_PBE_PARAM_CONFIG 0x00010C49
+
+/* ID of the Virtualizer module. This module supports the
+ * following parameter IDs:
+ * - #AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE
+ * - #AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH
+ * - #AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE
+ * - #AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST
+ */
+#define AUDPROC_MODULE_ID_VIRTUALIZER 0x000108A5
+/* ID of the Virtualizer enable parameter used by
+ * AUDPROC_MODULE_ID_VIRTUALIZER.
+ */
+#define AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE 0x000108A6
+/* ID of the Virtualizer strength parameter used by
+ * AUDPROC_MODULE_ID_VIRTUALIZER.
+ */
+#define AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH 0x000108A7
+/* ID of the Virtualizer out type parameter used by
+ * AUDPROC_MODULE_ID_VIRTUALIZER.
+ */
+#define AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE 0x000108A8
+/* ID of the Virtualizer out type parameter used by
+ * AUDPROC_MODULE_ID_VIRTUALIZER.
+ */
+#define AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST 0x000108A9
+
+/* ID of the Reverb module. This module supports the following
+ * parameter IDs:
+ * - #AUDPROC_PARAM_ID_REVERB_ENABLE
+ * - #AUDPROC_PARAM_ID_REVERB_MODE
+ * - #AUDPROC_PARAM_ID_REVERB_PRESET
+ * - #AUDPROC_PARAM_ID_REVERB_WET_MIX
+ * - #AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST
+ * - #AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL
+ * - #AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL
+ * - #AUDPROC_PARAM_ID_REVERB_DECAY_TIME
+ * - #AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO
+ * - #AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL
+ * - #AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY
+ * - #AUDPROC_PARAM_ID_REVERB_LEVEL
+ * - #AUDPROC_PARAM_ID_REVERB_DELAY
+ * - #AUDPROC_PARAM_ID_REVERB_DIFFUSION
+ * - #AUDPROC_PARAM_ID_REVERB_DENSITY
+ */
+#define AUDPROC_MODULE_ID_REVERB 0x000108AA
+/* ID of the Reverb enable parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_ENABLE 0x000108AB
+/* ID of the Reverb mode parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_MODE 0x000108AC
+/* ID of the Reverb preset parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_PRESET 0x000108AD
+/* ID of the Reverb wet mix parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_WET_MIX 0x000108AE
+/* ID of the Reverb gain adjust parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST 0x000108AF
+/* ID of the Reverb room level parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL 0x000108B0
+/* ID of the Reverb room hf level parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL 0x000108B1
+/* ID of the Reverb decay time parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_DECAY_TIME 0x000108B2
+/* ID of the Reverb decay hf ratio parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO 0x000108B3
+/* ID of the Reverb reflections level parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL 0x000108B4
+/* ID of the Reverb reflections delay parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY 0x000108B5
+/* ID of the Reverb level parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_LEVEL 0x000108B6
+/* ID of the Reverb delay parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_DELAY 0x000108B7
+/* ID of the Reverb diffusion parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_DIFFUSION 0x000108B8
+/* ID of the Reverb density parameter used by
+ * AUDPROC_MODULE_ID_REVERB.
+ */
+#define AUDPROC_PARAM_ID_REVERB_DENSITY 0x000108B9
+
+/* ID of the Popless Equalizer module. This module supports the
+ * following parameter IDs:
+ * - #AUDPROC_PARAM_ID_EQ_ENABLE
+ * - #AUDPROC_PARAM_ID_EQ_CONFIG
+ * - #AUDPROC_PARAM_ID_EQ_NUM_BANDS
+ * - #AUDPROC_PARAM_ID_EQ_BAND_LEVELS
+ * - #AUDPROC_PARAM_ID_EQ_BAND_LEVEL_RANGE
+ * - #AUDPROC_PARAM_ID_EQ_BAND_FREQS
+ * - #AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ_RANGE
+ * - #AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ
+ * - #AUDPROC_PARAM_ID_EQ_BAND_INDEX
+ * - #AUDPROC_PARAM_ID_EQ_PRESET_ID
+ * - #AUDPROC_PARAM_ID_EQ_NUM_PRESETS
+ * - #AUDPROC_PARAM_ID_EQ_GET_PRESET_NAME
+ */
+#define AUDPROC_MODULE_ID_POPLESS_EQUALIZER 0x000108BA
+/* ID of the Popless Equalizer enable parameter used by
+ * AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+ */
+#define AUDPROC_PARAM_ID_EQ_ENABLE 0x000108BB
+/* ID of the Popless Equalizer config parameter used by
+ * AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+ */
+#define AUDPROC_PARAM_ID_EQ_CONFIG 0x000108BC
+/* ID of the Popless Equalizer number of bands parameter used
+ * by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+ * used for get param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_NUM_BANDS 0x000108BD
+/* ID of the Popless Equalizer band levels parameter used by
+ * AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+ * used for get param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_BAND_LEVELS 0x000108BE
+/* ID of the Popless Equalizer band level range parameter used
+ * by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+ * used for get param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_BAND_LEVEL_RANGE 0x000108BF
+/* ID of the Popless Equalizer band frequencies parameter used
+ * by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+ * used for get param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_BAND_FREQS 0x000108C0
+/* ID of the Popless Equalizer single band frequency range
+ * parameter used by AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+ * This param ID is used for get param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ_RANGE 0x000108C1
+/* ID of the Popless Equalizer single band frequency parameter
+ * used by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID
+ * is used for set param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ 0x000108C2
+/* ID of the Popless Equalizer band index parameter used by
+ * AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+ */
+#define AUDPROC_PARAM_ID_EQ_BAND_INDEX 0x000108C3
+/* ID of the Popless Equalizer preset id parameter used by
+ * AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+ * for get param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_PRESET_ID 0x000108C4
+/* ID of the Popless Equalizer number of presets parameter used
+ * by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+ * for get param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_NUM_PRESETS 0x000108C5
+/* ID of the Popless Equalizer preset name parameter used by
+ * AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+ * for get param only.
+ */
+#define AUDPROC_PARAM_ID_EQ_PRESET_NAME 0x000108C6
+
+/* Set Q6 topologies */
+#define ASM_CMD_ADD_TOPOLOGIES 0x00010DBE
+#define ADM_CMD_ADD_TOPOLOGIES 0x00010335
+#define AFE_CMD_ADD_TOPOLOGIES 0x000100f8
+/* structure used for both ioctls */
+struct cmd_set_topologies {
+ struct apr_hdr hdr;
+ u32 payload_addr_lsw;
+ /* LSW of parameter data payload address.*/
+ u32 payload_addr_msw;
+ /* MSW of parameter data payload address.*/
+ u32 mem_map_handle;
+ /* Memory map handle returned by mem map command */
+ u32 payload_size;
+ /* Size in bytes of the variable payload in shared memory */
+} __packed;
+
+/* This module represents the Rx processing of Feedback speaker protection.
+ * It contains the excursion control, thermal protection,
+ * analog clip manager features in it.
+ * This module id will support following param ids.
+ * - AFE_PARAM_ID_FBSP_MODE_RX_CFG
+ */
+
+#define AFE_MODULE_FB_SPKR_PROT_RX 0x0001021C
+#define AFE_MODULE_FB_SPKR_PROT_V2_RX 0x0001025F
+
+#define AFE_PARAM_ID_FBSP_MODE_RX_CFG 0x0001021D
+#define AFE_PARAM_ID_FBSP_PTONE_RAMP_CFG 0x00010260
+
+struct asm_fbsp_mode_rx_cfg {
+ uint32_t minor_version;
+ uint32_t mode;
+} __packed;
+
+/* This module represents the VI processing of feedback speaker protection.
+ * It will receive Vsens and Isens from codec and generates necessary
+ * parameters needed by Rx processing.
+ * This module id will support following param ids.
+ * - AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG
+ * - AFE_PARAM_ID_CALIB_RES_CFG
+ * - AFE_PARAM_ID_FEEDBACK_PATH_CFG
+ */
+
+#define AFE_MODULE_FB_SPKR_PROT_VI_PROC 0x00010226
+#define AFE_MODULE_FB_SPKR_PROT_VI_PROC_V2 0x0001026A
+
+#define AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG 0x0001022A
+#define AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2 0x0001026B
+
+struct asm_spkr_calib_vi_proc_cfg {
+ uint32_t minor_version;
+ uint32_t operation_mode;
+ uint32_t r0_t0_selection_flag[SP_V2_NUM_MAX_SPKR];
+ int32_t r0_cali_q24[SP_V2_NUM_MAX_SPKR];
+ int16_t t0_cali_q6[SP_V2_NUM_MAX_SPKR];
+ uint32_t quick_calib_flag;
+} __packed;
+
+#define AFE_PARAM_ID_CALIB_RES_CFG 0x0001022B
+#define AFE_PARAM_ID_CALIB_RES_CFG_V2 0x0001026E
+
+struct asm_calib_res_cfg {
+ uint32_t minor_version;
+ int32_t r0_cali_q24[SP_V2_NUM_MAX_SPKR];
+ uint32_t th_vi_ca_state;
+} __packed;
+
+#define AFE_PARAM_ID_FEEDBACK_PATH_CFG 0x0001022C
+#define AFE_MODULE_FEEDBACK 0x00010257
+
+struct asm_feedback_path_cfg {
+ uint32_t minor_version;
+ int32_t dst_portid;
+ int32_t num_channels;
+ int32_t chan_info[4];
+} __packed;
+
+#define AFE_PARAM_ID_MODE_VI_PROC_CFG 0x00010227
+
+struct asm_mode_vi_proc_cfg {
+ uint32_t minor_version;
+ uint32_t cal_mode;
+} __packed;
+
+#define AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI 0x0001026A
+#define AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG 0x0001026B
+#define AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG 0x0001029F
+#define AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS 0x000102A0
+
+struct afe_sp_th_vi_mode_cfg {
+ uint32_t minor_version;
+ uint32_t operation_mode;
+ /*
+ * Operation mode of thermal VI module.
+ * 0 -- Normal Running mode
+ * 1 -- Calibration mode
+ * 2 -- FTM mode
+ */
+ uint32_t r0t0_selection_flag[SP_V2_NUM_MAX_SPKR];
+ /*
+ * Specifies which set of R0, T0 values the algorithm will use.
+ * This field is valid only in Normal mode (operation_mode = 0).
+ * 0 -- Use calibrated R0, T0 value
+ * 1 -- Use safe R0, T0 value
+ */
+ int32_t r0_cali_q24[SP_V2_NUM_MAX_SPKR];
+ /*
+ * Calibration point resistance per device. This field is valid
+ * only in Normal mode (operation_mode = 0).
+ * values 33554432 to 1073741824 Ohms (in Q24 format)
+ */
+ int16_t t0_cali_q6[SP_V2_NUM_MAX_SPKR];
+ /*
+ * Calibration point temperature per device. This field is valid
+ * in both Normal mode and Calibration mode.
+ * values -1920 to 5120 degrees C (in Q6 format)
+ */
+ uint32_t quick_calib_flag;
+ /*
+ * Indicates whether calibration is to be done in quick mode or not.
+ * This field is valid only in Calibration mode (operation_mode = 1).
+ * 0 -- Disabled
+ * 1 -- Enabled
+ */
+} __packed;
+
+struct afe_sp_th_vi_ftm_cfg {
+ uint32_t minor_version;
+ uint32_t wait_time_ms[SP_V2_NUM_MAX_SPKR];
+ /*
+ * Wait time to heat up speaker before collecting statistics
+ * for ftm mode in ms.
+ * values 0 to 4294967295 ms
+ */
+ uint32_t ftm_time_ms[SP_V2_NUM_MAX_SPKR];
+ /*
+ * duration for which FTM statistics are collected in ms.
+ * values 0 to 2000 ms
+ */
+} __packed;
+
+struct afe_sp_th_vi_ftm_params {
+ uint32_t minor_version;
+ int32_t dc_res_q24[SP_V2_NUM_MAX_SPKR];
+ /*
+ * DC resistance value in q24 format
+ * values 0 to 2147483647 Ohms (in Q24 format)
+ */
+ int32_t temp_q22[SP_V2_NUM_MAX_SPKR];
+ /*
+ * temperature value in q22 format
+ * values -125829120 to 2147483647 degC (in Q22 format)
+ */
+ uint32_t status[SP_V2_NUM_MAX_SPKR];
+ /*
+ * FTM packet status
+ * 0 - Incorrect operation mode.This status is returned
+ * when GET_PARAM is called in non FTM Mode
+ * 1 - Inactive mode -- Port is not yet started.
+ * 2 - Wait state. wait_time_ms has not yet elapsed
+ * 3 - In progress state. ftm_time_ms has not yet elapsed.
+ * 4 - Success.
+ * 5 - Failed.
+ */
+} __packed;
+
+struct afe_sp_th_vi_get_param {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_get_param_v2 get_param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_sp_th_vi_ftm_params param;
+} __packed;
+
+struct afe_sp_th_vi_get_param_resp {
+ uint32_t status;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_sp_th_vi_ftm_params param;
+} __packed;
+
+
+#define AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI 0x0001026F
+#define AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG 0x000102A1
+#define AFE_PARAM_ID_SP_V2_EX_VI_FTM_CFG 0x000102A2
+#define AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS 0x000102A3
+
+struct afe_sp_ex_vi_mode_cfg {
+ uint32_t minor_version;
+ uint32_t operation_mode;
+ /*
+ * Operation mode of Excursion VI module.
+ * 0 - Normal Running mode
+ * 2 - FTM mode
+ */
+} __packed;
+
+struct afe_sp_ex_vi_ftm_cfg {
+ uint32_t minor_version;
+ uint32_t wait_time_ms[SP_V2_NUM_MAX_SPKR];
+ /*
+ * Wait time to heat up speaker before collecting statistics
+ * for ftm mode in ms.
+ * values 0 to 4294967295 ms
+ */
+ uint32_t ftm_time_ms[SP_V2_NUM_MAX_SPKR];
+ /*
+ * duration for which FTM statistics are collected in ms.
+ * values 0 to 2000 ms
+ */
+} __packed;
+
+struct afe_sp_ex_vi_ftm_params {
+ uint32_t minor_version;
+ int32_t freq_q20[SP_V2_NUM_MAX_SPKR];
+ /*
+ * Resonance frequency in q20 format
+ * values 0 to 2147483647 Hz (in Q20 format)
+ */
+ int32_t resis_q24[SP_V2_NUM_MAX_SPKR];
+ /*
+ * Mechanical resistance in q24 format
+ * values 0 to 2147483647 Ohms (in Q24 format)
+ */
+ int32_t qmct_q24[SP_V2_NUM_MAX_SPKR];
+ /*
+ * Mechanical Qfactor in q24 format
+ * values 0 to 2147483647 (in Q24 format)
+ */
+ uint32_t status[SP_V2_NUM_MAX_SPKR];
+ /*
+ * FTM packet status
+ * 0 - Incorrect operation mode.This status is returned
+ * when GET_PARAM is called in non FTM Mode.
+ * 1 - Inactive mode -- Port is not yet started.
+ * 2 - Wait state. wait_time_ms has not yet elapsed
+ * 3 - In progress state. ftm_time_ms has not yet elapsed.
+ * 4 - Success.
+ * 5 - Failed.
+ */
+} __packed;
+
+struct afe_sp_ex_vi_get_param {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_get_param_v2 get_param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_sp_ex_vi_ftm_params param;
+} __packed;
+
+struct afe_sp_ex_vi_get_param_resp {
+ uint32_t status;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_sp_ex_vi_ftm_params param;
+} __packed;
+
+union afe_spkr_prot_config {
+ struct asm_fbsp_mode_rx_cfg mode_rx_cfg;
+ struct asm_spkr_calib_vi_proc_cfg vi_proc_cfg;
+ struct asm_feedback_path_cfg feedback_path_cfg;
+ struct asm_mode_vi_proc_cfg mode_vi_proc_cfg;
+ struct afe_sp_th_vi_mode_cfg th_vi_mode_cfg;
+ struct afe_sp_th_vi_ftm_cfg th_vi_ftm_cfg;
+ struct afe_sp_ex_vi_mode_cfg ex_vi_mode_cfg;
+ struct afe_sp_ex_vi_ftm_cfg ex_vi_ftm_cfg;
+} __packed;
+
+struct afe_spkr_prot_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ union afe_spkr_prot_config prot_config;
+} __packed;
+
+struct afe_spkr_prot_get_vi_calib {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_get_param_v2 get_param;
+ struct afe_port_param_data_v2 pdata;
+ struct asm_calib_res_cfg res_cfg;
+} __packed;
+
+struct afe_spkr_prot_calib_get_resp {
+ uint32_t status;
+ struct afe_port_param_data_v2 pdata;
+ struct asm_calib_res_cfg res_cfg;
+} __packed;
+
+
+/* SRS TRUMEDIA start */
+/* topology */
+#define SRS_TRUMEDIA_TOPOLOGY_ID 0x00010D90
+/* module */
+#define SRS_TRUMEDIA_MODULE_ID 0x10005010
+/* parameters */
+#define SRS_TRUMEDIA_PARAMS 0x10005011
+#define SRS_TRUMEDIA_PARAMS_WOWHD 0x10005012
+#define SRS_TRUMEDIA_PARAMS_CSHP 0x10005013
+#define SRS_TRUMEDIA_PARAMS_HPF 0x10005014
+#define SRS_TRUMEDIA_PARAMS_AEQ 0x10005015
+#define SRS_TRUMEDIA_PARAMS_HL 0x10005016
+#define SRS_TRUMEDIA_PARAMS_GEQ 0x10005017
+
+#define SRS_ID_GLOBAL 0x00000001
+#define SRS_ID_WOWHD 0x00000002
+#define SRS_ID_CSHP 0x00000003
+#define SRS_ID_HPF 0x00000004
+#define SRS_ID_AEQ 0x00000005
+#define SRS_ID_HL 0x00000006
+#define SRS_ID_GEQ 0x00000007
+
+#define SRS_CMD_UPLOAD 0x7FFF0000
+#define SRS_PARAM_OFFSET_MASK 0x3FFF0000
+#define SRS_PARAM_VALUE_MASK 0x0000FFFF
+
+struct srs_trumedia_params_GLOBAL {
+ uint8_t v1;
+ uint8_t v2;
+ uint8_t v3;
+ uint8_t v4;
+ uint8_t v5;
+ uint8_t v6;
+ uint8_t v7;
+ uint8_t v8;
+ uint16_t v9;
+} __packed;
+
+struct srs_trumedia_params_WOWHD {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v5;
+ uint16_t v6;
+ uint16_t v7;
+ uint16_t v8;
+ uint16_t v____A1;
+ uint32_t v9;
+ uint16_t v10;
+ uint16_t v11;
+ uint32_t v12[16];
+ uint32_t v13[16];
+ uint32_t v14[16];
+ uint32_t v15[16];
+ uint32_t v16;
+ uint16_t v17;
+ uint16_t v18;
+} __packed;
+
+struct srs_trumedia_params_CSHP {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v5;
+ uint16_t v6;
+ uint16_t v____A1;
+ uint32_t v7;
+ uint16_t v8;
+ uint16_t v9;
+ uint32_t v10[16];
+} __packed;
+
+struct srs_trumedia_params_HPF {
+ uint32_t v1;
+ uint32_t v2[26];
+} __packed;
+
+struct srs_trumedia_params_AEQ {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v____A1;
+ uint32_t v5[74];
+ uint32_t v6[74];
+ uint16_t v7[2048];
+} __packed;
+
+struct srs_trumedia_params_HL {
+ uint16_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v____A1;
+ int32_t v4;
+ uint32_t v5;
+ uint16_t v6;
+ uint16_t v____A2;
+ uint32_t v7;
+} __packed;
+
+struct srs_trumedia_params_GEQ {
+ int16_t v1[10];
+} __packed;
+struct srs_trumedia_params {
+ struct srs_trumedia_params_GLOBAL global;
+ struct srs_trumedia_params_WOWHD wowhd;
+ struct srs_trumedia_params_CSHP cshp;
+ struct srs_trumedia_params_HPF hpf;
+ struct srs_trumedia_params_AEQ aeq;
+ struct srs_trumedia_params_HL hl;
+ struct srs_trumedia_params_GEQ geq;
+} __packed;
+/* SRS TruMedia end */
+
+#define AUDPROC_PARAM_ID_ENABLE 0x00010904
+#define ASM_STREAM_POSTPROC_TOPO_ID_SA_PLUS 0x1000FFFF
+/* DTS Eagle */
+#define AUDPROC_MODULE_ID_DTS_HPX_PREMIX 0x0001077C
+#define AUDPROC_MODULE_ID_DTS_HPX_POSTMIX 0x0001077B
+#define ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX 0x00010DED
+#define ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS 0x10015000
+#define ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER 0x10015001
+struct asm_dts_eagle_param {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+} __packed;
+
+struct asm_dts_eagle_param_get {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_get_pp_params_v2 param;
+} __packed;
+
+/* LSM Specific */
+#define VW_FEAT_DIM (39)
+
+#define APRV2_IDS_SERVICE_ID_ADSP_LSM_V (0xD)
+#define APRV2_IDS_DOMAIN_ID_ADSP_V (0x4)
+#define APRV2_IDS_DOMAIN_ID_APPS_V (0x5)
+
+#define LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS (0x00012A7F)
+#define LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS (0x00012A80)
+#define LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS (0x00012A81)
+#define LSM_SESSION_CMD_OPEN_TX (0x00012A82)
+#define LSM_SESSION_CMD_CLOSE_TX (0x00012A88)
+#define LSM_SESSION_CMD_SET_PARAMS (0x00012A83)
+#define LSM_SESSION_CMD_SET_PARAMS_V2 (0x00012A8F)
+#define LSM_SESSION_CMD_REGISTER_SOUND_MODEL (0x00012A84)
+#define LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL (0x00012A85)
+#define LSM_SESSION_CMD_START (0x00012A86)
+#define LSM_SESSION_CMD_STOP (0x00012A87)
+#define LSM_SESSION_CMD_EOB (0x00012A89)
+#define LSM_SESSION_CMD_READ (0x00012A8A)
+#define LSM_SESSION_CMD_OPEN_TX_V2 (0x00012A8B)
+#define LSM_CMD_ADD_TOPOLOGIES (0x00012A8C)
+
+#define LSM_SESSION_EVENT_DETECTION_STATUS (0x00012B00)
+#define LSM_SESSION_EVENT_DETECTION_STATUS_V2 (0x00012B01)
+#define LSM_DATA_EVENT_READ_DONE (0x00012B02)
+#define LSM_DATA_EVENT_STATUS (0x00012B03)
+
+#define LSM_MODULE_ID_VOICE_WAKEUP (0x00012C00)
+#define LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD (0x00012C01)
+#define LSM_PARAM_ID_OPERATION_MODE (0x00012C02)
+#define LSM_PARAM_ID_GAIN (0x00012C03)
+#define LSM_PARAM_ID_CONNECT_TO_PORT (0x00012C04)
+#define LSM_PARAM_ID_FEATURE_COMPENSATION_DATA (0x00012C07)
+#define LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS (0x00012C07)
+#define LSM_MODULE_ID_LAB (0x00012C08)
+#define LSM_PARAM_ID_LAB_ENABLE (0x00012C09)
+#define LSM_PARAM_ID_LAB_CONFIG (0x00012C0A)
+#define LSM_MODULE_ID_FRAMEWORK (0x00012C0E)
+
+/* HW MAD specific */
+#define AFE_MODULE_HW_MAD (0x00010230)
+#define AFE_PARAM_ID_HW_MAD_CFG (0x00010231)
+#define AFE_PARAM_ID_HW_MAD_CTRL (0x00010232)
+#define AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG (0x00010233)
+
+/* SW MAD specific */
+#define AFE_MODULE_SW_MAD (0x0001022D)
+#define AFE_PARAM_ID_SW_MAD_CFG (0x0001022E)
+#define AFE_PARAM_ID_SVM_MODEL (0x0001022F)
+
+/* Commands/Params to pass the codec/slimbus data to DSP */
+#define AFE_SVC_CMD_SET_PARAM (0x000100f3)
+#define AFE_MODULE_CDC_DEV_CFG (0x00010234)
+#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG (0x00010235)
+#define AFE_PARAM_ID_CDC_REG_CFG (0x00010236)
+#define AFE_PARAM_ID_CDC_REG_CFG_INIT (0x00010237)
+#define AFE_PARAM_ID_CDC_REG_PAGE_CFG (0x00010296)
+
+#define AFE_MAX_CDC_REGISTERS_TO_CONFIG (20)
+
+/* AANC Port Config Specific */
+#define AFE_PARAM_ID_AANC_PORT_CONFIG (0x00010215)
+#define AFE_API_VERSION_AANC_PORT_CONFIG (0x1)
+#define AANC_TX_MIC_UNUSED (0)
+#define AANC_TX_VOICE_MIC (1)
+#define AANC_TX_ERROR_MIC (2)
+#define AANC_TX_NOISE_MIC (3)
+#define AFE_PORT_MAX_CHANNEL_CNT (8)
+#define AFE_MODULE_AANC (0x00010214)
+#define AFE_PARAM_ID_CDC_AANC_VERSION (0x0001023A)
+#define AFE_API_VERSION_CDC_AANC_VERSION (0x1)
+#define AANC_HW_BLOCK_VERSION_1 (1)
+#define AANC_HW_BLOCK_VERSION_2 (2)
+
+/*Clip bank selection*/
+#define AFE_API_VERSION_CLIP_BANK_SEL_CFG 0x1
+#define AFE_CLIP_MAX_BANKS 4
+#define AFE_PARAM_ID_CLIP_BANK_SEL_CFG 0x00010242
+
+struct afe_param_aanc_port_cfg {
+ /* Minor version used for tracking the version of the module's
+ * source port configuration.
+ */
+ uint32_t aanc_port_cfg_minor_version;
+
+ /* Sampling rate of the source Tx port. 8k - 192k*/
+ uint32_t tx_port_sample_rate;
+
+ /* Channel mapping for the Tx port signal carrying Noise (X),
+ * Error (E), and Voice (V) signals.
+ */
+ uint8_t tx_port_channel_map[AFE_PORT_MAX_CHANNEL_CNT];
+
+ /* Number of channels on the source Tx port. */
+ uint16_t tx_port_num_channels;
+
+ /* Port ID of the Rx path reference signal. */
+ uint16_t rx_path_ref_port_id;
+
+ /* Sampling rate of the reference port. 8k - 192k*/
+ uint32_t ref_port_sample_rate;
+} __packed;
+
+struct afe_param_id_cdc_aanc_version {
+ /* Minor version used for tracking the version of the module's
+ * hw version
+ */
+ uint32_t cdc_aanc_minor_version;
+
+ /* HW version. */
+ uint32_t aanc_hw_version;
+} __packed;
+
+struct afe_param_id_clip_bank_sel {
+ /* Minor version used for tracking the version of the module's
+ * hw version
+ */
+ uint32_t minor_version;
+
+ /* Number of banks to be read */
+ uint32_t num_banks;
+
+ uint32_t bank_map[AFE_CLIP_MAX_BANKS];
+} __packed;
+
+/* ERROR CODES */
+/* Success. The operation completed with no errors. */
+#define ADSP_EOK 0x00000000
+/* General failure. */
+#define ADSP_EFAILED 0x00000001
+/* Bad operation parameter. */
+#define ADSP_EBADPARAM 0x00000002
+/* Unsupported routine or operation. */
+#define ADSP_EUNSUPPORTED 0x00000003
+/* Unsupported version. */
+#define ADSP_EVERSION 0x00000004
+/* Unexpected problem encountered. */
+#define ADSP_EUNEXPECTED 0x00000005
+/* Unhandled problem occurred. */
+#define ADSP_EPANIC 0x00000006
+/* Unable to allocate resource. */
+#define ADSP_ENORESOURCE 0x00000007
+/* Invalid handle. */
+#define ADSP_EHANDLE 0x00000008
+/* Operation is already processed. */
+#define ADSP_EALREADY 0x00000009
+/* Operation is not ready to be processed. */
+#define ADSP_ENOTREADY 0x0000000A
+/* Operation is pending completion. */
+#define ADSP_EPENDING 0x0000000B
+/* Operation could not be accepted or processed. */
+#define ADSP_EBUSY 0x0000000C
+/* Operation aborted due to an error. */
+#define ADSP_EABORTED 0x0000000D
+/* Operation preempted by a higher priority. */
+#define ADSP_EPREEMPTED 0x0000000E
+/* Operation requests intervention to complete. */
+#define ADSP_ECONTINUE 0x0000000F
+/* Operation requests immediate intervention to complete. */
+#define ADSP_EIMMEDIATE 0x00000010
+/* Operation is not implemented. */
+#define ADSP_ENOTIMPL 0x00000011
+/* Operation needs more data or resources. */
+#define ADSP_ENEEDMORE 0x00000012
+/* Operation does not have memory. */
+#define ADSP_ENOMEMORY 0x00000014
+/* Item does not exist. */
+#define ADSP_ENOTEXIST 0x00000015
+/* Max count for adsp error code sent to HLOS*/
+#define ADSP_ERR_MAX (ADSP_ENOTEXIST + 1)
+/* Operation is finished. */
+#define ADSP_ETERMINATED 0x00011174
+
+/*bharath, adsp_error_codes.h */
+
+/* LPASS clock for I2S Interface */
+
+/* Supported OSR clock values */
+#define Q6AFE_LPASS_OSR_CLK_12_P288_MHZ 0xBB8000
+#define Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ 0xAC4400
+#define Q6AFE_LPASS_OSR_CLK_9_P600_MHZ 0x927C00
+#define Q6AFE_LPASS_OSR_CLK_8_P192_MHZ 0x7D0000
+#define Q6AFE_LPASS_OSR_CLK_6_P144_MHZ 0x5DC000
+#define Q6AFE_LPASS_OSR_CLK_4_P096_MHZ 0x3E8000
+#define Q6AFE_LPASS_OSR_CLK_3_P072_MHZ 0x2EE000
+#define Q6AFE_LPASS_OSR_CLK_2_P048_MHZ 0x1F4000
+#define Q6AFE_LPASS_OSR_CLK_1_P536_MHZ 0x177000
+#define Q6AFE_LPASS_OSR_CLK_1_P024_MHZ 0xFA000
+#define Q6AFE_LPASS_OSR_CLK_768_kHZ 0xBB800
+#define Q6AFE_LPASS_OSR_CLK_512_kHZ 0x7D000
+#define Q6AFE_LPASS_OSR_CLK_DISABLE 0x0
+
+/* Supported Bit clock values */
+#define Q6AFE_LPASS_IBIT_CLK_12_P288_MHZ 0xBB8000
+#define Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ 0xAC4400
+#define Q6AFE_LPASS_IBIT_CLK_8_P192_MHZ 0x7D0000
+#define Q6AFE_LPASS_IBIT_CLK_6_P144_MHZ 0x5DC000
+#define Q6AFE_LPASS_IBIT_CLK_4_P096_MHZ 0x3E8000
+#define Q6AFE_LPASS_IBIT_CLK_3_P072_MHZ 0x2EE000
+#define Q6AFE_LPASS_IBIT_CLK_2_P8224_MHZ 0x2b1100
+#define Q6AFE_LPASS_IBIT_CLK_2_P048_MHZ 0x1F4000
+#define Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ 0x177000
+#define Q6AFE_LPASS_IBIT_CLK_1_P4112_MHZ 0x158880
+#define Q6AFE_LPASS_IBIT_CLK_1_P024_MHZ 0xFA000
+#define Q6AFE_LPASS_IBIT_CLK_768_KHZ 0xBB800
+#define Q6AFE_LPASS_IBIT_CLK_512_KHZ 0x7D000
+#define Q6AFE_LPASS_IBIT_CLK_256_KHZ 0x3E800
+#define Q6AFE_LPASS_IBIT_CLK_DISABLE 0x0
+
+/* Supported LPASS CLK sources */
+#define Q6AFE_LPASS_CLK_SRC_EXTERNAL 0
+#define Q6AFE_LPASS_CLK_SRC_INTERNAL 1
+
+/* Supported LPASS CLK root*/
+#define Q6AFE_LPASS_CLK_ROOT_DEFAULT 0
+
+enum afe_lpass_clk_mode {
+ Q6AFE_LPASS_MODE_BOTH_INVALID,
+ Q6AFE_LPASS_MODE_CLK1_VALID,
+ Q6AFE_LPASS_MODE_CLK2_VALID,
+ Q6AFE_LPASS_MODE_BOTH_VALID,
+} __packed;
+
+/* Clock ID Enumeration Define. */
+/* Clock ID for Primary I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT 0x100
+/* Clock ID for Primary I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT 0x101
+/* Clock ID for Secondary I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT 0x102
+/* Clock ID for Secondary I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT 0x103
+/* Clock ID for Tertiary I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT 0x104
+/* Clock ID for Tertiary I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT 0x105
+/* Clock ID for Quartnery I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT 0x106
+/* Clock ID for Quartnery I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT 0x107
+/* Clock ID for Speaker I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_IBIT 0x108
+/* Clock ID for Speaker I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_EBIT 0x109
+/* Clock ID for Speaker I2S OSR */
+#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR 0x10A
+
+/* Clock ID for QUINARY I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT 0x10B
+/* Clock ID for QUINARY I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_EBIT 0x10C
+/* Clock ID for SENARY I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT 0x10D
+/* Clock ID for SENARY I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_SEN_MI2S_EBIT 0x10E
+/* Clock ID for INT0 I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT 0x10F
+/* Clock ID for INT1 I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_INT1_MI2S_IBIT 0x110
+/* Clock ID for INT2 I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_INT2_MI2S_IBIT 0x111
+/* Clock ID for INT3 I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT 0x112
+/* Clock ID for INT4 I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_INT4_MI2S_IBIT 0x113
+/* Clock ID for INT5 I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_INT5_MI2S_IBIT 0x114
+/* Clock ID for INT6 I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_INT6_MI2S_IBIT 0x115
+
+/* Clock ID for Primary PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT 0x200
+/* Clock ID for Primary PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_PCM_EBIT 0x201
+/* Clock ID for Secondary PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_PCM_IBIT 0x202
+/* Clock ID for Secondary PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_PCM_EBIT 0x203
+/* Clock ID for Tertiary PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_PCM_IBIT 0x204
+/* Clock ID for Tertiary PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_PCM_EBIT 0x205
+/* Clock ID for Quartery PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT 0x206
+/* Clock ID for Quartery PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_PCM_EBIT 0x207
+
+/** Clock ID for Primary TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT 0x200
+/** Clock ID for Primary TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT 0x201
+/** Clock ID for Secondary TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT 0x202
+/** Clock ID for Secondary TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT 0x203
+/** Clock ID for Tertiary TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT 0x204
+/** Clock ID for Tertiary TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT 0x205
+/** Clock ID for Quartery TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT 0x206
+/** Clock ID for Quartery TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT 0x207
+
+/* Clock ID for MCLK1 */
+#define Q6AFE_LPASS_CLK_ID_MCLK_1 0x300
+/* Clock ID for MCLK2 */
+#define Q6AFE_LPASS_CLK_ID_MCLK_2 0x301
+/* Clock ID for MCLK3 */
+#define Q6AFE_LPASS_CLK_ID_MCLK_3 0x302
+/* Clock ID for MCLK4 */
+#define Q6AFE_LPASS_CLK_ID_MCLK_4 0x304
+/* Clock ID for Internal Digital Codec Core */
+#define Q6AFE_LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 0x303
+/* Clock ID for INT MCLK0 */
+#define Q6AFE_LPASS_CLK_ID_INT_MCLK_0 0x305
+/* Clock ID for INT MCLK1 */
+#define Q6AFE_LPASS_CLK_ID_INT_MCLK_1 0x306
+/*
+ * Clock ID for soundwire NPL.
+ * This is the clock to be used to enable NPL clock for internal Soundwire.
+ */
+#define AFE_CLOCK_SET_CLOCK_ID_SWR_NPL_CLK 0x307
+
+/* Clock ID for AHB HDMI input */
+#define Q6AFE_LPASS_CLK_ID_AHB_HDMI_INPUT 0x400
+
+/* Clock ID for SPDIF core */
+#define Q6AFE_LPASS_CLK_ID_SPDIF_CORE 0x500
+
+
+/* Clock attribute for invalid use (reserved for internal usage) */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVALID 0x0
+/* Clock attribute for no couple case */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1
+/* Clock attribute for dividend couple case */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2
+/* Clock attribute for divisor couple case */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3
+/* Clock attribute for invert and no couple case */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO 0x4
+/* Clock set API version */
+#define Q6AFE_LPASS_CLK_CONFIG_API_VERSION 0x1
+
+struct afe_clk_set {
+ /*
+ * Minor version used for tracking clock set.
+ * @values #AFE_API_VERSION_CLOCK_SET
+ */
+ uint32_t clk_set_minor_version;
+
+ /*
+ * Clock ID
+ * @values
+ * - 0x100 to 0x10A - MSM8996
+ * - 0x200 to 0x207 - MSM8996
+ * - 0x300 to 0x302 - MSM8996 @tablebulletend
+ */
+ uint32_t clk_id;
+
+ /*
+ * Clock frequency (in Hertz) to be set.
+ * @values
+ * - >= 0 for clock frequency to set @tablebulletend
+ */
+ uint32_t clk_freq_in_hz;
+
+ /* Use to specific divider for two clocks if needed.
+ * Set to Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO for no divider
+ * relation clocks
+ * @values
+ * - #Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO
+ * - #Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND
+ * - #Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR @tablebulletend
+ */
+ uint16_t clk_attri;
+
+ /*
+ * Specifies the root clock source.
+ * Currently, only Q6AFE_LPASS_CLK_ROOT_DEFAULT is valid
+ * @values
+ * - 0 @tablebulletend
+ */
+ uint16_t clk_root;
+
+ /*
+ * for enable and disable clock.
+ * "clk_freq_in_hz", "clk_attri", and "clk_root"
+ * are ignored in disable clock case.
+ * @values
+ * - 0 -- Disabled
+ * - 1 -- Enabled @tablebulletend
+ */
+ uint32_t enable;
+};
+
+struct afe_clk_cfg {
+/* Minor version used for tracking the version of the I2S
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_I2S_CONFIG
+ */
+ u32 i2s_cfg_minor_version;
+
+/* clk value 1 in MHz. */
+ u32 clk_val1;
+
+/* clk value 2 in MHz. */
+ u32 clk_val2;
+
+/* clk_src
+ * #Q6AFE_LPASS_CLK_SRC_EXTERNAL
+ * #Q6AFE_LPASS_CLK_SRC_INTERNAL
+ */
+
+ u16 clk_src;
+
+/* clk_root -0 for default */
+ u16 clk_root;
+
+/* clk_set_mode
+ * #Q6AFE_LPASS_MODE_BOTH_INVALID
+ * #Q6AFE_LPASS_MODE_CLK1_VALID
+ * #Q6AFE_LPASS_MODE_CLK2_VALID
+ * #Q6AFE_LPASS_MODE_BOTH_VALID
+ */
+ u16 clk_set_mode;
+
+/* This param id is used to configure I2S clk */
+ u16 reserved;
+} __packed;
+
+/* This param id is used to configure I2S clk */
+#define AFE_PARAM_ID_LPAIF_CLK_CONFIG 0x00010238
+#define AFE_MODULE_CLOCK_SET 0x0001028F
+#define AFE_PARAM_ID_CLOCK_SET 0x00010290
+
+struct afe_lpass_clk_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_clk_cfg clk_cfg;
+} __packed;
+
+enum afe_lpass_digital_clk_src {
+ Q6AFE_LPASS_DIGITAL_ROOT_INVALID,
+ Q6AFE_LPASS_DIGITAL_ROOT_PRI_MI2S_OSR,
+ Q6AFE_LPASS_DIGITAL_ROOT_SEC_MI2S_OSR,
+ Q6AFE_LPASS_DIGITAL_ROOT_TER_MI2S_OSR,
+ Q6AFE_LPASS_DIGITAL_ROOT_QUAD_MI2S_OSR,
+ Q6AFE_LPASS_DIGITAL_ROOT_CDC_ROOT_CLK,
+} __packed;
+
+/* This param id is used to configure internal clk */
+#define AFE_PARAM_ID_INTERNAL_DIGIATL_CDC_CLK_CONFIG 0x00010239
+
+struct afe_digital_clk_cfg {
+/* Minor version used for tracking the version of the I2S
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_I2S_CONFIG
+ */
+ u32 i2s_cfg_minor_version;
+
+/* clk value in MHz. */
+ u32 clk_val;
+
+/* INVALID
+ * PRI_MI2S_OSR
+ * SEC_MI2S_OSR
+ * TER_MI2S_OSR
+ * QUAD_MI2S_OSR
+ * DIGT_CDC_ROOT
+ */
+ u16 clk_root;
+
+/* This field must be set to zero. */
+ u16 reserved;
+} __packed;
+
+
+struct afe_lpass_digital_clk_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_digital_clk_cfg clk_cfg;
+} __packed;
+
+/*
+ * Opcode for AFE to start DTMF.
+ */
+#define AFE_PORTS_CMD_DTMF_CTL 0x00010102
+
+/** DTMF payload.*/
+struct afe_dtmf_generation_command {
+ struct apr_hdr hdr;
+
+ /*
+ * Duration of the DTMF tone in ms.
+ * -1 -> continuous,
+ * 0 -> disable
+ */
+ int64_t duration_in_ms;
+
+ /*
+ * The DTMF high tone frequency.
+ */
+ uint16_t high_freq;
+
+ /*
+ * The DTMF low tone frequency.
+ */
+ uint16_t low_freq;
+
+ /*
+ * The DTMF volume setting
+ */
+ uint16_t gain;
+
+ /*
+ * The number of ports to enable/disable on.
+ */
+ uint16_t num_ports;
+
+ /*
+ * The Destination ports - array .
+ * For DTMF on multiple ports, portIds needs to
+ * be populated numPorts times.
+ */
+ uint16_t port_ids;
+
+ /*
+ * variable for 32 bit alignment of APR packet.
+ */
+ uint16_t reserved;
+} __packed;
+
+enum afe_config_type {
+ AFE_SLIMBUS_SLAVE_PORT_CONFIG,
+ AFE_SLIMBUS_SLAVE_CONFIG,
+ AFE_CDC_REGISTERS_CONFIG,
+ AFE_AANC_VERSION,
+ AFE_CDC_CLIP_REGISTERS_CONFIG,
+ AFE_CLIP_BANK_SEL,
+ AFE_CDC_REGISTER_PAGE_CONFIG,
+ AFE_MAX_CONFIG_TYPES,
+};
+
+struct afe_param_slimbus_slave_port_cfg {
+ uint32_t minor_version;
+ uint16_t slimbus_dev_id;
+ uint16_t slave_dev_pgd_la;
+ uint16_t slave_dev_intfdev_la;
+ uint16_t bit_width;
+ uint16_t data_format;
+ uint16_t num_channels;
+ uint16_t slave_port_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+} __packed;
+
+struct afe_param_cdc_slimbus_slave_cfg {
+ uint32_t minor_version;
+ uint32_t device_enum_addr_lsw;
+ uint32_t device_enum_addr_msw;
+ uint16_t tx_slave_port_offset;
+ uint16_t rx_slave_port_offset;
+} __packed;
+
+struct afe_param_cdc_reg_cfg {
+ uint32_t minor_version;
+ uint32_t reg_logical_addr;
+ uint32_t reg_field_type;
+ uint32_t reg_field_bit_mask;
+ uint16_t reg_bit_width;
+ uint16_t reg_offset_scale;
+} __packed;
+
+#define AFE_API_VERSION_CDC_REG_PAGE_CFG 1
+
+enum {
+ AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_0 = 0,
+ AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_1,
+ AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_2,
+ AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_3,
+};
+
+struct afe_param_cdc_reg_page_cfg {
+ uint32_t minor_version;
+ uint32_t enable;
+ uint32_t proc_id;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_data {
+ uint32_t num_registers;
+ struct afe_param_cdc_reg_cfg *reg_data;
+} __packed;
+
+struct afe_svc_cmd_set_param {
+ uint32_t payload_size;
+ uint32_t payload_address_lsw;
+ uint32_t payload_address_msw;
+ uint32_t mem_map_handle;
+} __packed;
+
+struct afe_svc_param_data {
+ uint32_t module_id;
+ uint32_t param_id;
+ uint16_t param_size;
+ uint16_t reserved;
+} __packed;
+
+struct afe_param_hw_mad_ctrl {
+ uint32_t minor_version;
+ uint16_t mad_type;
+ uint16_t mad_enable;
+} __packed;
+
+struct afe_cmd_hw_mad_ctrl {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_hw_mad_ctrl payload;
+} __packed;
+
+struct afe_cmd_hw_mad_slimbus_slave_port_cfg {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_slimbus_slave_port_cfg sb_port_cfg;
+} __packed;
+
+struct afe_cmd_sw_mad_enable {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_payload {
+ struct afe_svc_param_data common;
+ struct afe_param_cdc_reg_cfg reg_cfg;
+} __packed;
+
+struct afe_lpass_clk_config_command_v2 {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_svc_param_data pdata;
+ struct afe_clk_set clk_cfg;
+} __packed;
+
+/*
+ * reg_data's size can be up to AFE_MAX_CDC_REGISTERS_TO_CONFIG
+ */
+struct afe_svc_cmd_cdc_reg_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_param_cdc_reg_cfg_payload reg_data[0];
+} __packed;
+
+struct afe_svc_cmd_init_cdc_reg_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 init;
+} __packed;
+
+struct afe_svc_cmd_sb_slave_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_cdc_slimbus_slave_cfg sb_slave_cfg;
+} __packed;
+
+struct afe_svc_cmd_cdc_reg_page_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_cdc_reg_page_cfg cdc_reg_page_cfg;
+} __packed;
+
+struct afe_svc_cmd_cdc_aanc_version {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_cdc_aanc_version version;
+} __packed;
+
+struct afe_port_cmd_set_aanc_param {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ union {
+ struct afe_param_aanc_port_cfg aanc_port_cfg;
+ struct afe_mod_enable_param mod_enable;
+ } __packed data;
+} __packed;
+
+struct afe_port_cmd_set_aanc_acdb_table {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+} __packed;
+
+/* Dolby DAP topology */
+#define DOLBY_ADM_COPP_TOPOLOGY_ID 0x0001033B
+#define DS2_ADM_COPP_TOPOLOGY_ID 0x1301033B
+
+/* RMS value from DSP */
+#define RMS_MODULEID_APPI_PASSTHRU 0x10009011
+#define RMS_PARAM_FIRST_SAMPLE 0x10009012
+#define RMS_PAYLOAD_LEN 4
+
+/* Customized mixing in matix mixer */
+#define MTMX_MODULE_ID_DEFAULT_CHMIXER 0x00010341
+#define DEFAULT_CHMIXER_PARAM_ID_COEFF 0x00010342
+#define CUSTOM_STEREO_PAYLOAD_SIZE 9
+#define CUSTOM_STEREO_CMD_PARAM_SIZE 24
+#define CUSTOM_STEREO_NUM_OUT_CH 0x0002
+#define CUSTOM_STEREO_NUM_IN_CH 0x0002
+#define CUSTOM_STEREO_INDEX_PARAM 0x0002
+#define Q14_GAIN_ZERO_POINT_FIVE 0x2000
+#define Q14_GAIN_UNITY 0x4000
+
+struct afe_svc_cmd_set_clip_bank_selection {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_clip_bank_sel bank_sel;
+} __packed;
+
+/* Ultrasound supported formats */
+#define US_POINT_EPOS_FORMAT_V2 0x0001272D
+#define US_RAW_FORMAT_V2 0x0001272C
+#define US_PROX_FORMAT_V4 0x0001273B
+#define US_RAW_SYNC_FORMAT 0x0001272F
+#define US_GES_SYNC_FORMAT 0x00012730
+
+#define AFE_MODULE_GROUP_DEVICE 0x00010254
+#define AFE_PARAM_ID_GROUP_DEVICE_CFG 0x00010255
+#define AFE_PARAM_ID_GROUP_DEVICE_ENABLE 0x00010256
+#define AFE_GROUP_DEVICE_ID_SECONDARY_MI2S_RX 0x1102
+
+/* Payload of the #AFE_PARAM_ID_GROUP_DEVICE_CFG
+ * parameter, which configures max of 8 AFE ports
+ * into a group.
+ * The fixed size of this structure is sixteen bytes.
+ */
+struct afe_group_device_group_cfg {
+ u32 minor_version;
+ u16 group_id;
+ u16 num_channels;
+ u16 port_id[8];
+} __packed;
+
+#define AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x100)
+#define AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x100)
+#define AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x100)
+#define AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x100)
+#define AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x100)
+#define AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x100)
+#define AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x100)
+#define AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x100)
+
+/* ID of the parameter used by #AFE_MODULE_GROUP_DEVICE to configure the
+ * group device. #AFE_SVC_CMD_SET_PARAM can use this parameter ID.
+ *
+ * Requirements:
+ * - Configure the group before the member ports in the group are
+ * configured and started.
+ * - Enable the group only after it is configured.
+ * - Stop all member ports in the group before disabling the group.
+ */
+#define AFE_PARAM_ID_GROUP_DEVICE_TDM_CONFIG 0x0001029E
+
+/* Version information used to handle future additions to
+ * AFE_PARAM_ID_GROUP_DEVICE_TDM_CONFIG processing (for backward compatibility).
+ */
+#define AFE_API_VERSION_GROUP_DEVICE_TDM_CONFIG 0x1
+
+/* Number of AFE ports in group device */
+#define AFE_GROUP_DEVICE_NUM_PORTS 8
+
+/* Payload of the AFE_PARAM_ID_GROUP_DEVICE_TDM_CONFIG parameter ID
+ * used by AFE_MODULE_GROUP_DEVICE.
+ */
+struct afe_param_id_group_device_tdm_cfg {
+ u32 group_device_cfg_minor_version;
+ /* Minor version used to track group device configuration.
+ * @values #AFE_API_VERSION_GROUP_DEVICE_TDM_CONFIG
+ */
+
+ u16 group_id;
+ /* ID for the group device.
+ * @values
+ * - #AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX
+ * - #AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX
+ * - #AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX
+ * - #AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX
+ * - #AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX
+ * - #AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX
+ * - #AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX
+ * - #AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX
+ */
+
+ u16 reserved;
+ /* 0 */
+
+ u16 port_id[AFE_GROUP_DEVICE_NUM_PORTS];
+ /* Array of member port IDs of this group.
+ * @values
+ * - #AFE_PORT_ID_PRIMARY_TDM_RX
+ * - #AFE_PORT_ID_PRIMARY_TDM_RX_1
+ * - #AFE_PORT_ID_PRIMARY_TDM_RX_2
+ * - #AFE_PORT_ID_PRIMARY_TDM_RX_3
+ * - #AFE_PORT_ID_PRIMARY_TDM_RX_4
+ * - #AFE_PORT_ID_PRIMARY_TDM_RX_5
+ * - #AFE_PORT_ID_PRIMARY_TDM_RX_6
+ * - #AFE_PORT_ID_PRIMARY_TDM_RX_7
+
+ * - #AFE_PORT_ID_PRIMARY_TDM_TX
+ * - #AFE_PORT_ID_PRIMARY_TDM_TX_1
+ * - #AFE_PORT_ID_PRIMARY_TDM_TX_2
+ * - #AFE_PORT_ID_PRIMARY_TDM_TX_3
+ * - #AFE_PORT_ID_PRIMARY_TDM_TX_4
+ * - #AFE_PORT_ID_PRIMARY_TDM_TX_5
+ * - #AFE_PORT_ID_PRIMARY_TDM_TX_6
+ * - #AFE_PORT_ID_PRIMARY_TDM_TX_7
+
+ * - #AFE_PORT_ID_SECONDARY_TDM_RX
+ * - #AFE_PORT_ID_SECONDARY_TDM_RX_1
+ * - #AFE_PORT_ID_SECONDARY_TDM_RX_2
+ * - #AFE_PORT_ID_SECONDARY_TDM_RX_3
+ * - #AFE_PORT_ID_SECONDARY_TDM_RX_4
+ * - #AFE_PORT_ID_SECONDARY_TDM_RX_5
+ * - #AFE_PORT_ID_SECONDARY_TDM_RX_6
+ * - #AFE_PORT_ID_SECONDARY_TDM_RX_7
+
+ * - #AFE_PORT_ID_SECONDARY_TDM_TX
+ * - #AFE_PORT_ID_SECONDARY_TDM_TX_1
+ * - #AFE_PORT_ID_SECONDARY_TDM_TX_2
+ * - #AFE_PORT_ID_SECONDARY_TDM_TX_3
+ * - #AFE_PORT_ID_SECONDARY_TDM_TX_4
+ * - #AFE_PORT_ID_SECONDARY_TDM_TX_5
+ * - #AFE_PORT_ID_SECONDARY_TDM_TX_6
+ * - #AFE_PORT_ID_SECONDARY_TDM_TX_7
+
+ * - #AFE_PORT_ID_TERTIARY_TDM_RX
+ * - #AFE_PORT_ID_TERTIARY_TDM_RX_1
+ * - #AFE_PORT_ID_TERTIARY_TDM_RX_2
+ * - #AFE_PORT_ID_TERTIARY_TDM_RX_3
+ * - #AFE_PORT_ID_TERTIARY_TDM_RX_4
+ * - #AFE_PORT_ID_TERTIARY_TDM_RX_5
+ * - #AFE_PORT_ID_TERTIARY_TDM_RX_6
+ * - #AFE_PORT_ID_TERTIARY_TDM_RX_7
+
+ * - #AFE_PORT_ID_TERTIARY_TDM_TX
+ * - #AFE_PORT_ID_TERTIARY_TDM_TX_1
+ * - #AFE_PORT_ID_TERTIARY_TDM_TX_2
+ * - #AFE_PORT_ID_TERTIARY_TDM_TX_3
+ * - #AFE_PORT_ID_TERTIARY_TDM_TX_4
+ * - #AFE_PORT_ID_TERTIARY_TDM_TX_5
+ * - #AFE_PORT_ID_TERTIARY_TDM_TX_6
+ * - #AFE_PORT_ID_TERTIARY_TDM_TX_7
+
+ * - #AFE_PORT_ID_QUATERNARY_TDM_RX
+ * - #AFE_PORT_ID_QUATERNARY_TDM_RX_1
+ * - #AFE_PORT_ID_QUATERNARY_TDM_RX_2
+ * - #AFE_PORT_ID_QUATERNARY_TDM_RX_3
+ * - #AFE_PORT_ID_QUATERNARY_TDM_RX_4
+ * - #AFE_PORT_ID_QUATERNARY_TDM_RX_5
+ * - #AFE_PORT_ID_QUATERNARY_TDM_RX_6
+ * - #AFE_PORT_ID_QUATERNARY_TDM_RX_7
+
+ * - #AFE_PORT_ID_QUATERNARY_TDM_TX
+ * - #AFE_PORT_ID_QUATERNARY_TDM_TX_1
+ * - #AFE_PORT_ID_QUATERNARY_TDM_TX_2
+ * - #AFE_PORT_ID_QUATERNARY_TDM_TX_3
+ * - #AFE_PORT_ID_QUATERNARY_TDM_TX_4
+ * - #AFE_PORT_ID_QUATERNARY_TDM_TX_5
+ * - #AFE_PORT_ID_QUATERNARY_TDM_TX_6
+ * - #AFE_PORT_ID_QUATERNARY_TDM_TX_7
+ * @tablebulletend
+ */
+
+ u32 num_channels;
+ /* Number of enabled slots for TDM frame.
+ * @values 1 to 8
+ */
+
+ u32 sample_rate;
+ /* Sampling rate of the port.
+ * @values
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_24K
+ * - #AFE_PORT_SAMPLE_RATE_32K
+ * - #AFE_PORT_SAMPLE_RATE_48K @tablebulletend
+ */
+
+ u32 bit_width;
+ /* Bit width of the sample.
+ * @values 16, 24, (32)
+ */
+
+ u16 nslots_per_frame;
+ /* Number of slots per frame. Typical : 1, 2, 4, 8, 16, 32.
+ * @values 1 - 32
+ */
+
+ u16 slot_width;
+ /* Slot width of the slot in a TDM frame. (slot_width >= bit_width)
+ * have to be satisfied.
+ * @values 16, 24, 32
+ */
+
+ u32 slot_mask;
+ /* Position of active slots. When that bit is set, that paricular
+ * slot is active.
+ * Number of active slots can be inferred by number of bits set in
+ * the mask. Only 8 individual bits can be enabled.
+ * Bits 0..31 corresponding to slot 0..31
+ * @values 1 to 2^32 -1
+ */
+} __packed;
+
+/* Payload of the #AFE_PARAM_ID_GROUP_DEVICE_ENABLE
+ * parameter, which enables or
+ * disables any module.
+ * The fixed size of this structure is four bytes.
+ */
+
+struct afe_group_device_enable {
+ u16 group_id;
+ /* valid value is AFE_GROUP_DEVICE_ID_SECONDARY_MI2S_RX */
+ u16 enable;
+ /* Enables (1) or disables (0) the module. */
+} __packed;
+
+union afe_port_group_config {
+ struct afe_group_device_group_cfg group_cfg;
+ struct afe_group_device_enable group_enable;
+ struct afe_param_id_group_device_tdm_cfg tdm_cfg;
+} __packed;
+
+struct afe_port_group_create {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ union afe_port_group_config data;
+} __packed;
+
+/* Command for Matrix or Stream Router */
+#define ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2 0x00010DCE
+/* Module for AVSYNC */
+#define ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC 0x00010DC6
+
+/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to specify the
+ * render window start value. This parameter is supported only for a Set
+ * command (not a Get command) in the Rx direction
+ * (#ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2).
+ * Render window start is a value (session time minus timestamp, or ST-TS)
+ * below which frames are held, and after which frames are immediately
+ * rendered.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2 0x00010DD1
+
+/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to specify the
+ * render window end value. This parameter is supported only for a Set
+ * command (not a Get command) in the Rx direction
+ * (#ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2). Render window end is a value
+ * (session time minus timestamp) above which frames are dropped, and below
+ * which frames are immediately rendered.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2 0x00010DD2
+
+/* Generic payload of the window parameters in the
+ * #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC module.
+ * This payload is supported only for a Set command
+ * (not a Get command) on the Rx path.
+ */
+struct asm_session_mtmx_strtr_param_window_v2_t {
+ u32 window_lsw;
+ /* Lower 32 bits of the render window start value. */
+
+ u32 window_msw;
+ /* Upper 32 bits of the render window start value.
+ *
+ * The 64-bit number formed by window_lsw and window_msw specifies a
+ * signed 64-bit window value in microseconds. The sign extension is
+ * necessary. This value is used by the following parameter IDs:
+ * #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2
+ * #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2
+ * #ASM_SESSION_MTMX_STRTR_PARAM_STAT_WINDOW_START_V2
+ * #ASM_SESSION_MTMX_STRTR_PARAM_STAT_WINDOW_END_V2
+ * The value depends on which parameter ID is used.
+ * The aDSP honors the windows at a granularity of 1 ms.
+ */
+};
+
+struct asm_session_cmd_set_mtmx_strstr_params_v2 {
+ uint32_t data_payload_addr_lsw;
+ /* Lower 32 bits of the 64-bit data payload address. */
+
+ uint32_t data_payload_addr_msw;
+ /* Upper 32 bits of the 64-bit data payload address.
+ * If the address is not sent (NULL), the message is in the payload.
+ * If the address is sent (non-NULL), the parameter data payloads
+ * begin at the specified address.
+ */
+
+ uint32_t mem_map_handle;
+ /* Unique identifier for an address. This memory map handle is returned
+ * by the aDSP through the #ASM_CMD_SHARED_MEM_MAP_REGIONS command.
+ * values
+ * - NULL -- Parameter data payloads are within the message payload
+ * (in-band).
+ * - Non-NULL -- Parameter data payloads begin at the address specified
+ * in the data_payload_addr_lsw and data_payload_addr_msw fields
+ * (out-of-band).
+ */
+
+ uint32_t data_payload_size;
+ /* Actual size of the variable payload accompanying the message, or in
+ * shared memory. This field is used for parsing the parameter payload.
+ * values > 0 bytes
+ */
+
+ uint32_t direction;
+ /* Direction of the entity (matrix mixer or stream router) on which
+ * the parameter is to be set.
+ * values
+ * - 0 -- Rx (for Rx stream router or Rx matrix mixer)
+ * - 1 -- Tx (for Tx stream router or Tx matrix mixer)
+ */
+};
+
+struct asm_mtmx_strtr_params {
+ struct apr_hdr hdr;
+ struct asm_session_cmd_set_mtmx_strstr_params_v2 param;
+ struct asm_stream_param_data_v2 data;
+ u32 window_lsw;
+ u32 window_msw;
+} __packed;
+
+#define ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2 0x00010DCF
+#define ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2 0x00010DD0
+
+#define ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3 0x00012F0B
+#define ASM_SESSION_MTMX_STRTR_PARAM_STIME_TSTMP_FLG_BMASK (0x80000000UL)
+
+struct asm_session_cmd_get_mtmx_strstr_params_v2 {
+ uint32_t data_payload_addr_lsw;
+ /* Lower 32 bits of the 64-bit data payload address. */
+
+ uint32_t data_payload_addr_msw;
+ /*
+ * Upper 32 bits of the 64-bit data payload address.
+ * If the address is not sent (NULL), the message is in the payload.
+ * If the address is sent (non-NULL), the parameter data payloads
+ * begin at the specified address.
+ */
+
+ uint32_t mem_map_handle;
+ /*
+ * Unique identifier for an address. This memory map handle is returned
+ * by the aDSP through the #ASM_CMD_SHARED_MEM_MAP_REGIONS command.
+ * values
+ * - NULL -- Parameter data payloads are within the message payload
+ * (in-band).
+ * - Non-NULL -- Parameter data payloads begin at the address specified
+ * in the data_payload_addr_lsw and data_payload_addr_msw fields
+ * (out-of-band).
+ */
+ uint32_t direction;
+ /*
+ * Direction of the entity (matrix mixer or stream router) on which
+ * the parameter is to be set.
+ * values
+ * - 0 -- Rx (for Rx stream router or Rx matrix mixer)
+ * - 1 -- Tx (for Tx stream router or Tx matrix mixer)
+ */
+ uint32_t module_id;
+ /* Unique module ID. */
+
+ uint32_t param_id;
+ /* Unique parameter ID. */
+
+ uint32_t param_max_size;
+};
+
+struct asm_session_mtmx_strtr_param_session_time_v3_t {
+ uint32_t session_time_lsw;
+ /* Lower 32 bits of the current session time in microseconds */
+
+ uint32_t session_time_msw;
+ /*
+ * Upper 32 bits of the current session time in microseconds.
+ * The 64-bit number formed by session_time_lsw and session_time_msw
+ * is treated as signed.
+ */
+
+ uint32_t absolute_time_lsw;
+ /*
+ * Lower 32 bits of the 64-bit absolute time in microseconds.
+ * This is the time when the sample corresponding to the
+ * session_time_lsw is rendered to the hardware. This absolute
+ * time can be slightly in the future or past.
+ */
+
+ uint32_t absolute_time_msw;
+ /*
+ * Upper 32 bits of the 64-bit absolute time in microseconds.
+ * This is the time when the sample corresponding to the
+ * session_time_msw is rendered to hardware. This absolute
+ * time can be slightly in the future or past. The 64-bit number
+ * formed by absolute_time_lsw and absolute_time_msw is treated as
+ * unsigned.
+ */
+
+ uint32_t time_stamp_lsw;
+ /* Lower 32 bits of the last processed timestamp in microseconds */
+
+ uint32_t time_stamp_msw;
+ /*
+ * Upper 32 bits of the last processed timestamp in microseconds.
+ * The 64-bit number formed by time_stamp_lsw and time_stamp_lsw
+ * is treated as unsigned.
+ */
+
+ uint32_t flags;
+ /*
+ * Keeps track of any additional flags needed.
+ * @values{for bit 31}
+ * - 0 -- Uninitialized/invalid
+ * - 1 -- Valid
+ * All other bits are reserved; clients must set them to zero.
+ */
+};
+
+union asm_session_mtmx_strtr_data_type {
+ struct asm_session_mtmx_strtr_param_session_time_v3_t session_time;
+};
+
+struct asm_mtmx_strtr_get_params {
+ struct apr_hdr hdr;
+ struct asm_session_cmd_get_mtmx_strstr_params_v2 param_info;
+} __packed;
+
+struct asm_mtmx_strtr_get_params_cmdrsp {
+ uint32_t err_code;
+ struct asm_stream_param_data_v2 param_info;
+ union asm_session_mtmx_strtr_data_type param_data;
+} __packed;
+
+#define AUDPROC_MODULE_ID_RESAMPLER 0x00010719
+
+enum {
+ LEGACY_PCM = 0,
+ COMPRESSED_PASSTHROUGH,
+ COMPRESSED_PASSTHROUGH_CONVERT,
+ COMPRESSED_PASSTHROUGH_DSD,
+};
+
+#define AUDPROC_MODULE_ID_COMPRESSED_MUTE 0x00010770
+#define AUDPROC_PARAM_ID_COMPRESSED_MUTE 0x00010771
+
+struct adm_set_compressed_device_mute {
+ struct adm_cmd_set_pp_params_v5 command;
+ struct adm_param_data_v5 params;
+ u32 mute_on;
+} __packed;
+
+#define AUDPROC_MODULE_ID_COMPRESSED_LATENCY 0x0001076E
+#define AUDPROC_PARAM_ID_COMPRESSED_LATENCY 0x0001076F
+
+struct adm_set_compressed_device_latency {
+ struct adm_cmd_set_pp_params_v5 command;
+ struct adm_param_data_v5 params;
+ u32 latency;
+} __packed;
+
+#define VOICEPROC_MODULE_ID_GENERIC_TX 0x00010EF6
+#define VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS 0x00010E37
+#define VOICEPROC_PARAM_ID_FLUENCE_SOURCETRACKING 0x00010E38
+#define MAX_SECTORS 8
+#define MAX_NOISE_SOURCE_INDICATORS 3
+#define MAX_POLAR_ACTIVITY_INDICATORS 360
+
+struct sound_focus_param {
+ uint16_t start_angle[MAX_SECTORS];
+ uint8_t enable[MAX_SECTORS];
+ uint16_t gain_step;
+} __packed;
+
+struct source_tracking_param {
+ uint8_t vad[MAX_SECTORS];
+ uint16_t doa_speech;
+ uint16_t doa_noise[MAX_NOISE_SOURCE_INDICATORS];
+ uint8_t polar_activity[MAX_POLAR_ACTIVITY_INDICATORS];
+} __packed;
+
+struct adm_param_fluence_soundfocus_t {
+ uint16_t start_angles[MAX_SECTORS];
+ uint8_t enables[MAX_SECTORS];
+ uint16_t gain_step;
+ uint16_t reserved;
+} __packed;
+
+struct adm_set_fluence_soundfocus_param {
+ struct adm_cmd_set_pp_params_v5 params;
+ struct adm_param_data_v5 data;
+ struct adm_param_fluence_soundfocus_t soundfocus_data;
+} __packed;
+
+struct adm_param_fluence_sourcetracking_t {
+ uint8_t vad[MAX_SECTORS];
+ uint16_t doa_speech;
+ uint16_t doa_noise[MAX_NOISE_SOURCE_INDICATORS];
+ uint8_t polar_activity[MAX_POLAR_ACTIVITY_INDICATORS];
+} __packed;
+
+#define AUDPROC_MODULE_ID_AUDIOSPHERE 0x00010916
+#define AUDPROC_PARAM_ID_AUDIOSPHERE_ENABLE 0x00010917
+#define AUDPROC_PARAM_ID_AUDIOSPHERE_STRENGTH 0x00010918
+#define AUDPROC_PARAM_ID_AUDIOSPHERE_CONFIG_MODE 0x00010919
+
+#define AUDPROC_PARAM_ID_AUDIOSPHERE_COEFFS_STEREO_INPUT 0x0001091A
+#define AUDPROC_PARAM_ID_AUDIOSPHERE_COEFFS_MULTICHANNEL_INPUT 0x0001091B
+#define AUDPROC_PARAM_ID_AUDIOSPHERE_DESIGN_STEREO_INPUT 0x0001091C
+#define AUDPROC_PARAM_ID_AUDIOSPHERE_DESIGN_MULTICHANNEL_INPUT 0x0001091D
+
+#define AUDPROC_PARAM_ID_AUDIOSPHERE_OPERATING_INPUT_MEDIA_INFO 0x0001091E
+#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
new file mode 100644
index 0000000..eb35645
--- /dev/null
+++ b/include/sound/apr_audio.h
@@ -0,0 +1,1931 @@
+/*
+ *
+ * Copyright (c) 2010-2013, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _APR_AUDIO_H_
+#define _APR_AUDIO_H_
+
+/* ASM opcodes without APR payloads*/
+#include <linux/qdsp6v2/apr.h>
+
+/*
+ * Audio Front End (AFE)
+ */
+
+/* Port ID. Update afe_get_port_index when a new port is added here. */
+#define PRIMARY_I2S_RX 0 /* index = 0 */
+#define PRIMARY_I2S_TX 1 /* index = 1 */
+#define PCM_RX 2 /* index = 2 */
+#define PCM_TX 3 /* index = 3 */
+#define SECONDARY_I2S_RX 4 /* index = 4 */
+#define SECONDARY_I2S_TX 5 /* index = 5 */
+#define MI2S_RX 6 /* index = 6 */
+#define MI2S_TX 7 /* index = 7 */
+#define HDMI_RX 8 /* index = 8 */
+#define RSVD_2 9 /* index = 9 */
+#define RSVD_3 10 /* index = 10 */
+#define DIGI_MIC_TX 11 /* index = 11 */
+#define VOICE_RECORD_RX 0x8003 /* index = 12 */
+#define VOICE_RECORD_TX 0x8004 /* index = 13 */
+#define VOICE_PLAYBACK_TX 0x8005 /* index = 14 */
+
+/* Slimbus Multi channel port id pool */
+#define SLIMBUS_0_RX 0x4000 /* index = 15 */
+#define SLIMBUS_0_TX 0x4001 /* index = 16 */
+#define SLIMBUS_1_RX 0x4002 /* index = 17 */
+#define SLIMBUS_1_TX 0x4003 /* index = 18 */
+#define SLIMBUS_2_RX 0x4004
+#define SLIMBUS_2_TX 0x4005
+#define SLIMBUS_3_RX 0x4006
+#define SLIMBUS_3_TX 0x4007
+#define SLIMBUS_4_RX 0x4008
+#define SLIMBUS_4_TX 0x4009 /* index = 24 */
+
+#define INT_BT_SCO_RX 0x3000 /* index = 25 */
+#define INT_BT_SCO_TX 0x3001 /* index = 26 */
+#define INT_BT_A2DP_RX 0x3002 /* index = 27 */
+#define INT_FM_RX 0x3004 /* index = 28 */
+#define INT_FM_TX 0x3005 /* index = 29 */
+#define RT_PROXY_PORT_001_RX 0x2000 /* index = 30 */
+#define RT_PROXY_PORT_001_TX 0x2001 /* index = 31 */
+#define SECONDARY_PCM_RX 12 /* index = 32 */
+#define SECONDARY_PCM_TX 13 /* index = 33 */
+#define PSEUDOPORT_01 0x8001 /* index =34 */
+
+#define AFE_PORT_INVALID 0xFFFF
+#define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
+
+#define AFE_PORT_CMD_START 0x000100ca
+
+#define AFE_EVENT_RTPORT_START 0
+#define AFE_EVENT_RTPORT_STOP 1
+#define AFE_EVENT_RTPORT_LOW_WM 2
+#define AFE_EVENT_RTPORT_HI_WM 3
+
+struct afe_port_start_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 gain; /* Q13 */
+ u32 sample_rate; /* 8 , 16, 48khz */
+} __packed;
+
+#define AFE_PORT_CMD_STOP 0x000100cb
+struct afe_port_stop_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 reserved;
+} __packed;
+
+#define AFE_PORT_CMD_APPLY_GAIN 0x000100cc
+struct afe_port_gain_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 gain;/* Q13 */
+} __packed;
+
+#define AFE_PORT_CMD_SIDETONE_CTL 0x000100cd
+struct afe_port_sidetone_command {
+ struct apr_hdr hdr;
+ u16 rx_port_id; /* Primary i2s tx = 1 */
+ /* PCM tx = 3 */
+ /* Secondary i2s tx = 5 */
+ /* Mi2s tx = 7 */
+ /* Digital mic tx = 11 */
+ u16 tx_port_id; /* Primary i2s rx = 0 */
+ /* PCM rx = 2 */
+ /* Secondary i2s rx = 4 */
+ /* Mi2S rx = 6 */
+ /* HDMI rx = 8 */
+ u16 gain; /* Q13 */
+ u16 enable; /* 1 = enable, 0 = disable */
+} __packed;
+
+#define AFE_PORT_CMD_LOOPBACK 0x000100ce
+struct afe_loopback_command {
+ struct apr_hdr hdr;
+ u16 tx_port_id; /* Primary i2s rx = 0 */
+ /* PCM rx = 2 */
+ /* Secondary i2s rx = 4 */
+ /* Mi2S rx = 6 */
+ /* HDMI rx = 8 */
+ u16 rx_port_id; /* Primary i2s tx = 1 */
+ /* PCM tx = 3 */
+ /* Secondary i2s tx = 5 */
+ /* Mi2s tx = 7 */
+ /* Digital mic tx = 11 */
+ u16 mode; /* Default -1, DSP will conver
+ * the tx to rx format
+ */
+ u16 enable; /* 1 = enable, 0 = disable */
+} __packed;
+
+#define AFE_PSEUDOPORT_CMD_START 0x000100cf
+struct afe_pseudoport_start_command {
+ struct apr_hdr hdr;
+ u16 port_id; /* Pseudo Port 1 = 0x8000 */
+ /* Pseudo Port 2 = 0x8001 */
+ /* Pseudo Port 3 = 0x8002 */
+ u16 timing; /* FTRT = 0 , AVTimer = 1, */
+} __packed;
+
+#define AFE_PSEUDOPORT_CMD_STOP 0x000100d0
+struct afe_pseudoport_stop_command {
+ struct apr_hdr hdr;
+ u16 port_id; /* Pseudo Port 1 = 0x8000 */
+ /* Pseudo Port 2 = 0x8001 */
+ /* Pseudo Port 3 = 0x8002 */
+ u16 reserved;
+} __packed;
+
+#define AFE_CMD_GET_ACTIVE_PORTS 0x000100d1
+
+
+#define AFE_CMD_GET_ACTIVE_HANDLES_FOR_PORT 0x000100d2
+struct afe_get_active_handles_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 reserved;
+} __packed;
+
+/*
+ * Opcode for AFE to start DTMF.
+ */
+#define AFE_PORTS_CMD_DTMF_CTL 0x00010102
+
+/** DTMF payload.*/
+struct afe_dtmf_generation_command {
+ struct apr_hdr hdr;
+
+ /*
+ * Duration of the DTMF tone in ms.
+ * -1 -> continuous,
+ * 0 -> disable
+ */
+ int64_t duration_in_ms;
+
+ /*
+ * The DTMF high tone frequency.
+ */
+ uint16_t high_freq;
+
+ /*
+ * The DTMF low tone frequency.
+ */
+ uint16_t low_freq;
+
+ /*
+ * The DTMF volume setting
+ */
+ uint16_t gain;
+
+ /*
+ * The number of ports to enable/disable on.
+ */
+ uint16_t num_ports;
+
+ /*
+ * The Destination ports - array .
+ * For DTMF on multiple ports, portIds needs to
+ * be populated numPorts times.
+ */
+ uint16_t port_ids;
+
+ /*
+ * variable for 32 bit alignment of APR packet.
+ */
+ uint16_t reserved;
+} __packed;
+
+#define AFE_PCM_CFG_MODE_PCM 0x0
+#define AFE_PCM_CFG_MODE_AUX 0x1
+#define AFE_PCM_CFG_SYNC_EXT 0x0
+#define AFE_PCM_CFG_SYNC_INT 0x1
+#define AFE_PCM_CFG_FRM_8BPF 0x0
+#define AFE_PCM_CFG_FRM_16BPF 0x1
+#define AFE_PCM_CFG_FRM_32BPF 0x2
+#define AFE_PCM_CFG_FRM_64BPF 0x3
+#define AFE_PCM_CFG_FRM_128BPF 0x4
+#define AFE_PCM_CFG_FRM_256BPF 0x5
+#define AFE_PCM_CFG_QUANT_ALAW_NOPAD 0x0
+#define AFE_PCM_CFG_QUANT_MULAW_NOPAD 0x1
+#define AFE_PCM_CFG_QUANT_LINEAR_NOPAD 0x2
+#define AFE_PCM_CFG_QUANT_ALAW_PAD 0x3
+#define AFE_PCM_CFG_QUANT_MULAW_PAD 0x4
+#define AFE_PCM_CFG_QUANT_LINEAR_PAD 0x5
+#define AFE_PCM_CFG_CDATAOE_MASTER 0x0
+#define AFE_PCM_CFG_CDATAOE_SHARE 0x1
+
+struct afe_port_pcm_cfg {
+ u16 mode; /* PCM (short sync) = 0, AUXPCM (long sync) = 1 */
+ u16 sync; /* external = 0 , internal = 1 */
+ u16 frame; /* 8 bpf = 0 */
+ /* 16 bpf = 1 */
+ /* 32 bpf = 2 */
+ /* 64 bpf = 3 */
+ /* 128 bpf = 4 */
+ /* 256 bpf = 5 */
+ u16 quant;
+ u16 slot; /* Slot for PCM stream , 0 - 31 */
+ u16 data; /* 0, PCM block is the only master */
+ /* 1, PCM block is shares to driver data out signal */
+ /* other master */
+ u16 reserved;
+} __packed;
+
+enum {
+ AFE_I2S_SD0 = 1,
+ AFE_I2S_SD1,
+ AFE_I2S_SD2,
+ AFE_I2S_SD3,
+ AFE_I2S_QUAD01,
+ AFE_I2S_QUAD23,
+ AFE_I2S_6CHS,
+ AFE_I2S_8CHS,
+};
+
+#define AFE_MI2S_MONO 0
+#define AFE_MI2S_STEREO 3
+#define AFE_MI2S_4CHANNELS 4
+#define AFE_MI2S_6CHANNELS 6
+#define AFE_MI2S_8CHANNELS 8
+
+struct afe_port_mi2s_cfg {
+ u16 bitwidth; /* 16,24,32 */
+ u16 line; /* Called ChannelMode in documentation */
+ /* i2s_sd0 = 1 */
+ /* i2s_sd1 = 2 */
+ /* i2s_sd2 = 3 */
+ /* i2s_sd3 = 4 */
+ /* i2s_quad01 = 5 */
+ /* i2s_quad23 = 6 */
+ /* i2s_6chs = 7 */
+ /* i2s_8chs = 8 */
+ u16 channel; /* Called MonoStereo in documentation */
+ /* i2s mono = 0 */
+ /* i2s mono right = 1 */
+ /* i2s mono left = 2 */
+ /* i2s stereo = 3 */
+ u16 ws; /* 0, word select signal from external source */
+ /* 1, word select signal from internal source */
+ u16 format; /* don't touch this field if it is not for */
+ /* AFE_PORT_CMD_I2S_CONFIG opcode */
+} __packed;
+
+struct afe_port_hdmi_cfg {
+ u16 bitwidth; /* 16,24,32 */
+ u16 channel_mode; /* HDMI Stereo = 0 */
+ /* HDMI_3Point1 (4-ch) = 1 */
+ /* HDMI_5Point1 (6-ch) = 2 */
+ /* HDMI_6Point1 (8-ch) = 3 */
+ u16 data_type; /* HDMI_Linear = 0 */
+ /* HDMI_non_Linear = 1 */
+} __packed;
+
+
+struct afe_port_hdmi_multi_ch_cfg {
+ u16 data_type; /* HDMI_Linear = 0 */
+ /* HDMI_non_Linear = 1 */
+ u16 channel_allocation; /* The default is 0 (Stereo) */
+ u16 reserved; /* must be set to 0 */
+} __packed;
+
+
+/* Slimbus Device Ids */
+#define AFE_SLIMBUS_DEVICE_1 0x0
+#define AFE_SLIMBUS_DEVICE_2 0x1
+#define AFE_PORT_MAX_AUDIO_CHAN_CNT 16
+
+struct afe_port_slimbus_cfg {
+ u16 slimbus_dev_id; /* SLIMBUS Device id.*/
+
+ u16 slave_dev_pgd_la; /* Slave ported generic device
+ * logical address.
+ */
+ u16 slave_dev_intfdev_la; /* Slave interface device logical
+ * address.
+ */
+ u16 bit_width; /* bit width of the samples, 16, 24.*/
+
+ u16 data_format; /* data format.*/
+
+ u16 num_channels; /* Number of channels.*/
+
+ /* Slave port mapping for respective channels.*/
+ u16 slave_port_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+
+ u16 reserved;
+} __packed;
+
+struct afe_port_slimbus_sch_cfg {
+ u16 slimbus_dev_id; /* SLIMBUS Device id.*/
+ u16 bit_width; /* bit width of the samples, 16, 24.*/
+ u16 data_format; /* data format.*/
+ u16 num_channels; /* Number of channels.*/
+ u16 reserved;
+ /* Slave channel mapping for respective channels.*/
+ u8 slave_ch_mapping[8];
+} __packed;
+
+struct afe_port_rtproxy_cfg {
+ u16 bitwidth; /* 16,24,32 */
+ u16 interleaved; /* interleaved = 1 */
+ /* Noninterleaved = 0 */
+ u16 frame_sz; /* 5ms buffers = 160bytes */
+ u16 jitter; /* 10ms of jitter = 320 */
+ u16 lw_mark; /* Low watermark in bytes for triggering event*/
+ u16 hw_mark; /* High watermark bytes for triggering event*/
+ u16 rsvd;
+ int num_ch; /* 1 to 8 */
+} __packed;
+
+struct afe_port_pseudo_cfg {
+ u16 bit_width;
+ u16 num_channels;
+ u16 data_format;
+ u16 timing_mode;
+ u16 reserved;
+} __packed;
+
+#define AFE_PORT_AUDIO_IF_CONFIG 0x000100d3
+#define AFE_PORT_AUDIO_SLIM_SCH_CONFIG 0x000100e4
+#define AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG 0x000100D9
+#define AFE_PORT_CMD_I2S_CONFIG 0x000100E7
+
+union afe_port_config {
+ struct afe_port_pcm_cfg pcm;
+ struct afe_port_mi2s_cfg mi2s;
+ struct afe_port_hdmi_cfg hdmi;
+ struct afe_port_hdmi_multi_ch_cfg hdmi_multi_ch;
+ struct afe_port_slimbus_cfg slimbus;
+ struct afe_port_slimbus_sch_cfg slim_sch;
+ struct afe_port_rtproxy_cfg rtproxy;
+ struct afe_port_pseudo_cfg pseudo;
+} __packed;
+
+struct afe_audioif_config_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ union afe_port_config port;
+} __packed;
+
+#define AFE_TEST_CODEC_LOOPBACK_CTL 0x000100d5
+struct afe_codec_loopback_command {
+ u16 port_inf; /* Primary i2s = 0 */
+ /* PCM = 2 */
+ /* Secondary i2s = 4 */
+ /* Mi2s = 6 */
+ u16 enable; /* 0, disable. 1, enable */
+} __packed;
+
+
+#define AFE_PARAM_ID_SIDETONE_GAIN 0x00010300
+struct afe_param_sidetone_gain {
+ u16 gain;
+ u16 reserved;
+} __packed;
+
+#define AFE_PARAM_ID_SAMPLING_RATE 0x00010301
+struct afe_param_sampling_rate {
+ u32 sampling_rate;
+} __packed;
+
+
+#define AFE_PARAM_ID_CHANNELS 0x00010302
+struct afe_param_channels {
+ u16 channels;
+ u16 reserved;
+} __packed;
+
+
+#define AFE_PARAM_ID_LOOPBACK_GAIN 0x00010303
+struct afe_param_loopback_gain {
+ u16 gain;
+ u16 reserved;
+} __packed;
+
+/* Parameter ID used to configure and enable/disable the loopback path. The
+ * difference with respect to the existing API, AFE_PORT_CMD_LOOPBACK, is that
+ * it allows Rx port to be configured as source port in loopback path. Port-id
+ * in AFE_PORT_CMD_SET_PARAM cmd is the source port which can be Tx or Rx port.
+ * In addition, we can configure the type of routing mode to handle different
+ * use cases.
+ */
+enum {
+ /* Regular loopback from source to destination port */
+ LB_MODE_DEFAULT = 1,
+ /* Sidetone feed from Tx source to Rx destination port */
+ LB_MODE_SIDETONE,
+ /* Echo canceller reference, voice + audio + DTMF */
+ LB_MODE_EC_REF_VOICE_AUDIO,
+ /* Echo canceller reference, voice alone */
+ LB_MODE_EC_REF_VOICE
+};
+
+#define AFE_PARAM_ID_LOOPBACK_CONFIG 0x0001020B
+#define AFE_API_VERSION_LOOPBACK_CONFIG 0x1
+struct afe_param_loopback_cfg {
+ /* Minor version used for tracking the version of the configuration
+ * interface.
+ */
+ uint32_t loopback_cfg_minor_version;
+
+ /* Destination Port Id. */
+ uint16_t dst_port_id;
+
+ /* Specifies data path type from src to dest port. Supported values:
+ * LB_MODE_DEFAULT
+ * LB_MODE_SIDETONE
+ * LB_MODE_EC_REF_VOICE_AUDIO
+ * LB_MODE_EC_REF_VOICE
+ */
+ uint16_t routing_mode;
+
+ /* Specifies whether to enable (1) or disable (0) an AFE loopback. */
+ uint16_t enable;
+
+ /* Reserved for 32-bit alignment. This field must be set to 0. */
+ uint16_t reserved;
+} __packed;
+
+#define AFE_MODULE_ID_PORT_INFO 0x00010200
+/* Module ID for the loopback-related parameters. */
+#define AFE_MODULE_LOOPBACK 0x00010205
+struct afe_param_payload_base {
+ u32 module_id;
+ u32 param_id;
+ u16 param_size;
+ u16 reserved;
+} __packed;
+
+struct afe_param_payload {
+ struct afe_param_payload_base base;
+ union {
+ struct afe_param_sidetone_gain sidetone_gain;
+ struct afe_param_sampling_rate sampling_rate;
+ struct afe_param_channels channels;
+ struct afe_param_loopback_gain loopback_gain;
+ struct afe_param_loopback_cfg loopback_cfg;
+ } __packed param;
+} __packed;
+
+#define AFE_PORT_CMD_SET_PARAM 0x000100dc
+
+struct afe_port_cmd_set_param {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 payload_size;
+ u32 payload_address;
+ struct afe_param_payload payload;
+} __packed;
+
+struct afe_port_cmd_set_param_no_payload {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 payload_size;
+ u32 payload_address;
+} __packed;
+
+#define AFE_EVENT_GET_ACTIVE_PORTS 0x00010100
+struct afe_get_active_ports_rsp {
+ u16 num_ports;
+ u16 port_id;
+} __packed;
+
+
+#define AFE_EVENT_GET_ACTIVE_HANDLES 0x00010102
+struct afe_get_active_handles_rsp {
+ u16 port_id;
+ u16 num_handles;
+ u16 mode; /* 0, voice rx */
+ /* 1, voice tx */
+ /* 2, audio rx */
+ /* 3, audio tx */
+ u16 handle;
+} __packed;
+
+#define AFE_SERVICE_CMD_MEMORY_MAP 0x000100DE
+struct afe_cmd_memory_map {
+ struct apr_hdr hdr;
+ u32 phy_addr;
+ u32 mem_sz;
+ u16 mem_id;
+ u16 rsvd;
+} __packed;
+
+#define AFE_SERVICE_CMD_MEMORY_UNMAP 0x000100DF
+struct afe_cmd_memory_unmap {
+ struct apr_hdr hdr;
+ u32 phy_addr;
+} __packed;
+
+#define AFE_SERVICE_CMD_REG_RTPORT 0x000100E0
+struct afe_cmd_reg_rtport {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 rsvd;
+} __packed;
+
+#define AFE_SERVICE_CMD_UNREG_RTPORT 0x000100E1
+struct afe_cmd_unreg_rtport {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 rsvd;
+} __packed;
+
+#define AFE_SERVICE_CMD_RTPORT_WR 0x000100E2
+struct afe_cmd_rtport_wr {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 rsvd;
+ u32 buf_addr;
+ u32 bytes_avail;
+} __packed;
+
+#define AFE_SERVICE_CMD_RTPORT_RD 0x000100E3
+struct afe_cmd_rtport_rd {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 rsvd;
+ u32 buf_addr;
+ u32 bytes_avail;
+} __packed;
+
+#define AFE_EVENT_RT_PROXY_PORT_STATUS 0x00010105
+
+#define ADM_MAX_COPPS 5
+
+#define ADM_SERVICE_CMD_GET_COPP_HANDLES 0x00010300
+struct adm_get_copp_handles_command {
+ struct apr_hdr hdr;
+} __packed;
+
+#define ADM_CMD_MATRIX_MAP_ROUTINGS 0x00010301
+struct adm_routings_session {
+ u16 id;
+ u16 num_copps;
+ u16 copp_id[ADM_MAX_COPPS+1]; /*Padding if numCopps is odd */
+} __packed;
+
+struct adm_routings_command {
+ struct apr_hdr hdr;
+ u32 path; /* 0 = Rx, 1 Tx */
+ u32 num_sessions;
+ struct adm_routings_session session[8];
+} __packed;
+
+
+#define ADM_CMD_MATRIX_RAMP_GAINS 0x00010302
+struct adm_ramp_gain {
+ struct apr_hdr hdr;
+ u16 session_id;
+ u16 copp_id;
+ u16 initial_gain;
+ u16 gain_increment;
+ u16 ramp_duration;
+ u16 reserved;
+} __packed;
+
+struct adm_ramp_gains_command {
+ struct apr_hdr hdr;
+ u32 id;
+ u32 num_gains;
+ struct adm_ramp_gain gains[ADM_MAX_COPPS];
+} __packed;
+
+
+#define ADM_CMD_COPP_OPEN 0x00010304
+struct adm_copp_open_command {
+ struct apr_hdr hdr;
+ u16 flags;
+ u16 mode; /* 1-RX, 2-Live TX, 3-Non Live TX */
+ u16 endpoint_id1;
+ u16 endpoint_id2;
+ u32 topology_id;
+ u16 channel_config;
+ u16 reserved;
+ u32 rate;
+} __packed;
+
+#define ADM_CMD_COPP_CLOSE 0x00010305
+
+#define ADM_CMD_MULTI_CHANNEL_COPP_OPEN 0x00010310
+#define ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3 0x00010333
+struct adm_multi_ch_copp_open_command {
+ struct apr_hdr hdr;
+ u16 flags;
+ u16 mode; /* 1-RX, 2-Live TX, 3-Non Live TX */
+ u16 endpoint_id1;
+ u16 endpoint_id2;
+ u32 topology_id;
+ u16 channel_config;
+ u16 reserved;
+ u32 rate;
+ u8 dev_channel_mapping[8];
+} __packed;
+
+struct adm_multi_channel_copp_open_v3 {
+ struct apr_hdr hdr;
+ u16 flags;
+ u16 mode;
+ u16 endpoint_id1;
+ u16 endpoint_id2;
+ u32 topology_id;
+ u16 channel_config;
+ u16 bit_width;
+ u32 rate;
+ u8 dev_channel_mapping[8];
+};
+
+#define ADM_CMD_MEMORY_MAP 0x00010C30
+struct adm_cmd_memory_map {
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 buf_size;
+ u16 mempool_id;
+ u16 reserved;
+} __packed;
+
+#define ADM_CMD_MEMORY_UNMAP 0x00010C31
+struct adm_cmd_memory_unmap {
+ struct apr_hdr hdr;
+ u32 buf_add;
+} __packed;
+
+#define ADM_CMD_MEMORY_MAP_REGIONS 0x00010C47
+struct adm_memory_map_regions {
+ u32 phys;
+ u32 buf_size;
+} __packed;
+
+struct adm_cmd_memory_map_regions {
+ struct apr_hdr hdr;
+ u16 mempool_id;
+ u16 nregions;
+} __packed;
+
+#define ADM_CMD_MEMORY_UNMAP_REGIONS 0x00010C48
+struct adm_memory_unmap_regions {
+ u32 phys;
+} __packed;
+
+struct adm_cmd_memory_unmap_regions {
+ struct apr_hdr hdr;
+ u16 nregions;
+ u16 reserved;
+} __packed;
+
+#define DEFAULT_COPP_TOPOLOGY 0x00010be3
+#define DEFAULT_POPP_TOPOLOGY 0x00010be4
+#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
+#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
+#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
+
+#define LOWLATENCY_POPP_TOPOLOGY 0x00010C68
+#define LOWLATENCY_COPP_TOPOLOGY 0x00010312
+#define PCM_BITS_PER_SAMPLE 16
+
+#define ASM_OPEN_WRITE_PERF_MODE_BIT (1<<28)
+#define ASM_OPEN_READ_PERF_MODE_BIT (1<<29)
+#define ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT (1<<13)
+
+
+#define ASM_MAX_EQ_BANDS 12
+
+struct asm_eq_band {
+ u32 band_idx; /* The band index, 0 .. 11 */
+ u32 filter_type; /* Filter band type */
+ u32 center_freq_hz; /* Filter band center frequency */
+ u32 filter_gain; /* Filter band initial gain (dB) */
+ /* Range is +12 dB to -12 dB with 1dB increments. */
+ u32 q_factor;
+} __packed;
+
+struct asm_equalizer_params {
+ u32 enable;
+ u32 num_bands;
+ struct asm_eq_band eq_bands[ASM_MAX_EQ_BANDS];
+} __packed;
+
+struct asm_master_gain_params {
+ u16 master_gain;
+ u16 padding;
+} __packed;
+
+struct asm_lrchannel_gain_params {
+ u16 left_gain;
+ u16 right_gain;
+} __packed;
+
+struct asm_mute_params {
+ u32 muteflag;
+} __packed;
+
+struct asm_softvolume_params {
+ u32 period;
+ u32 step;
+ u32 rampingcurve;
+} __packed;
+
+struct asm_softpause_params {
+ u32 enable;
+ u32 period;
+ u32 step;
+ u32 rampingcurve;
+} __packed;
+
+struct asm_pp_param_data_hdr {
+ u32 module_id;
+ u32 param_id;
+ u16 param_size;
+ u16 reserved;
+} __packed;
+
+struct asm_pp_params_command {
+ struct apr_hdr hdr;
+ u32 *payload;
+ u32 payload_size;
+ struct asm_pp_param_data_hdr params;
+} __packed;
+
+#define EQUALIZER_MODULE_ID 0x00010c27
+#define EQUALIZER_PARAM_ID 0x00010c28
+
+#define VOLUME_CONTROL_MODULE_ID 0x00010bfe
+#define MASTER_GAIN_PARAM_ID 0x00010bff
+#define L_R_CHANNEL_GAIN_PARAM_ID 0x00010c00
+#define MUTE_CONFIG_PARAM_ID 0x00010c01
+#define SOFT_PAUSE_PARAM_ID 0x00010D6A
+#define SOFT_VOLUME_PARAM_ID 0x00010C29
+
+#define IIR_FILTER_ENABLE_PARAM_ID 0x00010c03
+#define IIR_FILTER_PREGAIN_PARAM_ID 0x00010c04
+#define IIR_FILTER_CONFIG_PARAM_ID 0x00010c05
+
+#define MBADRC_MODULE_ID 0x00010c06
+#define MBADRC_ENABLE_PARAM_ID 0x00010c07
+#define MBADRC_CONFIG_PARAM_ID 0x00010c08
+
+
+#define ADM_CMD_SET_PARAMS 0x00010306
+#define ADM_CMD_GET_PARAMS 0x0001030B
+#define ADM_CMDRSP_GET_PARAMS 0x0001030C
+struct adm_set_params_command {
+ struct apr_hdr hdr;
+ u32 payload;
+ u32 payload_size;
+} __packed;
+
+
+#define ADM_CMD_TAP_COPP_PCM 0x00010307
+struct adm_tap_copp_pcm_command {
+ struct apr_hdr hdr;
+} __packed;
+
+
+/* QDSP6 to Client messages */
+#define ADM_SERVICE_CMDRSP_GET_COPP_HANDLES 0x00010308
+struct adm_get_copp_handles_respond {
+ struct apr_hdr hdr;
+ u32 handles;
+ u32 copp_id;
+} __packed;
+
+#define ADM_CMDRSP_COPP_OPEN 0x0001030A
+struct adm_copp_open_respond {
+ u32 status;
+ u16 copp_id;
+ u16 reserved;
+} __packed;
+
+#define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN 0x00010311
+#define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3 0x00010334
+
+
+#define ASM_STREAM_PRIORITY_NORMAL 0
+#define ASM_STREAM_PRIORITY_LOW 1
+#define ASM_STREAM_PRIORITY_HIGH 2
+#define ASM_STREAM_PRIORITY_RESERVED 3
+
+#define ASM_END_POINT_DEVICE_MATRIX 0
+#define ASM_END_POINT_STREAM 1
+
+#define AAC_ENC_MODE_AAC_LC 0x02
+#define AAC_ENC_MODE_AAC_P 0x05
+#define AAC_ENC_MODE_EAAC_P 0x1D
+
+#define ASM_STREAM_CMD_CLOSE 0x00010BCD
+#define ASM_STREAM_CMD_FLUSH 0x00010BCE
+#define ASM_STREAM_CMD_SET_PP_PARAMS 0x00010BCF
+#define ASM_STREAM_CMD_GET_PP_PARAMS 0x00010BD0
+#define ASM_STREAM_CMDRSP_GET_PP_PARAMS 0x00010BD1
+#define ASM_SESSION_CMD_PAUSE 0x00010BD3
+#define ASM_SESSION_CMD_GET_SESSION_TIME 0x00010BD4
+#define ASM_DATA_CMD_EOS 0x00010BDB
+#define ASM_DATA_EVENT_EOS 0x00010BDD
+
+#define ASM_SERVICE_CMD_GET_STREAM_HANDLES 0x00010C0B
+#define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09
+
+#define ASM_SESSION_EVENT_RX_UNDERFLOW 0x00010C17
+#define ASM_SESSION_EVENT_TX_OVERFLOW 0x00010C18
+#define ASM_SERVICE_CMD_GET_WALLCLOCK_TIME 0x00010C19
+#define ASM_DATA_CMDRSP_EOS 0x00010C1C
+
+/* ASM Data structures */
+
+/* common declarations */
+struct asm_pcm_cfg {
+ u16 ch_cfg;
+ u16 bits_per_sample;
+ u32 sample_rate;
+ u16 is_signed;
+ u16 interleaved;
+};
+
+#define PCM_CHANNEL_NULL 0
+
+/* Front left channel. */
+#define PCM_CHANNEL_FL 1
+
+/* Front right channel. */
+#define PCM_CHANNEL_FR 2
+
+/* Front center channel. */
+#define PCM_CHANNEL_FC 3
+
+/* Left surround channel.*/
+#define PCM_CHANNEL_LS 4
+
+/* Right surround channel.*/
+#define PCM_CHANNEL_RS 5
+
+/* Low frequency effect channel. */
+#define PCM_CHANNEL_LFE 6
+
+/* Center surround channel; Rear center channel. */
+#define PCM_CHANNEL_CS 7
+
+/* Left back channel; Rear left channel. */
+#define PCM_CHANNEL_LB 8
+
+/* Right back channel; Rear right channel. */
+#define PCM_CHANNEL_RB 9
+
+/* Top surround channel. */
+#define PCM_CHANNEL_TS 10
+
+/* Center vertical height channel.*/
+#define PCM_CHANNEL_CVH 11
+
+/* Mono surround channel.*/
+#define PCM_CHANNEL_MS 12
+
+/* Front left of center. */
+#define PCM_CHANNEL_FLC 13
+
+/* Front right of center. */
+#define PCM_CHANNEL_FRC 14
+
+/* Rear left of center. */
+#define PCM_CHANNEL_RLC 15
+
+/* Rear right of center. */
+#define PCM_CHANNEL_RRC 16
+
+#define PCM_FORMAT_MAX_NUM_CHANNEL 8
+
+/* Maximum number of channels supported
+ * in ASM_ENCDEC_DEC_CHAN_MAP command
+ */
+#define MAX_CHAN_MAP_CHANNELS 16
+/*
+ * Multiple-channel PCM decoder format block structure used in the
+ * #ASM_STREAM_CMD_OPEN_WRITE command.
+ * The data must be in little-endian format.
+ */
+struct asm_multi_channel_pcm_fmt_blk {
+
+ u16 num_channels; /*
+ * Number of channels.
+ * Supported values:1 to 8
+ */
+
+ u16 bits_per_sample; /*
+ * Number of bits per sample per channel.
+ * Supported values: 16, 24 When used for
+ * playback, the client must send 24-bit
+ * samples packed in 32-bit words. The
+ * 24-bit samples must be placed in the most
+ * significant 24 bits of the 32-bit word. When
+ * used for recording, the aDSP sends 24-bit
+ * samples packed in 32-bit words. The 24-bit
+ * samples are placed in the most significant
+ * 24 bits of the 32-bit word.
+ */
+
+ u32 sample_rate; /*
+ * Number of samples per second
+ * (in Hertz). Supported values:
+ * 2000 to 48000
+ */
+
+ u16 is_signed; /*
+ * Flag that indicates the samples
+ * are signed (1).
+ */
+
+ u16 is_interleaved; /*
+ * Flag that indicates whether the channels are
+ * de-interleaved (0) or interleaved (1).
+ * Interleaved format means corresponding
+ * samples from the left and right channels are
+ * interleaved within the buffer.
+ * De-interleaved format means samples from
+ * each channel are contiguous in the buffer.
+ * The samples from one channel immediately
+ * follow those of the previous channel.
+ */
+
+ u8 channel_mapping[8]; /*
+ * Supported values:
+ * PCM_CHANNEL_NULL, PCM_CHANNEL_FL,
+ * PCM_CHANNEL_FR, PCM_CHANNEL_FC,
+ * PCM_CHANNEL_LS, PCM_CHANNEL_RS,
+ * PCM_CHANNEL_LFE, PCM_CHANNEL_CS,
+ * PCM_CHANNEL_LB, PCM_CHANNEL_RB,
+ * PCM_CHANNEL_TS, PCM_CHANNEL_CVH,
+ * PCM_CHANNEL_MS, PCM_CHANNEL_FLC,
+ * PCM_CHANNEL_FRC, PCM_CHANNEL_RLC,
+ * PCM_CHANNEL_RRC.
+ * Channel[i] mapping describes channel I. Each
+ * element i of the array describes channel I
+ * inside the buffer where I < num_channels.
+ * An unused channel is set to zero.
+ */
+};
+struct asm_dts_enc_cfg {
+ uint32_t sample_rate;
+ /*
+ * Samples at which input is to be encoded.
+ * Supported values:
+ * 44100 -- encode at 44.1 Khz
+ * 48000 -- encode at 48 Khz
+ */
+
+ uint32_t num_channels;
+ /*
+ * Number of channels for multi-channel encoding.
+ * Supported values: 1 to 6
+ */
+
+ uint8_t channel_mapping[6];
+ /*
+ * Channel array of size 16. Channel[i] mapping describes channel I.
+ * Each element i of the array describes channel I inside the buffer
+ * where num_channels. An unused channel is set to zero. Only first
+ * num_channels elements are valid
+ *
+ * Supported values:
+ * - # PCM_CHANNEL_L
+ * - # PCM_CHANNEL_R
+ * - # PCM_CHANNEL_C
+ * - # PCM_CHANNEL_LS
+ * - # PCM_CHANNEL_RS
+ * - # PCM_CHANNEL_LFE
+ */
+
+};
+struct asm_adpcm_cfg {
+ u16 ch_cfg;
+ u16 bits_per_sample;
+ u32 sample_rate;
+ u32 block_size;
+};
+
+struct asm_yadpcm_cfg {
+ u16 ch_cfg;
+ u16 bits_per_sample;
+ u32 sample_rate;
+};
+
+struct asm_midi_cfg {
+ u32 nMode;
+};
+
+struct asm_wma_cfg {
+ u16 format_tag;
+ u16 ch_cfg;
+ u32 sample_rate;
+ u32 avg_bytes_per_sec;
+ u16 block_align;
+ u16 valid_bits_per_sample;
+ u32 ch_mask;
+ u16 encode_opt;
+ u16 adv_encode_opt;
+ u32 adv_encode_opt2;
+ u32 drc_peak_ref;
+ u32 drc_peak_target;
+ u32 drc_ave_ref;
+ u32 drc_ave_target;
+};
+
+struct asm_wmapro_cfg {
+ u16 format_tag;
+ u16 ch_cfg;
+ u32 sample_rate;
+ u32 avg_bytes_per_sec;
+ u16 block_align;
+ u16 valid_bits_per_sample;
+ u32 ch_mask;
+ u16 encode_opt;
+ u16 adv_encode_opt;
+ u32 adv_encode_opt2;
+ u32 drc_peak_ref;
+ u32 drc_peak_target;
+ u32 drc_ave_ref;
+ u32 drc_ave_target;
+};
+
+struct asm_aac_cfg {
+ u16 format;
+ u16 aot;
+ u16 ep_config;
+ u16 section_data_resilience;
+ u16 scalefactor_data_resilience;
+ u16 spectral_data_resilience;
+ u16 ch_cfg;
+ u16 reserved;
+ u32 sample_rate;
+};
+
+struct asm_amrwbplus_cfg {
+ u32 size_bytes;
+ u32 version;
+ u32 num_channels;
+ u32 amr_band_mode;
+ u32 amr_dtx_mode;
+ u32 amr_frame_fmt;
+ u32 amr_lsf_idx;
+};
+
+struct asm_flac_cfg {
+ u16 stream_info_present;
+ u16 min_blk_size;
+ u16 max_blk_size;
+ u16 ch_cfg;
+ u16 sample_size;
+ u16 sample_rate;
+ u16 md5_sum;
+ u32 ext_sample_rate;
+ u32 min_frame_size;
+ u32 max_frame_size;
+};
+
+struct asm_vorbis_cfg {
+ u32 ch_cfg;
+ u32 bit_rate;
+ u32 min_bit_rate;
+ u32 max_bit_rate;
+ u16 bit_depth_pcm_sample;
+ u16 bit_stream_format;
+};
+
+struct asm_aac_read_cfg {
+ u32 bitrate;
+ u32 enc_mode;
+ u16 format;
+ u16 ch_cfg;
+ u32 sample_rate;
+};
+
+struct asm_amrnb_read_cfg {
+ u16 mode;
+ u16 dtx_mode;
+};
+
+struct asm_amrwb_read_cfg {
+ u16 mode;
+ u16 dtx_mode;
+};
+
+struct asm_evrc_read_cfg {
+ u16 max_rate;
+ u16 min_rate;
+ u16 rate_modulation_cmd;
+ u16 reserved;
+};
+
+struct asm_qcelp13_read_cfg {
+ u16 max_rate;
+ u16 min_rate;
+ u16 reduced_rate_level;
+ u16 rate_modulation_cmd;
+};
+
+struct asm_sbc_read_cfg {
+ u32 subband;
+ u32 block_len;
+ u32 ch_mode;
+ u32 alloc_method;
+ u32 bit_rate;
+ u32 sample_rate;
+};
+
+struct asm_sbc_bitrate {
+ u32 bitrate;
+};
+
+struct asm_immed_decode {
+ u32 mode;
+};
+
+struct asm_sbr_ps {
+ u32 enable;
+};
+
+struct asm_dual_mono {
+ u16 sce_left;
+ u16 sce_right;
+};
+
+struct asm_dec_chan_map {
+ u32 num_channels; /* Number of decoder output
+ * channels. A value of 0
+ * indicates native channel
+ * mapping, which is valid
+ * only for NT mode. This
+ * means the output of the
+ * decoder is to be preserved
+ * as is.
+ */
+
+ u8 channel_mapping[MAX_CHAN_MAP_CHANNELS];/* Channel array of size
+ * num_channels. It can grow
+ * till MAX_CHAN_MAP_CHANNELS.
+ * Channel[i] mapping
+ * describes channel I inside
+ * the decoder output buffer.
+ * Valid channel mapping
+ * values are to be present at
+ * the beginning of the array.
+ * All remaining elements of
+ * the array are to be filled
+ * with PCM_CHANNEL_NULL.
+ */
+};
+
+struct asm_encode_cfg_blk {
+ u32 frames_per_buf;
+ u32 format_id;
+ u32 cfg_size;
+ union {
+ struct asm_pcm_cfg pcm;
+ struct asm_aac_read_cfg aac;
+ struct asm_amrnb_read_cfg amrnb;
+ struct asm_evrc_read_cfg evrc;
+ struct asm_qcelp13_read_cfg qcelp13;
+ struct asm_sbc_read_cfg sbc;
+ struct asm_amrwb_read_cfg amrwb;
+ struct asm_multi_channel_pcm_fmt_blk mpcm;
+ struct asm_dts_enc_cfg dts;
+ } __packed cfg;
+};
+
+struct asm_frame_meta_info {
+ u32 offset_to_frame;
+ u32 frame_size;
+ u32 encoded_pcm_samples;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 nflags;
+};
+
+/* Stream level commands */
+#define ASM_STREAM_CMD_OPEN_READ 0x00010BCB
+#define ASM_STREAM_CMD_OPEN_READ_V2_1 0x00010DB2
+struct asm_stream_cmd_open_read {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 src_endpoint;
+ u32 pre_proc_top;
+ u32 format;
+} __packed;
+
+struct asm_stream_cmd_open_read_v2_1 {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 src_endpoint;
+ u32 pre_proc_top;
+ u32 format;
+ u16 bits_per_sample;
+ u16 reserved;
+} __packed;
+
+/* Supported formats */
+#define LINEAR_PCM 0x00010BE5
+#define DTMF 0x00010BE6
+#define ADPCM 0x00010BE7
+#define YADPCM 0x00010BE8
+#define MP3 0x00010BE9
+#define MPEG4_AAC 0x00010BEA
+#define AMRNB_FS 0x00010BEB
+#define AMRWB_FS 0x00010BEC
+#define V13K_FS 0x00010BED
+#define EVRC_FS 0x00010BEE
+#define EVRCB_FS 0x00010BEF
+#define EVRCWB_FS 0x00010BF0
+#define MIDI 0x00010BF1
+#define SBC 0x00010BF2
+#define WMA_V10PRO 0x00010BF3
+#define WMA_V9 0x00010BF4
+#define AMR_WB_PLUS 0x00010BF5
+#define AC3_DECODER 0x00010BF6
+#define EAC3_DECODER 0x00010C3C
+#define DTS 0x00010D88
+#define DTS_LBR 0x00010DBB
+#define MP2 0x00010DBE
+#define ATRAC 0x00010D89
+#define MAT 0x00010D8A
+#define G711_ALAW_FS 0x00010BF7
+#define G711_MLAW_FS 0x00010BF8
+#define G711_PCM_FS 0x00010BF9
+#define MPEG4_MULTI_AAC 0x00010D86
+#define US_POINT_EPOS_FORMAT 0x00012310
+#define US_RAW_FORMAT 0x0001127C
+#define US_PROX_FORMAT 0x0001272B
+#define MULTI_CHANNEL_PCM 0x00010C66
+
+#define ASM_ENCDEC_SBCRATE 0x00010C13
+#define ASM_ENCDEC_IMMDIATE_DECODE 0x00010C14
+#define ASM_ENCDEC_CFG_BLK 0x00010C2C
+
+#define ASM_ENCDEC_SBCRATE 0x00010C13
+#define ASM_ENCDEC_IMMDIATE_DECODE 0x00010C14
+#define ASM_ENCDEC_CFG_BLK 0x00010C2C
+
+#define ASM_STREAM_CMD_OPEN_READ_COMPRESSED 0x00010D95
+struct asm_stream_cmd_open_read_compressed {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 frame_per_buf;
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_WRITE 0x00010BCA
+#define ASM_STREAM_CMD_OPEN_WRITE_V2_1 0x00010DB1
+struct asm_stream_cmd_open_write {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u16 sink_endpoint;
+ u16 stream_handle;
+ u32 post_proc_top;
+ u32 format;
+} __packed;
+
+#define IEC_61937_MASK 0x00000001
+#define IEC_60958_MASK 0x00000002
+
+#define ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED 0x00010D84
+struct asm_stream_cmd_open_write_compressed {
+ struct apr_hdr hdr;
+ u32 flags;
+ u32 format;
+} __packed;
+#define ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK 0x00010DBA
+struct asm_stream_cmd_open_transcode_loopback {
+ struct apr_hdr hdr;
+ uint32_t mode_flags;
+ /*
+ * All bits are reserved. Clients must set them to zero.
+ */
+
+ uint32_t src_format_id;
+ /*
+ * Specifies the media format of the input audio stream.
+ *
+ * Supported values:
+ * - #ASM_MEDIA_FMT_LINEAR_PCM
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM
+ */
+
+ uint32_t sink_format_id;
+ /*
+ * Specifies the media format of the output stream.
+ *
+ * Supported values:
+ * - #ASM_MEDIA_FMT_LINEAR_PCM
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM
+ * - #ASM_MEDIA_FMT_DTS
+ */
+
+ uint32_t audproc_topo_id;
+ /*
+ * Postprocessing topology ID, which specifies the topology (order of
+ * processing) of postprocessing algorithms.
+ *
+ * Supported values:
+ * - #ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT
+ * - #ASM_STREAM_POSTPROC_TOPO_ID_PEAKMETER
+ * - #ASM_STREAM_POSTPROC_TOPO_ID_NONE
+ * - #ASM_STREAM_POSTPROC_TOPO_ID_MCH_PEAK_VOL
+ */
+
+ uint16_t src_endpoint_type;
+ /*
+ * Specifies the source endpoint that provides the input samples.
+ *
+ * Supported values:
+ * - 0 -- Tx device matrix or stream router
+ * (gateway to the hardware ports)
+ * - All other values are reserved
+ *
+ * Clients must set this field to zero. Otherwise, an error is returned.
+ */
+
+ uint16_t sink_endpoint_type;
+ /*
+ * Specifies the sink endpoint type.
+ *
+ * Supported values:
+ * - 0 -- Rx device matrix or stream router
+ * (gateway to the hardware ports)
+ * - All other values are reserved
+ *
+ * Clients must set this field to zero. Otherwise, an error is returned.
+ */
+
+ uint16_t bits_per_sample;
+ /*
+ * Number of bits per sample processed by the ASM modules.
+ * Supported values: 16, 24
+ */
+
+ uint16_t reserved;
+ /*
+ * This field must be set to zero.
+ */
+} __packed;
+
+/*
+ * ID of the DTS mix LFE channel to front channels parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ * asm_dts_generic_param_t
+ * ASM_PARAM_ID_DTS_MIX_LFE_TO_FRONT
+ */
+#define ASM_PARAM_ID_DTS_MIX_LFE_TO_FRONT 0x00010DB6
+
+/*
+ * ID of the DTS DRC ratio parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ * asm_dts_generic_param_t
+ * ASM_PARAM_ID_DTS_DRC_RATIO
+ */
+#define ASM_PARAM_ID_DTS_DRC_RATIO 0x00010DB7
+
+/*
+ * ID of the DTS enable dialog normalization parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ *
+ * asm_dts_generic_param_t
+ * ASM_PARAM_ID_DTS_ENABLE_DIALNORM
+ */
+#define ASM_PARAM_ID_DTS_ENABLE_DIALNORM 0x00010DB8
+
+/*
+ * ID of the DTS enable parse REV2AUX parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ * asm_dts_generic_param_t
+ * ASM_PARAM_ID_DTS_ENABLE_PARSE_REV2AUX
+ */
+#define ASM_PARAM_ID_DTS_ENABLE_PARSE_REV2AUX 0x00010DB9
+
+struct asm_dts_generic_param {
+ int32_t generic_parameter;
+ /*
+ * #ASM_PARAM_ID_DTS_MIX_LFE_TO_FRONT:
+ * - if enabled, mixes LFE channel to front
+ * while downmixing (if necessary)
+ * - Supported values: 1-> enable, 0-> disable
+ * - Default: disabled
+ *
+ * #ASM_PARAM_ID_DTS_DRC_RATIO:
+ * - percentage of DRC ratio.
+ * - Supported values: 0-100
+ * - Default: 0, DRC is disabled.
+ *
+ * #ASM_PARAM_ID_DTS_ENABLE_DIALNORM:
+ * - flag to enable dialog normalization post processing.
+ * - Supported values: 1-> enable, 0-> disable.
+ * - Default: enabled.
+ *
+ * #ASM_PARAM_ID_DTS_ENABLE_PARSE_REV2AUX:
+ * - flag to enable parsing of rev2aux chunk in the bitstream.
+ * This chunk contains broadcast metadata.
+ * - Supported values: 1-> enable, 0-> disable.
+ * - Default: disabled.
+ */
+};
+
+struct asm_stream_cmd_dts_dec_param {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_dts_generic_param generic_param;
+} __packed;
+
+
+#define ASM_STREAM_CMD_OPEN_READWRITE 0x00010BCC
+
+struct asm_stream_cmd_open_read_write {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 post_proc_top;
+ u32 write_format;
+ u32 read_format;
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_LOOPBACK 0x00010D6E
+struct asm_stream_cmd_open_loopback {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+ u16 src_endpointype;
+ /* Endpoint type. 0 = Tx Matrix */
+ u16 sink_endpointype;
+ /* Endpoint type. 0 = Rx Matrix */
+ u32 postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+} __packed;
+
+#define ADM_CMD_CONNECT_AFE_PORT 0x00010320
+#define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
+
+struct adm_cmd_connect_afe_port {
+ struct apr_hdr hdr;
+ u8 mode; /*mode represent the interface is for RX or TX*/
+ u8 session_id; /*ASM session ID*/
+ u16 afe_port_id;
+} __packed;
+
+#define ADM_CMD_CONNECT_AFE_PORT_V2 0x00010332
+
+struct adm_cmd_connect_afe_port_v2 {
+ struct apr_hdr hdr;
+ u8 mode; /*mode represent the interface is for RX or TX*/
+ u8 session_id; /*ASM session ID*/
+ u16 afe_port_id;
+ u32 num_channels;
+ u32 sampling_rate;
+} __packed;
+
+#define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10
+#define ASM_STREAM_CMD_GET_ENCDEC_PARAM 0x00010C11
+#define ASM_ENCDEC_CFG_BLK_ID 0x00010C2C
+#define ASM_ENABLE_SBR_PS 0x00010C63
+#define ASM_CONFIGURE_DUAL_MONO 0x00010C64
+struct asm_stream_cmd_encdec_cfg_blk {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_encode_cfg_blk enc_blk;
+} __packed;
+
+struct asm_stream_cmd_encdec_sbc_bitrate {
+ struct apr_hdr hdr;
+ u32 param_id;
+ struct asm_sbc_bitrate sbc_bitrate;
+} __packed;
+
+struct asm_stream_cmd_encdec_immed_decode {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_immed_decode dec;
+} __packed;
+
+struct asm_stream_cmd_encdec_sbr {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_sbr_ps sbr_ps;
+} __packed;
+
+struct asm_stream_cmd_encdec_dualmono {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_dual_mono channel_map;
+} __packed;
+
+#define ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG 0x00010DD8
+
+/* Structure for AAC decoder stereo coefficient setting. */
+
+struct asm_aac_stereo_mix_coeff_selection_param {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ u32 aac_stereo_mix_coeff_flag;
+} __packed;
+
+#define ASM_ENCDEC_DEC_CHAN_MAP 0x00010D82
+struct asm_stream_cmd_encdec_channelmap {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_dec_chan_map chan_map;
+} __packed;
+
+#define ASM_STREAM_CMD_ADJUST_SAMPLES 0x00010C0A
+struct asm_stream_cmd_adjust_samples {
+ struct apr_hdr hdr;
+ u16 nsamples;
+ u16 reserved;
+} __packed;
+
+#define ASM_STREAM_CMD_TAP_POPP_PCM 0x00010BF9
+struct asm_stream_cmd_tap_popp_pcm {
+ struct apr_hdr hdr;
+ u16 enable;
+ u16 reserved;
+ u32 module_id;
+} __packed;
+
+/* Session Level commands */
+#define ASM_SESSION_CMD_MEMORY_MAP 0x00010C32
+struct asm_stream_cmd_memory_map {
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 buf_size;
+ u16 mempool_id;
+ u16 reserved;
+} __packed;
+
+#define ASM_SESSION_CMD_MEMORY_UNMAP 0x00010C33
+struct asm_stream_cmd_memory_unmap {
+ struct apr_hdr hdr;
+ u32 buf_add;
+} __packed;
+
+#define ASM_SESSION_CMD_MEMORY_MAP_REGIONS 0x00010C45
+struct asm_memory_map_regions {
+ u32 phys;
+ u32 buf_size;
+} __packed;
+
+struct asm_stream_cmd_memory_map_regions {
+ struct apr_hdr hdr;
+ u16 mempool_id;
+ u16 nregions;
+} __packed;
+
+#define ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS 0x00010C46
+struct asm_memory_unmap_regions {
+ u32 phys;
+} __packed;
+
+struct asm_stream_cmd_memory_unmap_regions {
+ struct apr_hdr hdr;
+ u16 nregions;
+ u16 reserved;
+} __packed;
+
+#define ASM_SESSION_CMD_RUN 0x00010BD2
+struct asm_stream_cmd_run {
+ struct apr_hdr hdr;
+ u32 flags;
+ u32 msw_ts;
+ u32 lsw_ts;
+} __packed;
+
+/* Session level events */
+#define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
+struct asm_stream_cmd_reg_rx_underflow_event {
+ struct apr_hdr hdr;
+ u16 enable;
+ u16 reserved;
+} __packed;
+
+#define ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS 0x00010BD6
+struct asm_stream_cmd_reg_tx_overflow_event {
+ struct apr_hdr hdr;
+ u16 enable;
+ u16 reserved;
+} __packed;
+
+/* Data Path commands */
+#define ASM_DATA_CMD_WRITE 0x00010BD9
+struct asm_stream_cmd_write {
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 avail_bytes;
+ u32 uid;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 uflags;
+} __packed;
+
+#define ASM_DATA_CMD_READ 0x00010BDA
+struct asm_stream_cmd_read {
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 buf_size;
+ u32 uid;
+} __packed;
+
+#define ASM_DATA_CMD_READ_COMPRESSED 0x00010DBF
+struct asm_stream_cmd_read_compressed {
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 buf_size;
+ u32 uid;
+} __packed;
+
+#define ASM_DATA_CMD_MEDIA_FORMAT_UPDATE 0x00010BDC
+#define ASM_DATA_EVENT_ENC_SR_CM_NOTIFY 0x00010BDE
+struct asm_stream_media_format_update {
+ struct apr_hdr hdr;
+ u32 format;
+ u32 cfg_size;
+ union {
+ struct asm_pcm_cfg pcm_cfg;
+ struct asm_adpcm_cfg adpcm_cfg;
+ struct asm_yadpcm_cfg yadpcm_cfg;
+ struct asm_midi_cfg midi_cfg;
+ struct asm_wma_cfg wma_cfg;
+ struct asm_wmapro_cfg wmapro_cfg;
+ struct asm_aac_cfg aac_cfg;
+ struct asm_flac_cfg flac_cfg;
+ struct asm_vorbis_cfg vorbis_cfg;
+ struct asm_multi_channel_pcm_fmt_blk multi_ch_pcm_cfg;
+ struct asm_amrwbplus_cfg amrwbplus_cfg;
+ } __packed write_cfg;
+} __packed;
+
+
+/* Command Responses */
+#define ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM 0x00010C12
+struct asm_stream_cmdrsp_get_readwrite_param {
+ struct apr_hdr hdr;
+ u32 status;
+ u32 param_id;
+ u16 param_size;
+ u16 padding;
+ union {
+ struct asm_sbc_bitrate sbc_bitrate;
+ struct asm_immed_decode aac_dec;
+ } __packed read_write_cfg;
+} __packed;
+
+
+#define ASM_SESSION_CMDRSP_GET_SESSION_TIME 0x00010BD8
+struct asm_stream_cmdrsp_get_session_time {
+ struct apr_hdr hdr;
+ u32 status;
+ u32 msw_ts;
+ u32 lsw_ts;
+} __packed;
+
+#define ASM_DATA_EVENT_WRITE_DONE 0x00010BDF
+struct asm_data_event_write_done {
+ u32 buf_add;
+ u32 status;
+} __packed;
+
+#define ASM_DATA_EVENT_READ_DONE 0x00010BE0
+struct asm_data_event_read_done {
+ u32 status;
+ u32 buffer_add;
+ u32 enc_frame_size;
+ u32 offset;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 flags;
+ u32 num_frames;
+ u32 id;
+} __packed;
+
+#define ASM_DATA_EVENT_READ_COMPRESSED_DONE 0x00010DC0
+struct asm_data_event_read_compressed_done {
+ u32 status;
+ u32 buffer_add;
+ u32 enc_frame_size;
+ u32 offset;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 flags;
+ u32 num_frames;
+ u32 id;
+} __packed;
+
+#define ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY 0x00010C65
+struct asm_data_event_sr_cm_change_notify {
+ u32 sample_rate;
+ u16 no_of_channels;
+ u16 reserved;
+ u8 channel_map[8];
+} __packed;
+
+/* service level events */
+
+#define ASM_SERVICE_CMDRSP_GET_STREAM_HANDLES 0x00010C1B
+struct asm_svc_cmdrsp_get_strm_handles {
+ struct apr_hdr hdr;
+ u32 num_handles;
+ u32 stream_handles;
+} __packed;
+
+
+#define ASM_SERVICE_CMDRSP_GET_WALLCLOCK_TIME 0x00010C1A
+struct asm_svc_cmdrsp_get_wallclock_time {
+ struct apr_hdr hdr;
+ u32 status;
+ u32 msw_ts;
+ u32 lsw_ts;
+} __packed;
+
+/* Error code */
+#define ADSP_EOK 0x00000000 /* Success / completed / no errors. */
+#define ADSP_EFAILED 0x00000001 /* General failure. */
+#define ADSP_EBADPARAM 0x00000002 /* Bad operation parameter(s). */
+#define ADSP_EUNSUPPORTED 0x00000003 /* Unsupported routine/operation. */
+#define ADSP_EVERSION 0x00000004 /* Unsupported version. */
+#define ADSP_EUNEXPECTED 0x00000005 /* Unexpected problem encountered. */
+#define ADSP_EPANIC 0x00000006 /* Unhandled problem occurred. */
+#define ADSP_ENORESOURCE 0x00000007 /* Unable to allocate resource(s). */
+#define ADSP_EHANDLE 0x00000008 /* Invalid handle. */
+#define ADSP_EALREADY 0x00000009 /* Operation is already processed. */
+#define ADSP_ENOTREADY 0x0000000A /* Operation not ready to be processed*/
+#define ADSP_EPENDING 0x0000000B /* Operation is pending completion*/
+#define ADSP_EBUSY 0x0000000C /* Operation could not be accepted or
+ * processed.
+ */
+#define ADSP_EABORTED 0x0000000D /* Operation aborted due to an error. */
+#define ADSP_EPREEMPTED 0x0000000E /* Operation preempted by higher priority*/
+#define ADSP_ECONTINUE 0x0000000F /* Operation requests intervention
+ * to complete.
+ */
+#define ADSP_EIMMEDIATE 0x00000010 /* Operation requests immediate
+ * intervention to complete.
+ */
+#define ADSP_ENOTIMPL 0x00000011 /* Operation is not implemented. */
+#define ADSP_ENEEDMORE 0x00000012 /* Operation needs more data or resources*/
+
+/* SRS TRUMEDIA GUIDS */
+#define SRS_TRUMEDIA_TOPOLOGY_ID 0x00010D90
+#define SRS_TRUMEDIA_MODULE_ID 0x10005010
+#define SRS_TRUMEDIA_PARAMS 0x10005011
+#define SRS_TRUMEDIA_PARAMS_WOWHD 0x10005012
+#define SRS_TRUMEDIA_PARAMS_CSHP 0x10005013
+#define SRS_TRUMEDIA_PARAMS_HPF 0x10005014
+#define SRS_TRUMEDIA_PARAMS_PEQ 0x10005015
+#define SRS_TRUMEDIA_PARAMS_HL 0x10005016
+
+/* SRS STUDIO SOUND 3D GUIDS */
+#define SRS_SS3D_TOPOLOGY_ID 0x00010720
+#define SRS_SS3D_MODULE_ID 0x10005020
+#define SRS_SS3D_PARAMS 0x10005021
+#define SRS_SS3D_PARAMS_CTRL 0x10005022
+#define SRS_SS3D_PARAMS_FILTER 0x10005023
+
+/* SRS ALSA CMD MASKS */
+#define SRS_CMD_UPLOAD 0x7FFF0000
+#define SRS_PARAM_INDEX_MASK 0x80000000
+#define SRS_PARAM_OFFSET_MASK 0x3FFF0000
+#define SRS_PARAM_VALUE_MASK 0x0000FFFF
+
+/* SRS TRUMEDIA start */
+#define SRS_ID_GLOBAL 0x00000001
+#define SRS_ID_WOWHD 0x00000002
+#define SRS_ID_CSHP 0x00000003
+#define SRS_ID_HPF 0x00000004
+#define SRS_ID_PEQ 0x00000005
+#define SRS_ID_HL 0x00000006
+
+struct srs_trumedia_params_GLOBAL {
+ uint8_t v1;
+ uint8_t v2;
+ uint8_t v3;
+ uint8_t v4;
+ uint8_t v5;
+ uint8_t v6;
+ uint8_t v7;
+ uint8_t v8;
+} __packed;
+
+struct srs_trumedia_params_WOWHD {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v5;
+ uint16_t v6;
+ uint16_t v7;
+ uint16_t v8;
+ uint16_t v____A1;
+ uint32_t v9;
+ uint16_t v10;
+ uint16_t v11;
+ uint32_t v12[16];
+} __packed;
+
+struct srs_trumedia_params_CSHP {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v5;
+ uint16_t v6;
+ uint16_t v____A1;
+ uint32_t v7;
+ uint16_t v8;
+ uint16_t v9;
+ uint32_t v10[16];
+} __packed;
+
+struct srs_trumedia_params_HPF {
+ uint32_t v1;
+ uint32_t v2[26];
+} __packed;
+
+struct srs_trumedia_params_PEQ {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v____A1;
+ uint32_t v5[26];
+ uint32_t v6[26];
+} __packed;
+
+struct srs_trumedia_params_HL {
+ uint16_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v____A1;
+ int32_t v4;
+ uint32_t v5;
+ uint16_t v6;
+ uint16_t v____A2;
+ uint32_t v7;
+} __packed;
+
+struct srs_trumedia_params {
+ struct srs_trumedia_params_GLOBAL global;
+ struct srs_trumedia_params_WOWHD wowhd;
+ struct srs_trumedia_params_CSHP cshp;
+ struct srs_trumedia_params_HPF hpf;
+ struct srs_trumedia_params_PEQ peq;
+ struct srs_trumedia_params_HL hl;
+} __packed;
+
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
+/* SRS TruMedia end */
+
+/* SRS Studio Sound 3D start */
+#define SRS_ID_SS3D_GLOBAL 0x00000001
+#define SRS_ID_SS3D_CTRL 0x00000002
+#define SRS_ID_SS3D_FILTER 0x00000003
+
+struct srs_SS3D_params_GLOBAL {
+ uint8_t v1;
+ uint8_t v2;
+ uint8_t v3;
+ uint8_t v4;
+ uint8_t v5;
+ uint8_t v6;
+ uint8_t v7;
+ uint8_t v8;
+} __packed;
+
+struct srs_SS3D_ctrl_params {
+ uint8_t v[236];
+} __packed;
+
+struct srs_SS3D_filter_params {
+ uint8_t v[28 + 2752];
+} __packed;
+
+struct srs_SS3D_params {
+ struct srs_SS3D_params_GLOBAL global;
+ struct srs_SS3D_ctrl_params ss3d;
+ struct srs_SS3D_filter_params ss3d_f;
+} __packed;
+
+int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
+/* SRS Studio Sound 3D end */
+#endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/audio_cal_utils.h b/include/sound/audio_cal_utils.h
new file mode 100644
index 0000000..b28b3bd
--- /dev/null
+++ b/include/sound/audio_cal_utils.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _AUDIO_CAL_UTILS_H
+#define _AUDIO_CAL_UTILS_H
+
+#include <linux/msm_ion.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/msm_audio_calibration.h>
+#include "audio_calibration.h"
+
+struct cal_data {
+ size_t size;
+ void *kvaddr;
+ phys_addr_t paddr;
+};
+
+struct mem_map_data {
+ size_t map_size;
+ int32_t q6map_handle;
+ int32_t ion_map_handle;
+ struct ion_client *ion_client;
+ struct ion_handle *ion_handle;
+};
+
+struct cal_block_data {
+ size_t client_info_size;
+ void *client_info;
+ void *cal_info;
+ struct list_head list;
+ struct cal_data cal_data;
+ struct mem_map_data map_data;
+ int32_t buffer_number;
+};
+
+struct cal_util_callbacks {
+ int (*map_cal)
+ (int32_t cal_type, struct cal_block_data *cal_block);
+ int (*unmap_cal)
+ (int32_t cal_type, struct cal_block_data *cal_block);
+ bool (*match_block)
+ (struct cal_block_data *cal_block, void *user_data);
+};
+
+struct cal_type_info {
+ struct audio_cal_reg reg;
+ struct cal_util_callbacks cal_util_callbacks;
+};
+
+struct cal_type_data {
+ struct cal_type_info info;
+ struct mutex lock;
+ struct list_head cal_blocks;
+};
+
+
+/* to register & degregister with cal util driver */
+int cal_utils_create_cal_types(int num_cal_types,
+ struct cal_type_data **cal_type,
+ struct cal_type_info *info);
+void cal_utils_destroy_cal_types(int num_cal_types,
+ struct cal_type_data **cal_type);
+
+/* common functions for callbacks */
+int cal_utils_alloc_cal(size_t data_size, void *data,
+ struct cal_type_data *cal_type,
+ size_t client_info_size, void *client_info);
+int cal_utils_dealloc_cal(size_t data_size, void *data,
+ struct cal_type_data *cal_type);
+int cal_utils_set_cal(size_t data_size, void *data,
+ struct cal_type_data *cal_type,
+ size_t client_info_size, void *client_info);
+
+/* use for SSR */
+void cal_utils_clear_cal_block_q6maps(int num_cal_types,
+ struct cal_type_data **cal_type);
+
+
+/* common matching functions used to add blocks */
+bool cal_utils_match_buf_num(struct cal_block_data *cal_block,
+ void *user_data);
+
+/* common matching functions to find cal blocks */
+struct cal_block_data *cal_utils_get_only_cal_block(
+ struct cal_type_data *cal_type);
+
+/* Size of calibration specific data */
+size_t get_cal_info_size(int32_t cal_type);
+size_t get_user_cal_type_size(int32_t cal_type);
+
+/* Version of the cal type*/
+int32_t cal_utils_get_cal_type_version(void *cal_type_data);
+#endif
diff --git a/include/sound/audio_calibration.h b/include/sound/audio_calibration.h
new file mode 100644
index 0000000..5decff9
--- /dev/null
+++ b/include/sound/audio_calibration.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _AUDIO_CALIBRATION_H
+#define _AUDIO_CALIBRATION_H
+
+#include <linux/msm_audio_calibration.h>
+
+/* Used by driver in buffer_number field to notify client
+ * To update all blocks, for example: freeing all memory
+ */
+#define ALL_CAL_BLOCKS -1
+
+
+struct audio_cal_callbacks {
+ int (*alloc)(int32_t cal_type, size_t data_size, void *data);
+ int (*dealloc)(int32_t cal_type, size_t data_size, void *data);
+ int (*pre_cal)(int32_t cal_type, size_t data_size, void *data);
+ int (*set_cal)(int32_t cal_type, size_t data_size, void *data);
+ int (*get_cal)(int32_t cal_type, size_t data_size, void *data);
+ int (*post_cal)(int32_t cal_type, size_t data_size, void *data);
+};
+
+struct audio_cal_reg {
+ int32_t cal_type;
+ struct audio_cal_callbacks callbacks;
+};
+
+int audio_cal_register(int num_cal_types, struct audio_cal_reg *reg_data);
+int audio_cal_deregister(int num_cal_types, struct audio_cal_reg *reg_data);
+
+#endif
diff --git a/include/sound/audio_slimslave.h b/include/sound/audio_slimslave.h
new file mode 100644
index 0000000..316a557
--- /dev/null
+++ b/include/sound/audio_slimslave.h
@@ -0,0 +1,18 @@
+#ifndef __AUDIO_SLIMSLAVE_H__
+#define __AUDIO_SLIMSLAVE_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define AUDIO_SLIMSLAVE_IOCTL_NAME "audio_slimslave"
+#define AUDIO_SLIMSLAVE_MAGIC 'S'
+
+#define AUDIO_SLIMSLAVE_IOCTL_UNVOTE _IO(AUDIO_SLIMSLAVE_MAGIC, 0x00)
+#define AUDIO_SLIMSLAVE_IOCTL_VOTE _IO(AUDIO_SLIMSLAVE_MAGIC, 0x01)
+
+enum {
+ AUDIO_SLIMSLAVE_UNVOTE,
+ AUDIO_SLIMSLAVE_VOTE
+};
+
+#endif
diff --git a/include/sound/cpe_cmi.h b/include/sound/cpe_cmi.h
new file mode 100644
index 0000000..cbf83e7
--- /dev/null
+++ b/include/sound/cpe_cmi.h
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2014-2016, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CPE_CMI_H__
+#define __CPE_CMI_H__
+
+#include <linux/types.h>
+
+#define CPE_AFE_PORT_1_TX 1
+#define CPE_AFE_PORT_3_TX 3
+#define CPE_AFE_PORT_ID_2_OUT 0x02
+#define CMI_INBAND_MESSAGE_SIZE 127
+
+/*
+ * Multiple mad types can be supported at once.
+ * these values can be OR'ed to form the set of
+ * supported mad types
+ */
+#define MAD_TYPE_AUDIO (1 << 0)
+#define MAD_TYPE_BEACON (1 << 1)
+#define MAD_TYPE_ULTRASND (1 << 2)
+
+/* Core service command opcodes */
+#define CPE_CORE_SVC_CMD_SHARED_MEM_ALLOC (0x3001)
+#define CPE_CORE_SVC_CMDRSP_SHARED_MEM_ALLOC (0x3002)
+#define CPE_CORE_SVC_CMD_SHARED_MEM_DEALLOC (0x3003)
+#define CPE_CORE_SVC_CMD_DRAM_ACCESS_REQ (0x3004)
+#define CPE_CORE_SVC_EVENT_SYSTEM_BOOT (0x3005)
+/* core service command opcodes for WCD9335 */
+#define CPE_CORE_SVC_CMD_CFG_CLK_PLAN (0x3006)
+#define CPE_CORE_SVC_CMD_CLK_FREQ_REQUEST (0x3007)
+
+#define CPE_BOOT_SUCCESS 0x00
+#define CPE_BOOT_FAILED 0x01
+
+#define CPE_CORE_VERSION_SYSTEM_BOOT_EVENT 0x01
+
+/* LSM Service command opcodes */
+#define CPE_LSM_SESSION_CMD_OPEN_TX (0x2000)
+#define CPE_LSM_SESSION_CMD_SET_PARAMS (0x2001)
+#define CPE_LSM_SESSION_CMD_REGISTER_SOUND_MODEL (0x2002)
+#define CPE_LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL (0x2003)
+#define CPE_LSM_SESSION_CMD_START (0x2004)
+#define CPE_LSM_SESSION_CMD_STOP (0x2005)
+#define CPE_LSM_SESSION_EVENT_DETECTION_STATUS_V2 (0x2006)
+#define CPE_LSM_SESSION_CMD_CLOSE_TX (0x2007)
+#define CPE_LSM_SESSION_CMD_SHARED_MEM_ALLOC (0x2008)
+#define CPE_LSM_SESSION_CMDRSP_SHARED_MEM_ALLOC (0x2009)
+#define CPE_LSM_SESSION_CMD_SHARED_MEM_DEALLOC (0x200A)
+#define CPE_LSM_SESSION_CMD_TX_BUFF_OUTPUT_CONFIG (0x200f)
+#define CPE_LSM_SESSION_CMD_OPEN_TX_V2 (0x200D)
+#define CPE_LSM_SESSION_CMD_SET_PARAMS_V2 (0x200E)
+
+/* LSM Service module and param IDs */
+#define CPE_LSM_MODULE_ID_VOICE_WAKEUP (0x00012C00)
+#define CPE_LSM_MODULE_ID_VOICE_WAKEUP_V2 (0x00012C0D)
+#define CPE_LSM_MODULE_FRAMEWORK (0x00012C0E)
+
+#define CPE_LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD (0x00012C01)
+#define CPE_LSM_PARAM_ID_OPERATION_MODE (0x00012C02)
+#define CPE_LSM_PARAM_ID_GAIN (0x00012C03)
+#define CPE_LSM_PARAM_ID_CONNECT_TO_PORT (0x00012C04)
+#define CPE_LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS (0x00012C07)
+
+/* LSM LAB command opcodes */
+#define CPE_LSM_SESSION_CMD_EOB 0x0000200B
+#define CPE_LSM_MODULE_ID_LAB 0x00012C08
+/* used for enable/disable lab*/
+#define CPE_LSM_PARAM_ID_LAB_ENABLE 0x00012C09
+/* used for T in LAB config DSP internal buffer*/
+#define CPE_LSM_PARAM_ID_LAB_CONFIG 0x00012C0A
+#define CPE_LSM_PARAM_ID_REGISTER_SOUND_MODEL (0x00012C14)
+#define CPE_LSM_PARAM_ID_DEREGISTER_SOUND_MODEL (0x00012C15)
+#define CPE_LSM_PARAM_ID_MEDIA_FMT (0x00012C1E)
+
+/* AFE Service command opcodes */
+#define CPE_AFE_PORT_CMD_START (0x1001)
+#define CPE_AFE_PORT_CMD_STOP (0x1002)
+#define CPE_AFE_PORT_CMD_SUSPEND (0x1003)
+#define CPE_AFE_PORT_CMD_RESUME (0x1004)
+#define CPE_AFE_PORT_CMD_SHARED_MEM_ALLOC (0x1005)
+#define CPE_AFE_PORT_CMDRSP_SHARED_MEM_ALLOC (0x1006)
+#define CPE_AFE_PORT_CMD_SHARED_MEM_DEALLOC (0x1007)
+#define CPE_AFE_PORT_CMD_GENERIC_CONFIG (0x1008)
+#define CPE_AFE_SVC_CMD_LAB_MODE (0x1009)
+
+/* AFE Service module and param IDs */
+#define CPE_AFE_CMD_SET_PARAM (0x1000)
+#define CPE_AFE_MODULE_ID_SW_MAD (0x0001022D)
+#define CPE_AFE_PARAM_ID_SW_MAD_CFG (0x0001022E)
+#define CPE_AFE_PARAM_ID_SVM_MODEL (0x0001022F)
+
+#define CPE_AFE_MODULE_HW_MAD (0x00010230)
+#define CPE_AFE_PARAM_ID_HW_MAD_CTL (0x00010232)
+#define CPE_AFE_PARAM_ID_HW_MAD_CFG (0x00010231)
+
+#define CPE_AFE_MODULE_AUDIO_DEV_INTERFACE (0x0001020C)
+#define CPE_AFE_PARAM_ID_GENERIC_PORT_CONFIG (0x00010253)
+
+#define CPE_CMI_BASIC_RSP_OPCODE (0x0001)
+#define CPE_HDR_MAX_PLD_SIZE (0x7F)
+
+#define CMI_OBM_FLAG_IN_BAND 0
+#define CMI_OBM_FLAG_OUT_BAND 1
+
+#define CMI_SHMEM_ALLOC_FAILED 0xff
+
+/*
+ * Future Service ID's can be added one line
+ * before the CMI_CPE_SERVICE_ID_MAX
+ */
+enum {
+ CMI_CPE_SERVICE_ID_MIN = 0,
+ CMI_CPE_CORE_SERVICE_ID,
+ CMI_CPE_AFE_SERVICE_ID,
+ CMI_CPE_LSM_SERVICE_ID,
+ CMI_CPE_SERVICE_ID_MAX,
+};
+
+#define CPE_LSM_SESSION_ID_MAX 2
+
+#define IS_VALID_SESSION_ID(s_id) \
+ (s_id <= CPE_LSM_SESSION_ID_MAX)
+
+#define IS_VALID_SERVICE_ID(s_id) \
+ (s_id > CMI_CPE_SERVICE_ID_MIN && \
+ s_id < CMI_CPE_SERVICE_ID_MAX)
+
+#define IS_VALID_PLD_SIZE(p_size) \
+ (p_size <= CPE_HDR_MAX_PLD_SIZE)
+
+#define CMI_HDR_SET_OPCODE(hdr, cmd) (hdr->opcode = cmd)
+
+
+#define CMI_HDR_SET(hdr_info, mask, shift, value) \
+ (hdr_info = (((hdr_info) & ~(mask)) | \
+ ((value << shift) & mask)))
+
+#define SVC_ID_SHIFT 4
+#define SVC_ID_MASK (0x07 << SVC_ID_SHIFT)
+
+#define SESSION_ID_SHIFT 0
+#define SESSION_ID_MASK (0x0F << SESSION_ID_SHIFT)
+
+#define PAYLD_SIZE_SHIFT 0
+#define PAYLD_SIZE_MASK (0x7F << PAYLD_SIZE_SHIFT)
+
+#define OBM_FLAG_SHIFT 7
+#define OBM_FLAG_MASK (1 << OBM_FLAG_SHIFT)
+
+#define VERSION_SHIFT 7
+#define VERSION_MASK (1 << VERSION_SHIFT)
+
+#define CMI_HDR_SET_SERVICE(hdr, s_id) \
+ CMI_HDR_SET(hdr->hdr_info, SVC_ID_MASK,\
+ SVC_ID_SHIFT, s_id)
+#define CMI_HDR_GET_SERVICE(hdr) \
+ ((hdr->hdr_info >> SVC_ID_SHIFT) & \
+ (SVC_ID_MASK >> SVC_ID_SHIFT))
+
+
+#define CMI_HDR_SET_SESSION(hdr, s_id) \
+ CMI_HDR_SET(hdr->hdr_info, SESSION_ID_MASK,\
+ SESSION_ID_SHIFT, s_id)
+
+#define CMI_HDR_GET_SESSION_ID(hdr) \
+ ((hdr->hdr_info >> SESSION_ID_SHIFT) & \
+ (SESSION_ID_MASK >> SESSION_ID_SHIFT))
+
+#define CMI_GET_HEADER(msg) ((struct cmi_hdr *)(msg))
+#define CMI_GET_PAYLOAD(msg) ((void *)(CMI_GET_HEADER(msg) + 1))
+#define CMI_GET_OPCODE(msg) (CMI_GET_HEADER(msg)->opcode)
+
+#define CMI_HDR_SET_VERSION(hdr, ver) \
+ CMI_HDR_SET(hdr->hdr_info, VERSION_MASK, \
+ VERSION_SHIFT, ver)
+
+#define CMI_HDR_SET_PAYLOAD_SIZE(hdr, p_size) \
+ CMI_HDR_SET(hdr->pld_info, PAYLD_SIZE_MASK, \
+ PAYLD_SIZE_SHIFT, p_size)
+
+#define CMI_HDR_GET_PAYLOAD_SIZE(hdr) \
+ ((hdr->pld_info >> PAYLD_SIZE_SHIFT) & \
+ (PAYLD_SIZE_MASK >> PAYLD_SIZE_SHIFT))
+
+#define CMI_HDR_SET_OBM(hdr, obm_flag) \
+ CMI_HDR_SET(hdr->pld_info, OBM_FLAG_MASK, \
+ OBM_FLAG_SHIFT, obm_flag)
+
+#define CMI_HDR_GET_OBM_FLAG(hdr) \
+ ((hdr->pld_info >> OBM_FLAG_SHIFT) & \
+ (OBM_FLAG_MASK >> OBM_FLAG_SHIFT))
+
+struct cmi_hdr {
+ /*
+ * bits 0:3 is session id
+ * bits 4:6 is service id
+ * bit 7 is the version flag
+ */
+ u8 hdr_info;
+
+ /*
+ * bits 0:6 is payload size in case of in-band message
+ * bits 0:6 is size (OBM message size)
+ * bit 7 is the OBM flag
+ */
+ u8 pld_info;
+
+ /* 16 bit command opcode */
+ u16 opcode;
+} __packed;
+
+union cpe_addr {
+ u64 msw_lsw;
+ void *kvaddr;
+} __packed;
+
+struct cmi_obm {
+ u32 version;
+ u32 size;
+ union cpe_addr data_ptr;
+ u32 mem_handle;
+} __packed;
+
+struct cmi_obm_msg {
+ struct cmi_hdr hdr;
+ struct cmi_obm pld;
+} __packed;
+
+struct cmi_core_svc_event_system_boot {
+ u8 status;
+ u8 version;
+ u16 sfr_buff_size;
+ u32 sfr_buff_address;
+} __packed;
+
+struct cmi_core_svc_cmd_shared_mem_alloc {
+ u32 size;
+} __packed;
+
+struct cmi_core_svc_cmdrsp_shared_mem_alloc {
+ u32 addr;
+} __packed;
+
+struct cmi_core_svc_cmd_clk_freq_request {
+ u32 clk_freq;
+} __packed;
+
+struct cmi_msg_transport {
+ u32 size;
+ u32 addr;
+} __packed;
+
+struct cmi_basic_rsp_result {
+ u8 status;
+} __packed;
+
+struct cpe_lsm_cmd_open_tx {
+ struct cmi_hdr hdr;
+ u16 app_id;
+ u16 reserved;
+ u32 sampling_rate;
+} __packed;
+
+struct cpe_lsm_cmd_open_tx_v2 {
+ struct cmi_hdr hdr;
+ u32 topology_id;
+} __packed;
+
+struct cpe_cmd_shmem_alloc {
+ struct cmi_hdr hdr;
+ u32 size;
+} __packed;
+
+struct cpe_cmdrsp_shmem_alloc {
+ struct cmi_hdr hdr;
+ u32 addr;
+} __packed;
+
+struct cpe_cmd_shmem_dealloc {
+ struct cmi_hdr hdr;
+ u32 addr;
+} __packed;
+
+struct cpe_lsm_event_detect_v2 {
+ struct cmi_hdr hdr;
+ u8 detection_status;
+ u8 size;
+ u8 payload[0];
+} __packed;
+
+struct cpe_lsm_psize_res {
+ u16 param_size;
+ u16 reserved;
+} __packed;
+
+union cpe_lsm_param_size {
+ u32 param_size;
+ struct cpe_lsm_psize_res sr;
+} __packed;
+
+struct cpe_param_data {
+ u32 module_id;
+ u32 param_id;
+ union cpe_lsm_param_size p_size;
+} __packed;
+
+struct cpe_lsm_param_epd_thres {
+ struct cmi_hdr hdr;
+ struct cpe_param_data param;
+ u32 minor_version;
+ u32 epd_begin;
+ u32 epd_end;
+} __packed;
+
+struct cpe_lsm_param_gain {
+ struct cmi_hdr hdr;
+ struct cpe_param_data param;
+ u32 minor_version;
+ u16 gain;
+ u16 reserved;
+} __packed;
+
+struct cpe_afe_hw_mad_ctrl {
+ struct cpe_param_data param;
+ u32 minor_version;
+ u16 mad_type;
+ u16 mad_enable;
+} __packed;
+
+struct cpe_afe_port_cfg {
+ struct cpe_param_data param;
+ u32 minor_version;
+ u16 bit_width;
+ u16 num_channels;
+ u32 sample_rate;
+} __packed;
+
+struct cpe_afe_cmd_port_cfg {
+ struct cmi_hdr hdr;
+ u8 bit_width;
+ u8 num_channels;
+ u16 buffer_size;
+ u32 sample_rate;
+} __packed;
+
+struct cpe_afe_params {
+ struct cmi_hdr hdr;
+ struct cpe_afe_hw_mad_ctrl hw_mad_ctrl;
+ struct cpe_afe_port_cfg port_cfg;
+} __packed;
+
+struct cpe_afe_svc_cmd_mode {
+ struct cmi_hdr hdr;
+ u8 mode;
+} __packed;
+
+struct cpe_lsm_param_opmode {
+ struct cmi_hdr hdr;
+ struct cpe_param_data param;
+ u32 minor_version;
+ u16 mode;
+ u16 reserved;
+} __packed;
+
+struct cpe_lsm_param_connectport {
+ struct cmi_hdr hdr;
+ struct cpe_param_data param;
+ u32 minor_version;
+ u16 afe_port_id;
+ u16 reserved;
+} __packed;
+
+/*
+ * This cannot be sent to CPE as is,
+ * need to append the conf_levels dynamically
+ */
+struct cpe_lsm_conf_level {
+ struct cmi_hdr hdr;
+ struct cpe_param_data param;
+ u8 num_active_models;
+} __packed;
+
+struct cpe_lsm_output_format_cfg {
+ struct cmi_hdr hdr;
+ u8 format;
+ u8 packing;
+ u8 data_path_events;
+} __packed;
+
+struct cpe_lsm_lab_enable {
+ struct cpe_param_data param;
+ u16 enable;
+ u16 reserved;
+} __packed;
+
+struct cpe_lsm_control_lab {
+ struct cmi_hdr hdr;
+ struct cpe_lsm_lab_enable lab_enable;
+} __packed;
+
+struct cpe_lsm_lab_config {
+ struct cpe_param_data param;
+ u32 minor_ver;
+ u32 latency;
+} __packed;
+
+struct cpe_lsm_lab_latency_config {
+ struct cmi_hdr hdr;
+ struct cpe_lsm_lab_config latency_cfg;
+} __packed;
+
+struct cpe_lsm_media_fmt_param {
+ struct cmi_hdr hdr;
+ struct cpe_param_data param;
+ u32 minor_version;
+ u32 sample_rate;
+ u16 num_channels;
+ u16 bit_width;
+} __packed;
+
+
+#define CPE_PARAM_LSM_LAB_LATENCY_SIZE (\
+ sizeof(struct cpe_lsm_lab_latency_config) - \
+ sizeof(struct cmi_hdr))
+#define PARAM_SIZE_LSM_LATENCY_SIZE (\
+ sizeof(struct cpe_lsm_lab_config) - \
+ sizeof(struct cpe_param_data))
+#define CPE_PARAM_SIZE_LSM_LAB_CONTROL (\
+ sizeof(struct cpe_lsm_control_lab) - \
+ sizeof(struct cmi_hdr))
+#define PARAM_SIZE_LSM_CONTROL_SIZE (sizeof(struct cpe_lsm_lab_enable) - \
+ sizeof(struct cpe_param_data))
+#define PARAM_SIZE_AFE_HW_MAD_CTRL (sizeof(struct cpe_afe_hw_mad_ctrl) - \
+ sizeof(struct cpe_param_data))
+#define PARAM_SIZE_AFE_PORT_CFG (sizeof(struct cpe_afe_port_cfg) - \
+ sizeof(struct cpe_param_data))
+#define CPE_AFE_PARAM_PAYLOAD_SIZE (sizeof(struct cpe_afe_params) - \
+ sizeof(struct cmi_hdr))
+
+#define OPEN_CMD_PAYLOAD_SIZE (sizeof(struct cpe_lsm_cmd_open_tx) - \
+ sizeof(struct cmi_hdr))
+#define OPEN_V2_CMD_PAYLOAD_SIZE (sizeof(struct cpe_lsm_cmd_open_tx_v2) - \
+ sizeof(struct cmi_hdr))
+#define SHMEM_ALLOC_CMD_PLD_SIZE (sizeof(struct cpe_cmd_shmem_alloc) - \
+ sizeof(struct cmi_hdr))
+
+#define SHMEM_DEALLOC_CMD_PLD_SIZE (sizeof(struct cpe_cmd_shmem_dealloc) - \
+ sizeof(struct cmi_hdr))
+#define OUT_FMT_CFG_CMD_PAYLOAD_SIZE ( \
+ sizeof(struct cpe_lsm_output_format_cfg) - \
+ sizeof(struct cmi_hdr))
+
+#define CPE_AFE_CMD_PORT_CFG_PAYLOAD_SIZE \
+ (sizeof(struct cpe_afe_cmd_port_cfg) - \
+ sizeof(struct cmi_hdr))
+
+#define CPE_AFE_CMD_MODE_PAYLOAD_SIZE \
+ (sizeof(struct cpe_afe_svc_cmd_mode) - \
+ sizeof(struct cmi_hdr))
+#define CPE_CMD_EPD_THRES_PLD_SIZE (sizeof(struct cpe_lsm_param_epd_thres) - \
+ sizeof(struct cmi_hdr))
+#define CPE_EPD_THRES_PARAM_SIZE ((CPE_CMD_EPD_THRES_PLD_SIZE) - \
+ sizeof(struct cpe_param_data))
+#define CPE_CMD_OPMODE_PLD_SIZE (sizeof(struct cpe_lsm_param_opmode) - \
+ sizeof(struct cmi_hdr))
+#define CPE_OPMODE_PARAM_SIZE ((CPE_CMD_OPMODE_PLD_SIZE) -\
+ sizeof(struct cpe_param_data))
+#define CPE_CMD_CONNECTPORT_PLD_SIZE \
+ (sizeof(struct cpe_lsm_param_connectport) - \
+ sizeof(struct cmi_hdr))
+#define CPE_CONNECTPORT_PARAM_SIZE ((CPE_CMD_CONNECTPORT_PLD_SIZE) - \
+ sizeof(struct cpe_param_data))
+#define CPE_CMD_GAIN_PLD_SIZE (sizeof(struct cpe_lsm_param_gain) - \
+ sizeof(struct cmi_hdr))
+#define CPE_GAIN_PARAM_SIZE ((CPE_CMD_GAIN_PLD_SIZE) - \
+ sizeof(struct cpe_param_data))
+#define CPE_MEDIA_FMT_PLD_SIZE (sizeof(struct cpe_lsm_media_fmt_param) - \
+ sizeof(struct cmi_hdr))
+#define CPE_MEDIA_FMT_PARAM_SIZE ((CPE_MEDIA_FMT_PLD_SIZE) - \
+ sizeof(struct cpe_param_data))
+#endif /* __CPE_CMI_H__ */
diff --git a/include/sound/cpe_core.h b/include/sound/cpe_core.h
new file mode 100644
index 0000000..f4af562
--- /dev/null
+++ b/include/sound/cpe_core.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013-2017, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CPE_CORE_H__
+#define __CPE_CORE_H__
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <sound/lsm_params.h>
+
+enum {
+ CMD_INIT_STATE = 0,
+ CMD_SENT,
+ CMD_RESP_RCVD,
+};
+
+enum wcd_cpe_event {
+ WCD_CPE_PRE_ENABLE = 1,
+ WCD_CPE_POST_ENABLE,
+ WCD_CPE_PRE_DISABLE,
+ WCD_CPE_POST_DISABLE,
+};
+
+struct wcd_cpe_afe_port_cfg {
+ u8 port_id;
+ u16 bit_width;
+ u16 num_channels;
+ u32 sample_rate;
+};
+
+struct lsm_out_fmt_cfg {
+ u8 format;
+ u8 pack_mode;
+ u8 data_path_events;
+ u8 transfer_mode;
+};
+
+struct lsm_hw_params {
+ u32 sample_rate;
+ u16 num_chs;
+ u16 bit_width;
+};
+
+struct cpe_lsm_session {
+ /* sound model related */
+ void *snd_model_data;
+ u8 *conf_levels;
+ void *cmi_reg_handle;
+
+ /* Clients private data */
+ void *priv_d;
+
+ void (*event_cb)(void *priv_data,
+ u8 detect_status,
+ u8 size, u8 *payload);
+
+ struct completion cmd_comp;
+ struct wcd_cpe_afe_port_cfg afe_port_cfg;
+ struct wcd_cpe_afe_port_cfg afe_out_port_cfg;
+ struct mutex lsm_lock;
+
+ u32 snd_model_size;
+ u32 lsm_mem_handle;
+ u16 cmd_err_code;
+ u8 id;
+ u8 num_confidence_levels;
+ u16 afe_out_port_id;
+ struct task_struct *lsm_lab_thread;
+ bool started;
+
+ u32 lab_enable;
+ struct lsm_out_fmt_cfg out_fmt_cfg;
+
+ bool is_topology_used;
+};
+
+struct wcd_cpe_afe_ops {
+ int (*afe_set_params)(void *core_handle,
+ struct wcd_cpe_afe_port_cfg *cfg,
+ bool afe_mad_ctl);
+
+ int (*afe_port_start)(void *core_handle,
+ struct wcd_cpe_afe_port_cfg *cfg);
+
+ int (*afe_port_stop)(void *core_handle,
+ struct wcd_cpe_afe_port_cfg *cfg);
+
+ int (*afe_port_suspend)(void *core_handle,
+ struct wcd_cpe_afe_port_cfg *cfg);
+
+ int (*afe_port_resume)(void *core_handle,
+ struct wcd_cpe_afe_port_cfg *cfg);
+
+ int (*afe_port_cmd_cfg)(void *core_handle,
+ struct wcd_cpe_afe_port_cfg *cfg);
+};
+
+struct wcd_cpe_lsm_ops {
+
+ struct cpe_lsm_session *(*lsm_alloc_session)
+ (void *core_handle, void *lsm_priv_d,
+ void (*event_cb)(void *priv_data,
+ u8 detect_status,
+ u8 size, u8 *payload));
+
+ int (*lsm_dealloc_session)
+ (void *core_handle, struct cpe_lsm_session *);
+
+ int (*lsm_open_tx)(void *core_handle,
+ struct cpe_lsm_session *, u16, u16);
+
+ int (*lsm_close_tx)(void *core_handle,
+ struct cpe_lsm_session *);
+
+ int (*lsm_shmem_alloc)(void *core_handle,
+ struct cpe_lsm_session *, u32 size);
+
+ int (*lsm_shmem_dealloc)(void *core_handle,
+ struct cpe_lsm_session *);
+
+ int (*lsm_register_snd_model)(void *core_handle,
+ struct cpe_lsm_session *,
+ enum lsm_detection_mode, bool);
+
+ int (*lsm_deregister_snd_model)(void *core_handle,
+ struct cpe_lsm_session *);
+
+ int (*lsm_get_afe_out_port_id)(void *core_handle,
+ struct cpe_lsm_session *session);
+
+ int (*lsm_start)(void *core_handle,
+ struct cpe_lsm_session *);
+
+ int (*lsm_stop)(void *core_handle,
+ struct cpe_lsm_session *);
+
+ int (*lsm_lab_control)(void *core_handle,
+ struct cpe_lsm_session *session,
+ bool enable);
+
+ int (*lab_ch_setup)(void *core_handle,
+ struct cpe_lsm_session *session,
+ enum wcd_cpe_event event);
+
+ int (*lsm_set_data)(void *core_handle,
+ struct cpe_lsm_session *session,
+ enum lsm_detection_mode detect_mode,
+ bool detect_failure);
+ int (*lsm_set_fmt_cfg)(void *core_handle,
+ struct cpe_lsm_session *session);
+ int (*lsm_set_one_param)(void *core_handle,
+ struct cpe_lsm_session *session,
+ struct lsm_params_info *p_info,
+ void *data, enum LSM_PARAM_TYPE param_type);
+ void (*lsm_get_snd_model_offset)
+ (void *core_handle, struct cpe_lsm_session *,
+ size_t *offset);
+ int (*lsm_set_media_fmt_params)(void *core_handle,
+ struct cpe_lsm_session *session,
+ struct lsm_hw_params *param);
+ int (*lsm_set_port)(void *core_handle,
+ struct cpe_lsm_session *session, void *data);
+};
+
+int wcd_cpe_get_lsm_ops(struct wcd_cpe_lsm_ops *lsm_ops);
+int wcd_cpe_get_afe_ops(struct wcd_cpe_afe_ops *afe_ops);
+void *wcd_cpe_get_core_handle(struct snd_soc_codec *codec);
+#endif
diff --git a/include/sound/cpe_err.h b/include/sound/cpe_err.h
new file mode 100644
index 0000000..d355803
--- /dev/null
+++ b/include/sound/cpe_err.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CPE_ERR__
+#define __CPE_ERR__
+
+#include <linux/errno.h>
+
+/* ERROR CODES */
+/* Success. The operation completed with no errors. */
+#define CPE_EOK 0x00000000
+/* General failure. */
+#define CPE_EFAILED 0x00000001
+/* Bad operation parameter. */
+#define CPE_EBADPARAM 0x00000002
+/* Unsupported routine or operation. */
+#define CPE_EUNSUPPORTED 0x00000003
+/* Unsupported version. */
+#define CPE_EVERSION 0x00000004
+/* Unexpected problem encountered. */
+#define CPE_EUNEXPECTED 0x00000005
+/* Unhandled problem occurred. */
+#define CPE_EPANIC 0x00000006
+/* Unable to allocate resource. */
+#define CPE_ENORESOURCE 0x00000007
+/* Invalid handle. */
+#define CPE_EHANDLE 0x00000008
+/* Operation is already processed. */
+#define CPE_EALREADY 0x00000009
+/* Operation is not ready to be processed. */
+#define CPE_ENOTREADY 0x0000000A
+/* Operation is pending completion. */
+#define CPE_EPENDING 0x0000000B
+/* Operation could not be accepted or processed. */
+#define CPE_EBUSY 0x0000000C
+/* Operation aborted due to an error. */
+#define CPE_EABORTED 0x0000000D
+/* Operation preempted by a higher priority. */
+#define CPE_EPREEMPTED 0x0000000E
+/* Operation requests intervention to complete. */
+#define CPE_ECONTINUE 0x0000000F
+/* Operation requests immediate intervention to complete. */
+#define CPE_EIMMEDIATE 0x00000010
+/* Operation is not implemented. */
+#define CPE_ENOTIMPL 0x00000011
+/* Operation needs more data or resources. */
+#define CPE_ENEEDMORE 0x00000012
+/* Operation does not have memory. */
+#define CPE_ENOMEMORY 0x00000014
+/* Item does not exist. */
+#define CPE_ENOTEXIST 0x00000015
+/* Operation is finished. */
+#define CPE_ETERMINATED 0x00000016
+/* Max count for adsp error code sent to HLOS*/
+#define CPE_ERR_MAX (CPE_ETERMINATED + 1)
+
+
+/* ERROR STRING */
+/* Success. The operation completed with no errors. */
+#define CPE_EOK_STR "CPE_EOK"
+/* General failure. */
+#define CPE_EFAILED_STR "CPE_EFAILED"
+/* Bad operation parameter. */
+#define CPE_EBADPARAM_STR "CPE_EBADPARAM"
+/* Unsupported routine or operation. */
+#define CPE_EUNSUPPORTED_STR "CPE_EUNSUPPORTED"
+/* Unsupported version. */
+#define CPE_EVERSION_STR "CPE_EVERSION"
+/* Unexpected problem encountered. */
+#define CPE_EUNEXPECTED_STR "CPE_EUNEXPECTED"
+/* Unhandled problem occurred. */
+#define CPE_EPANIC_STR "CPE_EPANIC"
+/* Unable to allocate resource. */
+#define CPE_ENORESOURCE_STR "CPE_ENORESOURCE"
+/* Invalid handle. */
+#define CPE_EHANDLE_STR "CPE_EHANDLE"
+/* Operation is already processed. */
+#define CPE_EALREADY_STR "CPE_EALREADY"
+/* Operation is not ready to be processed. */
+#define CPE_ENOTREADY_STR "CPE_ENOTREADY"
+/* Operation is pending completion. */
+#define CPE_EPENDING_STR "CPE_EPENDING"
+/* Operation could not be accepted or processed. */
+#define CPE_EBUSY_STR "CPE_EBUSY"
+/* Operation aborted due to an error. */
+#define CPE_EABORTED_STR "CPE_EABORTED"
+/* Operation preempted by a higher priority. */
+#define CPE_EPREEMPTED_STR "CPE_EPREEMPTED"
+/* Operation requests intervention to complete. */
+#define CPE_ECONTINUE_STR "CPE_ECONTINUE"
+/* Operation requests immediate intervention to complete. */
+#define CPE_EIMMEDIATE_STR "CPE_EIMMEDIATE"
+/* Operation is not implemented. */
+#define CPE_ENOTIMPL_STR "CPE_ENOTIMPL"
+/* Operation needs more data or resources. */
+#define CPE_ENEEDMORE_STR "CPE_ENEEDMORE"
+/* Operation does not have memory. */
+#define CPE_ENOMEMORY_STR "CPE_ENOMEMORY"
+/* Item does not exist. */
+#define CPE_ENOTEXIST_STR "CPE_ENOTEXIST"
+/* Operation is finished. */
+#define CPE_ETERMINATED_STR "CPE_ETERMINATED"
+/* Unexpected error code. */
+#define CPE_ERR_MAX_STR "CPE_ERR_MAX"
+
+
+struct cpe_err_code {
+ int lnx_err_code;
+ char *cpe_err_str;
+};
+
+
+static struct cpe_err_code cpe_err_code_info[CPE_ERR_MAX+1] = {
+ { 0, CPE_EOK_STR},
+ { -ENOTRECOVERABLE, CPE_EFAILED_STR},
+ { -EINVAL, CPE_EBADPARAM_STR},
+ { -EOPNOTSUPP, CPE_EUNSUPPORTED_STR},
+ { -ENOPROTOOPT, CPE_EVERSION_STR},
+ { -ENOTRECOVERABLE, CPE_EUNEXPECTED_STR},
+ { -ENOTRECOVERABLE, CPE_EPANIC_STR},
+ { -ENOSPC, CPE_ENORESOURCE_STR},
+ { -EBADR, CPE_EHANDLE_STR},
+ { -EALREADY, CPE_EALREADY_STR},
+ { -EPERM, CPE_ENOTREADY_STR},
+ { -EINPROGRESS, CPE_EPENDING_STR},
+ { -EBUSY, CPE_EBUSY_STR},
+ { -ECANCELED, CPE_EABORTED_STR},
+ { -EAGAIN, CPE_EPREEMPTED_STR},
+ { -EAGAIN, CPE_ECONTINUE_STR},
+ { -EAGAIN, CPE_EIMMEDIATE_STR},
+ { -EAGAIN, CPE_ENOTIMPL_STR},
+ { -ENODATA, CPE_ENEEDMORE_STR},
+ { -EADV, CPE_ERR_MAX_STR},
+ { -ENOMEM, CPE_ENOMEMORY_STR},
+ { -ENODEV, CPE_ENOTEXIST_STR},
+ { -EADV, CPE_ETERMINATED_STR},
+ { -EADV, CPE_ERR_MAX_STR},
+};
+
+static inline int cpe_err_get_lnx_err_code(u32 cpe_error)
+{
+ if (cpe_error > CPE_ERR_MAX)
+ return cpe_err_code_info[CPE_ERR_MAX].lnx_err_code;
+ else
+ return cpe_err_code_info[cpe_error].lnx_err_code;
+}
+
+static inline char *cpe_err_get_err_str(u32 cpe_error)
+{
+ if (cpe_error > CPE_ERR_MAX)
+ return cpe_err_code_info[CPE_ERR_MAX].cpe_err_str;
+ else
+ return cpe_err_code_info[cpe_error].cpe_err_str;
+}
+
+#endif
diff --git a/include/sound/msm-audio-effects-q6-v2.h b/include/sound/msm-audio-effects-q6-v2.h
new file mode 100644
index 0000000..6bc2338
--- /dev/null
+++ b/include/sound/msm-audio-effects-q6-v2.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_AUDIO_EFFECTS_H
+#define _MSM_AUDIO_EFFECTS_H
+
+#include <sound/audio_effects.h>
+
+#define MAX_PP_PARAMS_SZ 128
+
+bool msm_audio_effects_is_effmodule_supp_in_top(int effect_module,
+ int topology);
+
+int msm_audio_effects_enable_extn(struct audio_client *ac,
+ struct msm_nt_eff_all_config *effects,
+ bool flag);
+
+int msm_audio_effects_reverb_handler(struct audio_client *ac,
+ struct reverb_params *reverb,
+ long *values);
+
+int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
+ struct bass_boost_params *bass_boost,
+ long *values);
+
+int msm_audio_effects_pbe_handler(struct audio_client *ac,
+ struct pbe_params *pbe,
+ long *values);
+
+int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
+ struct virtualizer_params *virtualizer,
+ long *values);
+
+int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
+ struct eq_params *eq,
+ long *values);
+
+int msm_audio_effects_volume_handler(struct audio_client *ac,
+ struct soft_volume_params *vol,
+ long *values);
+
+int msm_audio_effects_volume_handler_v2(struct audio_client *ac,
+ struct soft_volume_params *vol,
+ long *values, int instance);
+#endif /*_MSM_AUDIO_EFFECTS_H*/
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
new file mode 100644
index 0000000..b1d76bf
--- /dev/null
+++ b/include/sound/msm-dai-q6-v2.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_DAI_Q6_PDATA_H__
+
+#define __MSM_DAI_Q6_PDATA_H__
+
+#define MSM_MI2S_SD0 (1 << 0)
+#define MSM_MI2S_SD1 (1 << 1)
+#define MSM_MI2S_SD2 (1 << 2)
+#define MSM_MI2S_SD3 (1 << 3)
+#define MSM_MI2S_CAP_RX 0
+#define MSM_MI2S_CAP_TX 1
+
+#define MSM_PRIM_MI2S 0
+#define MSM_SEC_MI2S 1
+#define MSM_TERT_MI2S 2
+#define MSM_QUAT_MI2S 3
+#define MSM_SEC_MI2S_SD1 4
+#define MSM_QUIN_MI2S 5
+#define MSM_SENARY_MI2S 6
+#define MSM_INT0_MI2S 7
+#define MSM_INT1_MI2S 8
+#define MSM_INT2_MI2S 9
+#define MSM_INT3_MI2S 10
+#define MSM_INT4_MI2S 11
+#define MSM_INT5_MI2S 12
+#define MSM_INT6_MI2S 13
+#define MSM_MI2S_MIN MSM_PRIM_MI2S
+#define MSM_MI2S_MAX MSM_INT6_MI2S
+
+struct msm_dai_auxpcm_config {
+ u16 mode;
+ u16 sync;
+ u16 frame;
+ u16 quant;
+ u16 num_slots;
+ u16 *slot_mapping;
+ u16 data;
+ u32 pcm_clk_rate;
+};
+
+struct msm_dai_auxpcm_pdata {
+ struct msm_dai_auxpcm_config mode_8k;
+ struct msm_dai_auxpcm_config mode_16k;
+};
+
+struct msm_mi2s_pdata {
+ u16 rx_sd_lines;
+ u16 tx_sd_lines;
+ u16 intf_id;
+};
+
+struct msm_i2s_data {
+ u32 capability; /* RX or TX */
+ u16 sd_lines;
+};
+
+struct msm_dai_tdm_group_config {
+ u16 group_id;
+ u16 num_ports;
+ u16 *port_id;
+ u32 clk_rate;
+};
+
+struct msm_dai_tdm_config {
+ u16 sync_mode;
+ u16 sync_src;
+ u16 data_out;
+ u16 invert_sync;
+ u16 data_delay;
+ u32 data_align;
+ u16 header_start_offset;
+ u16 header_width;
+ u16 header_num_frame_repeat;
+};
+
+struct msm_dai_tdm_pdata {
+ struct msm_dai_tdm_group_config group_config;
+ struct msm_dai_tdm_config config;
+};
+
+#endif
diff --git a/include/sound/msm-dts-eagle.h b/include/sound/msm-dts-eagle.h
new file mode 100644
index 0000000..2ef0113
--- /dev/null
+++ b/include/sound/msm-dts-eagle.h
@@ -0,0 +1,148 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_DTS_EAGLE_H__
+#define __MSM_DTS_EAGLE_H__
+
+#include <linux/compat.h>
+#include <sound/soc.h>
+#include <sound/devdep_params.h>
+#include <sound/q6asm-v2.h>
+
+#ifdef CONFIG_COMPAT
+enum {
+ DTS_EAGLE_IOCTL_GET_CACHE_SIZE32 = _IOR(0xF2, 0, __s32),
+ DTS_EAGLE_IOCTL_SET_CACHE_SIZE32 = _IOW(0xF2, 1, __s32),
+ DTS_EAGLE_IOCTL_GET_PARAM32 = _IOR(0xF2, 2, compat_uptr_t),
+ DTS_EAGLE_IOCTL_SET_PARAM32 = _IOW(0xF2, 3, compat_uptr_t),
+ DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32 =
+ _IOW(0xF2, 4, compat_uptr_t),
+ DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32 =
+ _IOW(0xF2, 5, compat_uptr_t),
+ DTS_EAGLE_IOCTL_GET_LICENSE32 =
+ _IOR(0xF2, 6, compat_uptr_t),
+ DTS_EAGLE_IOCTL_SET_LICENSE32 =
+ _IOW(0xF2, 7, compat_uptr_t),
+ DTS_EAGLE_IOCTL_SEND_LICENSE32 = _IOW(0xF2, 8, __s32),
+ DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32 = _IOW(0xF2, 9,
+ compat_uptr_t),
+};
+#endif
+
+#ifdef CONFIG_DTS_EAGLE
+void msm_dts_ion_memmap(struct param_outband *po_);
+int msm_dts_eagle_enable_asm(struct audio_client *ac, u32 enable, int module);
+int msm_dts_eagle_enable_adm(int port_id, int copp_idx, u32 enable);
+void msm_dts_eagle_add_controls(struct snd_soc_platform *platform);
+int msm_dts_eagle_set_stream_gain(struct audio_client *ac,
+ int lgain, int rgain);
+int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd, char *buf,
+ bool for_pre, bool get, struct audio_client *ac,
+ struct param_outband *po);
+int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd, char *buf,
+ bool for_pre, bool get);
+int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg);
+int msm_dts_eagle_is_hpx_on(void);
+int msm_dts_eagle_init_pre(struct audio_client *ac);
+int msm_dts_eagle_deinit_pre(struct audio_client *ac);
+int msm_dts_eagle_init_post(int port_id, int copp_id);
+int msm_dts_eagle_deinit_post(int port_id, int topology);
+int msm_dts_eagle_init_master_module(struct audio_client *ac);
+int msm_dts_eagle_deinit_master_module(struct audio_client *ac);
+int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime);
+void msm_dts_eagle_pcm_free(struct snd_pcm *pcm);
+int msm_dts_eagle_compat_ioctl(unsigned int cmd, unsigned long arg);
+#else
+static inline void msm_dts_ion_memmap(struct param_outband *po_)
+{
+ pr_debug("%s\n", __func__);
+}
+static inline int msm_dts_eagle_enable_asm(struct audio_client *ac,
+ u32 enable, int module)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_enable_adm(int port_id, int copp_idx,
+ u32 enable)
+{
+ return 0;
+}
+static inline void msm_dts_eagle_add_controls(struct snd_soc_platform *platform)
+{
+}
+static inline int msm_dts_eagle_set_stream_gain(struct audio_client *ac,
+ int lgain, int rgain)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+static inline int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd,
+ char *buf, bool for_pre, bool get,
+ struct audio_client *ac,
+ struct param_outband *po)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd,
+ char *buf, bool for_pre, bool get)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg)
+{
+ return -EPERM;
+}
+static inline int msm_dts_eagle_is_hpx_on(void)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_init_pre(struct audio_client *ac)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_deinit_pre(struct audio_client *ac)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_init_post(int port_id, int coppid)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_deinit_post(int port_id, int topology)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_init_master_module(struct audio_client *ac)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_deinit_master_module(struct audio_client *ac)
+{
+ return 0;
+}
+static inline int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+static inline void msm_dts_eagle_pcm_free(struct snd_pcm *pcm)
+{
+ pr_debug("%s\n", __func__);
+}
+static inline int msm_dts_eagle_compat_ioctl(unsigned int cmd,
+ unsigned long arg)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/include/sound/msm-slim-dma.h b/include/sound/msm-slim-dma.h
new file mode 100644
index 0000000..daf394b
--- /dev/null
+++ b/include/sound/msm-slim-dma.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MSM_SLIMBUS_DMA_H
+#define _MSM_SLIMBUS_DMA_H
+
+#include <linux/slimbus/slimbus.h>
+
+/*
+ * struct msm_slim_dma_data - DMA data for slimbus data transfer
+ *
+ * @sdev: Handle to the slim_device instance associated with the
+ * data transfer.
+ * @ph: Port handle for the slimbus ports.
+ * @dai_channel_ctl: callback function into the CPU dai driver
+ * to setup the data path.
+ *
+ * This structure is used to share the slimbus port handles and
+ * other data path setup related handles with other drivers.
+ */
+struct msm_slim_dma_data {
+
+ /* Handle to slimbus device */
+ struct slim_device *sdev;
+
+ /* Port Handle */
+ u32 ph;
+
+ /* Callback for data channel control */
+ int (*dai_channel_ctl)(struct msm_slim_dma_data *dma_data,
+ struct snd_soc_dai *dai, bool enable);
+};
+
+#endif
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
new file mode 100644
index 0000000..c9a429d
--- /dev/null
+++ b/include/sound/q6adm-v2.h
@@ -0,0 +1,156 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6_ADM_V2_H__
+#define __Q6_ADM_V2_H__
+
+
+#define ADM_PATH_PLAYBACK 0x1
+#define ADM_PATH_LIVE_REC 0x2
+#define ADM_PATH_NONLIVE_REC 0x3
+#define ADM_PATH_COMPRESSED_RX 0x5
+#include <linux/qdsp6v2/rtac.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6audio-v2.h>
+
+#define MAX_MODULES_IN_TOPO 16
+#define ADM_GET_TOPO_MODULE_LIST_LENGTH\
+ ((MAX_MODULES_IN_TOPO + 1) * sizeof(uint32_t))
+#define AUD_PROC_BLOCK_SIZE 4096
+#define AUD_VOL_BLOCK_SIZE 4096
+#define AUDIO_RX_CALIBRATION_SIZE (AUD_PROC_BLOCK_SIZE + \
+ AUD_VOL_BLOCK_SIZE)
+enum {
+ ADM_CUSTOM_TOP_CAL = 0,
+ ADM_AUDPROC_CAL,
+ ADM_AUDVOL_CAL,
+ ADM_RTAC_INFO_CAL,
+ ADM_RTAC_APR_CAL,
+ ADM_DTS_EAGLE,
+ ADM_SRS_TRUMEDIA,
+ ADM_RTAC_AUDVOL_CAL,
+ ADM_MAX_CAL_TYPES
+};
+
+enum {
+ ADM_MEM_MAP_INDEX_SOURCE_TRACKING = ADM_MAX_CAL_TYPES,
+ ADM_MEM_MAP_INDEX_MAX
+};
+
+enum {
+ ADM_CLIENT_ID_DEFAULT = 0,
+ ADM_CLIENT_ID_SOURCE_TRACKING,
+ ADM_CLIENT_ID_MAX,
+};
+
+#define MAX_COPPS_PER_PORT 0x8
+#define ADM_MAX_CHANNELS 8
+
+/* multiple copp per stream. */
+struct route_payload {
+ unsigned int copp_idx[MAX_COPPS_PER_PORT];
+ unsigned int port_id[MAX_COPPS_PER_PORT];
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+ unsigned short num_copps;
+ unsigned int session_id;
+};
+
+int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
+ void *srs_params);
+
+int adm_dts_eagle_set(int port_id, int copp_idx, int param_id,
+ void *data, uint32_t size);
+
+int adm_dts_eagle_get(int port_id, int copp_idx, int param_id,
+ void *data, uint32_t size);
+
+void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate);
+
+int adm_get_params(int port_id, int copp_idx, uint32_t module_id,
+ uint32_t param_id, uint32_t params_length, char *params);
+
+int adm_send_params_v5(int port_id, int copp_idx, char *params,
+ uint32_t params_length);
+
+int adm_dolby_dap_send_params(int port_id, int copp_idx, char *params,
+ uint32_t params_length);
+
+int adm_open(int port, int path, int rate, int mode, int topology,
+ int perf_mode, uint16_t bits_per_sample,
+ int app_type, int acdbdev_id);
+
+int adm_map_rtac_block(struct rtac_cal_block_data *cal_block);
+
+int adm_unmap_rtac_block(uint32_t *mem_map_handle);
+
+int adm_close(int port, int topology, int perf_mode);
+
+int adm_matrix_map(int path, struct route_payload payload_map,
+ int perf_mode);
+
+int adm_connect_afe_port(int mode, int session_id, int port_id);
+
+void adm_ec_ref_rx_id(int port_id);
+
+int adm_get_lowlatency_copp_id(int port_id);
+
+int adm_set_multi_ch_map(char *channel_map, int path);
+
+int adm_get_multi_ch_map(char *channel_map, int path);
+
+int adm_validate_and_get_port_index(int port_id);
+
+int adm_get_default_copp_idx(int port_id);
+
+int adm_get_topology_for_port_from_copp_id(int port_id, int copp_id);
+
+int adm_get_topology_for_port_copp_idx(int port_id, int copp_idx);
+
+int adm_get_indexes_from_copp_id(int copp_id, int *port_idx, int *copp_idx);
+
+int adm_set_stereo_to_custom_stereo(int port_id, int copp_idx,
+ unsigned int session_id,
+ char *params, uint32_t params_length);
+
+int adm_get_pp_topo_module_list(int port_id, int copp_idx, int32_t param_length,
+ char *params);
+
+int adm_set_volume(int port_id, int copp_idx, int volume);
+
+int adm_set_softvolume(int port_id, int copp_idx,
+ struct audproc_softvolume_params *softvol_param);
+
+int adm_param_enable(int port_id, int copp_idx, int module_id, int enable);
+
+int adm_send_calibration(int port_id, int copp_idx, int path, int perf_mode,
+ int cal_type, char *params, int size);
+
+int adm_set_wait_parameters(int port_id, int copp_idx);
+
+int adm_reset_wait_parameters(int port_id, int copp_idx);
+
+int adm_wait_timeout(int port_id, int copp_idx, int wait_time);
+
+int adm_store_cal_data(int port_id, int copp_idx, int path, int perf_mode,
+ int cal_type, char *params, int *size);
+
+int adm_send_compressed_device_mute(int port_id, int copp_idx, bool mute_on);
+
+int adm_send_compressed_device_latency(int port_id, int copp_idx, int latency);
+int adm_set_sound_focus(int port_id, int copp_idx,
+ struct sound_focus_param soundFocusData);
+int adm_get_sound_focus(int port_id, int copp_idx,
+ struct sound_focus_param *soundFocusData);
+int adm_get_source_tracking(int port_id, int copp_idx,
+ struct source_tracking_param *sourceTrackingData);
+#endif /* __Q6_ADM_V2_H__ */
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
new file mode 100644
index 0000000..367e75d
--- /dev/null
+++ b/include/sound/q6afe-v2.h
@@ -0,0 +1,366 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6AFE_V2_H__
+#define __Q6AFE_V2_H__
+#include <sound/apr_audio-v2.h>
+#include <linux/qdsp6v2/rtac.h>
+
+#define IN 0x000
+#define OUT 0x001
+#define MSM_AFE_MONO 0
+#define MSM_AFE_CH_STEREO 1
+#define MSM_AFE_MONO_RIGHT 1
+#define MSM_AFE_MONO_LEFT 2
+#define MSM_AFE_STEREO 3
+#define MSM_AFE_4CHANNELS 4
+#define MSM_AFE_6CHANNELS 6
+#define MSM_AFE_8CHANNELS 8
+
+#define MSM_AFE_I2S_FORMAT_LPCM 0
+#define MSM_AFE_I2S_FORMAT_COMPR 1
+#define MSM_AFE_I2S_FORMAT_IEC60958_LPCM 2
+#define MSM_AFE_I2S_FORMAT_IEC60958_COMPR 3
+
+#define MSM_AFE_PORT_TYPE_RX 0
+#define MSM_AFE_PORT_TYPE_TX 1
+
+#define RT_PROXY_DAI_001_RX 0xE0
+#define RT_PROXY_DAI_001_TX 0xF0
+#define RT_PROXY_DAI_002_RX 0xF1
+#define RT_PROXY_DAI_002_TX 0xE1
+#define VIRTUAL_ID_TO_PORTID(val) ((val & 0xF) | 0x2000)
+
+#define AFE_CLK_VERSION_V1 1
+#define AFE_CLK_VERSION_V2 2
+
+enum {
+ /* IDX 0->4 */
+ IDX_PRIMARY_I2S_RX,
+ IDX_PRIMARY_I2S_TX,
+ IDX_AFE_PORT_ID_PRIMARY_PCM_RX,
+ IDX_AFE_PORT_ID_PRIMARY_PCM_TX,
+ IDX_SECONDARY_I2S_RX,
+ /* IDX 5->9 */
+ IDX_SECONDARY_I2S_TX,
+ IDX_MI2S_RX,
+ IDX_MI2S_TX,
+ IDX_HDMI_RX,
+ IDX_RSVD_2,
+ /* IDX 10->14 */
+ IDX_RSVD_3,
+ IDX_DIGI_MIC_TX,
+ IDX_VOICE_RECORD_RX,
+ IDX_VOICE_RECORD_TX,
+ IDX_VOICE_PLAYBACK_TX,
+ /* IDX 15->19 */
+ IDX_SLIMBUS_0_RX,
+ IDX_SLIMBUS_0_TX,
+ IDX_SLIMBUS_1_RX,
+ IDX_SLIMBUS_1_TX,
+ IDX_SLIMBUS_2_RX,
+ /* IDX 20->24 */
+ IDX_SLIMBUS_2_TX,
+ IDX_SLIMBUS_3_RX,
+ IDX_SLIMBUS_3_TX,
+ IDX_SLIMBUS_4_RX,
+ IDX_SLIMBUS_4_TX,
+ /* IDX 25->29 */
+ IDX_SLIMBUS_5_RX,
+ IDX_SLIMBUS_5_TX,
+ IDX_INT_BT_SCO_RX,
+ IDX_INT_BT_SCO_TX,
+ IDX_INT_BT_A2DP_RX,
+ /* IDX 30->34 */
+ IDX_INT_FM_RX,
+ IDX_INT_FM_TX,
+ IDX_RT_PROXY_PORT_001_RX,
+ IDX_RT_PROXY_PORT_001_TX,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX,
+ /* IDX 35->39 */
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX,
+ IDX_AFE_PORT_ID_SECONDARY_MI2S_RX,
+ IDX_AFE_PORT_ID_SECONDARY_MI2S_TX,
+ IDX_AFE_PORT_ID_TERTIARY_MI2S_RX,
+ IDX_AFE_PORT_ID_TERTIARY_MI2S_TX,
+ /* IDX 40->44 */
+ IDX_AFE_PORT_ID_PRIMARY_MI2S_RX,
+ IDX_AFE_PORT_ID_PRIMARY_MI2S_TX,
+ IDX_AFE_PORT_ID_SECONDARY_PCM_RX,
+ IDX_AFE_PORT_ID_SECONDARY_PCM_TX,
+ IDX_VOICE2_PLAYBACK_TX,
+ /* IDX 45->49 */
+ IDX_SLIMBUS_6_RX,
+ IDX_SLIMBUS_6_TX,
+ IDX_SPDIF_RX,
+ IDX_GLOBAL_CFG,
+ IDX_AUDIO_PORT_ID_I2S_RX,
+ /* IDX 50->53 */
+ IDX_AFE_PORT_ID_SECONDARY_MI2S_RX_SD1,
+ IDX_AFE_PORT_ID_QUINARY_MI2S_RX,
+ IDX_AFE_PORT_ID_QUINARY_MI2S_TX,
+ IDX_AFE_PORT_ID_SENARY_MI2S_TX,
+ /* IDX 54->117 */
+ IDX_AFE_PORT_ID_PRIMARY_TDM_RX_0,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_TX_0,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_RX_1,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_TX_1,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_RX_2,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_TX_2,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_RX_3,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_TX_3,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_RX_4,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_TX_4,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_RX_5,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_TX_5,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_RX_6,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_TX_6,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_RX_7,
+ IDX_AFE_PORT_ID_PRIMARY_TDM_TX_7,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_RX_0,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_TX_0,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_RX_1,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_TX_1,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_RX_2,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_TX_2,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_RX_3,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_TX_3,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_RX_4,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_TX_4,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_RX_5,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_TX_5,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_RX_6,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_TX_6,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_RX_7,
+ IDX_AFE_PORT_ID_SECONDARY_TDM_TX_7,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_RX_0,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_TX_0,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_RX_1,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_TX_1,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_RX_2,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_TX_2,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_RX_3,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_TX_3,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_RX_4,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_TX_4,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_RX_5,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_TX_5,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_RX_6,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_TX_6,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_RX_7,
+ IDX_AFE_PORT_ID_TERTIARY_TDM_TX_7,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_0,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_0,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_1,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_1,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_2,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_2,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_3,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_3,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_4,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_4,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_5,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_5,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_6,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_6,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_7,
+ IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_7,
+ /* IDX 118->121 */
+ IDX_SLIMBUS_7_RX,
+ IDX_SLIMBUS_7_TX,
+ IDX_SLIMBUS_8_RX,
+ IDX_SLIMBUS_8_TX,
+ /* IDX 122-> 123 */
+ IDX_AFE_PORT_ID_USB_RX,
+ IDX_AFE_PORT_ID_USB_TX,
+ /* IDX 124 */
+ IDX_DISPLAY_PORT_RX,
+ /* IDX 125-> 128 */
+ IDX_AFE_PORT_ID_TERTIARY_PCM_RX,
+ IDX_AFE_PORT_ID_TERTIARY_PCM_TX,
+ IDX_AFE_PORT_ID_QUATERNARY_PCM_RX,
+ IDX_AFE_PORT_ID_QUATERNARY_PCM_TX,
+ /* IDX 129-> 142 */
+ IDX_AFE_PORT_ID_INT0_MI2S_RX,
+ IDX_AFE_PORT_ID_INT0_MI2S_TX,
+ IDX_AFE_PORT_ID_INT1_MI2S_RX,
+ IDX_AFE_PORT_ID_INT1_MI2S_TX,
+ IDX_AFE_PORT_ID_INT2_MI2S_RX,
+ IDX_AFE_PORT_ID_INT2_MI2S_TX,
+ IDX_AFE_PORT_ID_INT3_MI2S_RX,
+ IDX_AFE_PORT_ID_INT3_MI2S_TX,
+ IDX_AFE_PORT_ID_INT4_MI2S_RX,
+ IDX_AFE_PORT_ID_INT4_MI2S_TX,
+ IDX_AFE_PORT_ID_INT5_MI2S_RX,
+ IDX_AFE_PORT_ID_INT5_MI2S_TX,
+ IDX_AFE_PORT_ID_INT6_MI2S_RX,
+ IDX_AFE_PORT_ID_INT6_MI2S_TX,
+ AFE_MAX_PORTS
+};
+
+enum afe_mad_type {
+ MAD_HW_NONE = 0x00,
+ MAD_HW_AUDIO = 0x01,
+ MAD_HW_BEACON = 0x02,
+ MAD_HW_ULTRASOUND = 0x04,
+ MAD_SW_AUDIO = 0x05,
+};
+
+enum afe_cal_mode {
+ AFE_CAL_MODE_DEFAULT = 0x00,
+ AFE_CAL_MODE_NONE,
+};
+
+struct afe_audio_buffer {
+ dma_addr_t phys;
+ void *data;
+ uint32_t used;
+ uint32_t size;/* size of buffer */
+ uint32_t actual_size; /* actual number of bytes read by DSP */
+ struct ion_handle *handle;
+ struct ion_client *client;
+};
+
+struct afe_audio_port_data {
+ struct afe_audio_buffer *buf;
+ uint32_t max_buf_cnt;
+ uint32_t dsp_buf;
+ uint32_t cpu_buf;
+ struct list_head mem_map_handle;
+ uint32_t tmp_hdl;
+ /* read or write locks */
+ struct mutex lock;
+ spinlock_t dsp_lock;
+};
+
+struct afe_audio_client {
+ atomic_t cmd_state;
+ /* Relative or absolute TS */
+ uint32_t time_flag;
+ void *priv;
+ uint64_t time_stamp;
+ struct mutex cmd_lock;
+ /* idx:1 out port, 0: in port*/
+ struct afe_audio_port_data port[2];
+ wait_queue_head_t cmd_wait;
+ uint32_t mem_map_handle;
+};
+
+struct aanc_data {
+ bool aanc_active;
+ uint16_t aanc_rx_port;
+ uint16_t aanc_tx_port;
+ uint32_t aanc_rx_port_sample_rate;
+ uint32_t aanc_tx_port_sample_rate;
+};
+
+int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
+int afe_close(int port_id);
+int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
+int afe_loopback_gain(u16 port_id, u16 volume);
+int afe_validate_port(u16 port_id);
+int afe_get_port_index(u16 port_id);
+int afe_get_topology(int port_id);
+int afe_start_pseudo_port(u16 port_id);
+int afe_stop_pseudo_port(u16 port_id);
+uint32_t afe_req_mmap_handle(struct afe_audio_client *ac);
+int afe_memory_map(phys_addr_t dma_addr_p, u32 dma_buf_sz,
+ struct afe_audio_client *ac);
+int afe_cmd_memory_map(phys_addr_t dma_addr_p, u32 dma_buf_sz);
+int afe_cmd_memory_map_nowait(int port_id, phys_addr_t dma_addr_p,
+ u32 dma_buf_sz);
+int afe_cmd_memory_unmap(u32 dma_addr_p);
+int afe_cmd_memory_unmap_nowait(u32 dma_addr_p);
+void afe_set_dtmf_gen_rx_portid(u16 rx_port_id, int set);
+int afe_dtmf_generate_rx(int64_t duration_in_ms,
+ uint16_t high_freq,
+ uint16_t low_freq, uint16_t gain);
+int afe_register_get_events(u16 port_id,
+ void (*cb)(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv),
+ void *private_data);
+int afe_unregister_get_events(u16 port_id);
+int afe_rt_proxy_port_write(phys_addr_t buf_addr_p,
+ u32 mem_map_handle, int bytes);
+int afe_rt_proxy_port_read(phys_addr_t buf_addr_p,
+ u32 mem_map_handle, int bytes);
+void afe_set_cal_mode(u16 port_id, enum afe_cal_mode afe_cal_mode);
+int afe_port_start(u16 port_id, union afe_port_config *afe_config,
+ u32 rate);
+int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
+ u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
+ struct afe_enc_config *enc_config);
+int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
+ int l_ch, int r_ch, u32 enable);
+int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib);
+int afe_port_stop_nowait(int port_id);
+int afe_apply_gain(u16 port_id, u16 gain);
+int afe_q6_interface_prepare(void);
+int afe_get_port_type(u16 port_id);
+int q6afe_audio_client_buf_alloc_contiguous(unsigned int dir,
+ struct afe_audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt);
+struct afe_audio_client *q6afe_audio_client_alloc(void *priv);
+int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
+ struct afe_audio_client *ac);
+void q6afe_audio_client_free(struct afe_audio_client *ac);
+/* if port_id is virtual, convert to physical..
+ * if port_id is already physical, return physical
+ */
+int afe_convert_virtual_to_portid(u16 port_id);
+
+int afe_pseudo_port_start_nowait(u16 port_id);
+int afe_pseudo_port_stop_nowait(u16 port_id);
+int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg);
+int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg);
+int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg);
+int afe_set_digital_codec_core_clock(u16 port_id,
+ struct afe_digital_clk_cfg *cfg);
+int afe_set_lpass_internal_digital_codec_clock(u16 port_id,
+ struct afe_digital_clk_cfg *cfg);
+int afe_enable_lpass_core_shared_clock(u16 port_id, u32 enable);
+
+int q6afe_check_osr_clk_freq(u32 freq);
+
+int afe_send_spdif_clk_cfg(struct afe_param_id_spdif_clk_cfg *cfg,
+ u16 port_id);
+int afe_send_spdif_ch_status_cfg(struct afe_param_id_spdif_ch_status_cfg
+ *ch_status_cfg, u16 port_id);
+
+int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port,
+ u32 rate);
+
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 mad_enable);
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type);
+enum afe_mad_type afe_port_get_mad_type(u16 port_id);
+int afe_set_config(enum afe_config_type config_type, void *config_data,
+ int arg);
+void afe_clear_config(enum afe_config_type config);
+bool afe_has_config(enum afe_config_type config);
+
+void afe_set_aanc_info(struct aanc_data *aanc_info);
+int afe_port_group_set_param(u16 group_id,
+ union afe_port_group_config *afe_group_config);
+int afe_port_group_enable(u16 group_id,
+ union afe_port_group_config *afe_group_config, u16 enable);
+int afe_unmap_rtac_block(uint32_t *mem_map_handle);
+int afe_map_rtac_block(struct rtac_cal_block_data *cal_block);
+int afe_send_slot_mapping_cfg(
+ struct afe_param_id_slot_mapping_cfg *slot_mapping_cfg,
+ u16 port_id);
+int afe_send_custom_tdm_header_cfg(
+ struct afe_param_id_custom_tdm_header_cfg *custom_tdm_header_cfg,
+ u16 port_id);
+int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
+ u32 rate);
+#endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
new file mode 100644
index 0000000..7321481
--- /dev/null
+++ b/include/sound/q6asm-v2.h
@@ -0,0 +1,637 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6_ASM_V2_H__
+#define __Q6_ASM_V2_H__
+
+#include <linux/qdsp6v2/apr.h>
+#include <linux/qdsp6v2/rtac.h>
+#include <sound/apr_audio-v2.h>
+#include <linux/list.h>
+#include <linux/msm_ion.h>
+
+#define IN 0x000
+#define OUT 0x001
+#define CH_MODE_MONO 0x001
+#define CH_MODE_STEREO 0x002
+
+#define FORMAT_LINEAR_PCM 0x0000
+#define FORMAT_DTMF 0x0001
+#define FORMAT_ADPCM 0x0002
+#define FORMAT_YADPCM 0x0003
+#define FORMAT_MP3 0x0004
+#define FORMAT_MPEG4_AAC 0x0005
+#define FORMAT_AMRNB 0x0006
+#define FORMAT_AMRWB 0x0007
+#define FORMAT_V13K 0x0008
+#define FORMAT_EVRC 0x0009
+#define FORMAT_EVRCB 0x000a
+#define FORMAT_EVRCWB 0x000b
+#define FORMAT_MIDI 0x000c
+#define FORMAT_SBC 0x000d
+#define FORMAT_WMA_V10PRO 0x000e
+#define FORMAT_WMA_V9 0x000f
+#define FORMAT_AMR_WB_PLUS 0x0010
+#define FORMAT_MPEG4_MULTI_AAC 0x0011
+#define FORMAT_MULTI_CHANNEL_LINEAR_PCM 0x0012
+#define FORMAT_AC3 0x0013
+#define FORMAT_EAC3 0x0014
+#define FORMAT_MP2 0x0015
+#define FORMAT_FLAC 0x0016
+#define FORMAT_ALAC 0x0017
+#define FORMAT_VORBIS 0x0018
+#define FORMAT_APE 0x0019
+#define FORMAT_G711_ALAW_FS 0x001a
+#define FORMAT_G711_MLAW_FS 0x001b
+#define FORMAT_DTS 0x001c
+#define FORMAT_DSD 0x001d
+
+#define ENCDEC_SBCBITRATE 0x0001
+#define ENCDEC_IMMEDIATE_DECODE 0x0002
+#define ENCDEC_CFG_BLK 0x0003
+
+#define CMD_PAUSE 0x0001
+#define CMD_FLUSH 0x0002
+#define CMD_EOS 0x0003
+#define CMD_CLOSE 0x0004
+#define CMD_OUT_FLUSH 0x0005
+#define CMD_SUSPEND 0x0006
+
+/* bit 0:1 represents priority of stream */
+#define STREAM_PRIORITY_NORMAL 0x0000
+#define STREAM_PRIORITY_LOW 0x0001
+#define STREAM_PRIORITY_HIGH 0x0002
+
+/* bit 4 represents META enable of encoded data buffer */
+#define BUFFER_META_ENABLE 0x0010
+
+/* bit 5 represents timestamp */
+/* bit 5 - 0 -- ASM_DATA_EVENT_READ_DONE will have relative time-stamp*/
+/* bit 5 - 1 -- ASM_DATA_EVENT_READ_DONE will have absolute time-stamp*/
+#define ABSOLUTE_TIMESTAMP_ENABLE 0x0020
+
+/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
+#define SR_CM_NOTIFY_ENABLE 0x0004
+
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */
+#define SYNC_IO_MODE 0x0001
+#define ASYNC_IO_MODE 0x0002
+#define COMPRESSED_IO 0x0040
+#define COMPRESSED_STREAM_IO 0x0080
+#define NT_MODE 0x0400
+
+#define NO_TIMESTAMP 0xFF00
+#define SET_TIMESTAMP 0x0000
+
+#define SOFT_PAUSE_ENABLE 1
+#define SOFT_PAUSE_DISABLE 0
+
+#define ASM_ACTIVE_STREAMS_ALLOWED 0x8
+/* Control session is used for mapping calibration memory */
+#define ASM_CONTROL_SESSION (ASM_ACTIVE_STREAMS_ALLOWED + 1)
+
+#define ASM_SHIFT_GAPLESS_MODE_FLAG 31
+#define ASM_SHIFT_LAST_BUFFER_FLAG 30
+
+#define ASM_LITTLE_ENDIAN 0
+#define ASM_BIG_ENDIAN 1
+
+/* PCM_MEDIA_FORMAT_Version */
+enum {
+ PCM_MEDIA_FORMAT_V2 = 0,
+ PCM_MEDIA_FORMAT_V3,
+ PCM_MEDIA_FORMAT_V4,
+};
+
+/* PCM format modes in DSP */
+enum {
+ DEFAULT_QF = 0,
+ Q15 = 15,
+ Q23 = 23,
+ Q31 = 31,
+};
+
+/* payload structure bytes */
+#define READDONE_IDX_STATUS 0
+#define READDONE_IDX_BUFADD_LSW 1
+#define READDONE_IDX_BUFADD_MSW 2
+#define READDONE_IDX_MEMMAP_HDL 3
+#define READDONE_IDX_SIZE 4
+#define READDONE_IDX_OFFSET 5
+#define READDONE_IDX_LSW_TS 6
+#define READDONE_IDX_MSW_TS 7
+#define READDONE_IDX_FLAGS 8
+#define READDONE_IDX_NUMFRAMES 9
+#define READDONE_IDX_SEQ_ID 10
+
+#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */
+#define SOFT_PAUSE_STEP 0 /* Step value 0ms or 0us */
+enum {
+ SOFT_PAUSE_CURVE_LINEAR = 0,
+ SOFT_PAUSE_CURVE_EXP,
+ SOFT_PAUSE_CURVE_LOG,
+};
+
+#define SOFT_VOLUME_PERIOD 30 /* ramp up/down for 30ms */
+#define SOFT_VOLUME_STEP 0 /* Step value 0ms or 0us */
+enum {
+ SOFT_VOLUME_CURVE_LINEAR = 0,
+ SOFT_VOLUME_CURVE_EXP,
+ SOFT_VOLUME_CURVE_LOG,
+};
+
+#define SOFT_VOLUME_INSTANCE_1 1
+#define SOFT_VOLUME_INSTANCE_2 2
+
+typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv);
+
+struct audio_buffer {
+ dma_addr_t phys;
+ void *data;
+ uint32_t used;
+ uint32_t size;/* size of buffer */
+ uint32_t actual_size; /* actual number of bytes read by DSP */
+ struct ion_handle *handle;
+ struct ion_client *client;
+};
+
+struct audio_aio_write_param {
+ phys_addr_t paddr;
+ uint32_t len;
+ uint32_t uid;
+ uint32_t lsw_ts;
+ uint32_t msw_ts;
+ uint32_t flags;
+ uint32_t metadata_len;
+ uint32_t last_buffer;
+};
+
+struct audio_aio_read_param {
+ phys_addr_t paddr;
+ uint32_t len;
+ uint32_t uid;
+ uint32_t flags;/*meta data flags*/
+};
+
+struct audio_port_data {
+ struct audio_buffer *buf;
+ uint32_t max_buf_cnt;
+ uint32_t dsp_buf;
+ uint32_t cpu_buf;
+ struct list_head mem_map_handle;
+ uint32_t tmp_hdl;
+ /* read or write locks */
+ struct mutex lock;
+ spinlock_t dsp_lock;
+};
+
+struct shared_io_config {
+ uint32_t format;
+ uint16_t bits_per_sample;
+ uint32_t rate;
+ uint32_t channels;
+ uint16_t sample_word_size;
+ uint32_t bufsz;
+ uint32_t bufcnt;
+};
+
+struct audio_client {
+ int session;
+ app_cb cb;
+ atomic_t cmd_state;
+ /* Relative or absolute TS */
+ atomic_t time_flag;
+ atomic_t nowait_cmd_cnt;
+ atomic_t mem_state;
+ void *priv;
+ uint32_t io_mode;
+ uint64_t time_stamp;
+ struct apr_svc *apr;
+ struct apr_svc *mmap_apr;
+ struct apr_svc *apr2;
+ struct mutex cmd_lock;
+ /* idx:1 out port, 0: in port*/
+ struct audio_port_data port[2];
+ wait_queue_head_t cmd_wait;
+ wait_queue_head_t time_wait;
+ wait_queue_head_t mem_wait;
+ int perf_mode;
+ int stream_id;
+ struct device *dev;
+ int topology;
+ int app_type;
+ /* audio cache operations fptr*/
+ int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
+ atomic_t unmap_cb_success;
+ atomic_t reset;
+ /* holds latest DSP pipeline delay */
+ uint32_t path_delay;
+ /* shared io */
+ struct audio_buffer shared_pos_buf;
+ struct shared_io_config config;
+};
+
+void q6asm_audio_client_free(struct audio_client *ac);
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv);
+
+struct audio_client *q6asm_get_audio_client(int session_id);
+
+int q6asm_audio_client_buf_alloc(unsigned int dir/* 1:Out,0:In */,
+ struct audio_client *ac,
+ unsigned int bufsz,
+ uint32_t bufcnt);
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir
+ /* 1:Out,0:In */,
+ struct audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt);
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+ struct audio_client *ac);
+
+int q6asm_open_read(struct audio_client *ac, uint32_t format
+ /*, uint16_t bits_per_sample*/);
+
+int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
+int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
+int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
+int q6asm_open_write(struct audio_client *ac, uint32_t format
+ /*, uint16_t bits_per_sample*/);
+
+int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
+int q6asm_open_shared_io(struct audio_client *ac,
+ struct shared_io_config *c, int dir);
+
+int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
+int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
+int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode);
+
+int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode);
+
+int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode);
+
+int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
+ uint32_t passthrough_flag);
+
+int q6asm_open_read_write(struct audio_client *ac,
+ uint32_t rd_format,
+ uint32_t wr_format);
+
+int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format,
+ uint32_t wr_format, bool is_meta_data_mode,
+ uint32_t bits_per_sample, bool overwrite_topology,
+ int topology);
+
+int q6asm_open_loopback_v2(struct audio_client *ac,
+ uint16_t bits_per_sample);
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t flags);
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t flags);
+
+int q6asm_async_write(struct audio_client *ac,
+ struct audio_aio_write_param *param);
+
+int q6asm_async_read(struct audio_client *ac,
+ struct audio_aio_read_param *param);
+
+int q6asm_read(struct audio_client *ac);
+int q6asm_read_v2(struct audio_client *ac, uint32_t len);
+int q6asm_read_nolock(struct audio_client *ac);
+
+int q6asm_memory_map(struct audio_client *ac, phys_addr_t buf_add,
+ int dir, uint32_t bufsz, uint32_t bufcnt);
+
+int q6asm_memory_unmap(struct audio_client *ac, phys_addr_t buf_add,
+ int dir);
+
+struct audio_buffer *q6asm_shared_io_buf(struct audio_client *ac, int dir);
+
+int q6asm_shared_io_free(struct audio_client *ac, int dir);
+
+int q6asm_get_shared_pos(struct audio_client *ac, uint32_t *si, uint32_t *msw,
+ uint32_t *lsw);
+
+int q6asm_map_rtac_block(struct rtac_cal_block_data *cal_block);
+
+int q6asm_unmap_rtac_block(uint32_t *mem_map_handle);
+
+int q6asm_send_cal(struct audio_client *ac);
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts);
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts);
+
+int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id);
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable);
+
+int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable);
+
+int q6asm_cmd(struct audio_client *ac, int cmd);
+
+int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id);
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+
+int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id);
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac,
+ uint32_t *size, uint32_t *idx);
+
+int q6asm_cpu_buf_release(int dir, struct audio_client *ac);
+
+void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
+ uint32_t *size, uint32_t *idx);
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac);
+
+/* File format specific configurations to be added below */
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+ uint32_t frames_per_buf,
+ uint32_t sample_rate, uint32_t channels,
+ uint32_t bit_rate,
+ uint32_t mode, uint32_t format);
+
+int q6asm_enc_cfg_blk_g711(struct audio_client *ac,
+ uint32_t frames_per_buf,
+ uint32_t sample_rate);
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels);
+
+int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ bool use_default_chmap, bool use_back_flavor,
+ u8 *channel_map);
+
+int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, bool use_default_chmap,
+ bool use_back_flavor, u8 *channel_map,
+ uint16_t sample_word_size);
+
+int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, bool use_default_chmap,
+ bool use_back_flavor, u8 *channel_map,
+ uint16_t sample_word_size, uint16_t endianness,
+ uint16_t mode);
+
+int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample);
+
+int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size);
+
+int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode);
+
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+ uint32_t num_channels);
+
+int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
+ uint32_t rate, uint32_t channels);
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+ uint32_t sbr_ps);
+
+int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
+ uint16_t sce_left, uint16_t sce_right);
+
+int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff);
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t min_rate, uint16_t max_rate,
+ uint16_t reduced_rate_level, uint16_t rate_modulation_cmd);
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t min_rate, uint16_t max_rate,
+ uint16_t rate_modulation_cmd);
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t band_mode, uint16_t dtx_enable);
+
+int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t band_mode, uint16_t dtx_enable);
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels);
+
+int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample);
+
+int q6asm_media_format_block_pcm_format_support_v2(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, int stream_id,
+ bool use_default_chmap, char *channel_map);
+
+int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size);
+
+int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode);
+
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map);
+
+int q6asm_media_format_block_multi_ch_pcm_v2(
+ struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample);
+
+int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size);
+
+int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode);
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg);
+
+int q6asm_stream_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id);
+
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg);
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+ void *cfg, int stream_id);
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+ void *cfg, int stream_id);
+
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+ struct asm_amrwbplus_cfg *cfg);
+
+int q6asm_stream_media_format_block_flac(struct audio_client *ac,
+ struct asm_flac_cfg *cfg, int stream_id);
+
+int q6asm_media_format_block_alac(struct audio_client *ac,
+ struct asm_alac_cfg *cfg, int stream_id);
+
+int q6asm_media_format_block_g711(struct audio_client *ac,
+ struct asm_g711_dec_cfg *cfg, int stream_id);
+
+int q6asm_stream_media_format_block_vorbis(struct audio_client *ac,
+ struct asm_vorbis_cfg *cfg, int stream_id);
+
+int q6asm_media_format_block_ape(struct audio_client *ac,
+ struct asm_ape_cfg *cfg, int stream_id);
+
+int q6asm_media_format_block_dsd(struct audio_client *ac,
+ struct asm_dsd_cfg *cfg, int stream_id);
+
+int q6asm_ds1_set_endp_params(struct audio_client *ac,
+ int param_id, int param_value);
+
+/* Send stream based end params */
+int q6asm_ds1_set_stream_endp_params(struct audio_client *ac, int param_id,
+ int param_value, int stream_id);
+
+/* PP specific */
+int q6asm_equalizer(struct audio_client *ac, void *eq);
+
+/* Send Volume Command */
+int q6asm_set_volume(struct audio_client *ac, int volume);
+
+/* Send Volume Command */
+int q6asm_set_volume_v2(struct audio_client *ac, int volume, int instance);
+
+/* DTS Eagle Params */
+int q6asm_dts_eagle_set(struct audio_client *ac, int param_id, uint32_t size,
+ void *data, struct param_outband *po, int m_id);
+int q6asm_dts_eagle_get(struct audio_client *ac, int param_id, uint32_t size,
+ void *data, struct param_outband *po, int m_id);
+
+/* Set SoftPause Params */
+int q6asm_set_softpause(struct audio_client *ac,
+ struct asm_softpause_params *param);
+
+/* Set Softvolume Params */
+int q6asm_set_softvolume(struct audio_client *ac,
+ struct asm_softvolume_params *param);
+
+/* Set Softvolume Params */
+int q6asm_set_softvolume_v2(struct audio_client *ac,
+ struct asm_softvolume_params *param, int instance);
+
+/* Send left-right channel gain */
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain);
+
+/* Send multi channel gain */
+int q6asm_set_multich_gain(struct audio_client *ac, uint32_t channels,
+ uint32_t *gains, uint8_t *ch_map, bool use_default);
+
+/* Enable Mute/unmute flag */
+int q6asm_set_mute(struct audio_client *ac, int muteflag);
+
+int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp);
+
+int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp);
+
+int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
+ uint32_t params_length);
+
+/* Client can set the IO mode to either AIO/SIO mode */
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
+
+/* Get Service ID for APR communication */
+int q6asm_get_apr_service_id(int session_id);
+
+/* Common format block without any payload */
+int q6asm_media_format_block(struct audio_client *ac, uint32_t format);
+
+/* Send the meta data to remove initial and trailing silence */
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+ uint32_t trailing_samples);
+
+/* Send the stream meta data to remove initial and trailing silence */
+int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id,
+ uint32_t initial_samples, uint32_t trailing_samples);
+
+int q6asm_get_asm_topology(int session_id);
+int q6asm_get_asm_app_type(int session_id);
+
+int q6asm_send_mtmx_strtr_window(struct audio_client *ac,
+ struct asm_session_mtmx_strtr_param_window_v2_t *window_param,
+ uint32_t param_id);
+
+/* Retrieve the current DSP path delay */
+int q6asm_get_path_delay(struct audio_client *ac);
+
+/* Helper functions to retrieve data from token */
+uint8_t q6asm_get_buf_index_from_token(uint32_t token);
+uint8_t q6asm_get_stream_id_from_token(uint32_t token);
+
+#endif /* __Q6_ASM_H__ */
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
new file mode 100644
index 0000000..fd14f33
--- /dev/null
+++ b/include/sound/q6audio-v2.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2012-2013, 2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _Q6_AUDIO_H_
+#define _Q6_AUDIO_H_
+
+#include <linux/qdsp6v2/apr.h>
+
+enum {
+ LEGACY_PCM_MODE = 0,
+ LOW_LATENCY_PCM_MODE,
+ ULTRA_LOW_LATENCY_PCM_MODE,
+ ULL_POST_PROCESSING_PCM_MODE,
+};
+
+
+int q6audio_get_port_index(u16 port_id);
+
+int q6audio_convert_virtual_to_portid(u16 port_id);
+
+int q6audio_validate_port(u16 port_id);
+
+int q6audio_is_digital_pcm_interface(u16 port_id);
+
+int q6audio_get_port_id(u16 port_id);
+
+#endif
diff --git a/include/sound/q6core.h b/include/sound/q6core.h
new file mode 100644
index 0000000..0b8309a
--- /dev/null
+++ b/include/sound/q6core.h
@@ -0,0 +1,159 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __Q6CORE_H__
+#define __Q6CORE_H__
+#include <linux/qdsp6v2/apr.h>
+
+
+
+#define AVCS_CMD_ADSP_EVENT_GET_STATE 0x0001290C
+#define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D
+
+bool q6core_is_adsp_ready(void);
+
+#define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919
+#define DTS_EAGLE_LICENSE_ID 0x00028346
+struct adsp_dts_eagle {
+ struct apr_hdr hdr;
+ uint32_t id;
+ uint32_t overwrite;
+ uint32_t size;
+ char data[];
+};
+int core_dts_eagle_set(int size, char *data);
+int core_dts_eagle_get(int id, int size, char *data);
+
+#define ADSP_CMD_SET_DOLBY_MANUFACTURER_ID 0x00012918
+
+struct adsp_dolby_manufacturer_id {
+ struct apr_hdr hdr;
+ int manufacturer_id;
+};
+
+uint32_t core_set_dolby_manufacturer_id(int manufacturer_id);
+
+/* Dolby Surround1 Module License ID. This ID is used as an identifier
+ * for DS1 license via ADSP generic license mechanism.
+ * Please refer AVCS_CMD_SET_LICENSE for more details.
+ */
+#define DOLBY_DS1_LICENSE_ID 0x00000001
+
+#define AVCS_CMD_SET_LICENSE 0x00012919
+struct avcs_cmd_set_license {
+ struct apr_hdr hdr;
+ uint32_t id; /**< A unique ID used to refer to this license */
+ uint32_t overwrite;
+ /* 0 = do not overwrite an existing license with this id.
+ * 1 = overwrite an existing license with this id.
+ */
+ uint32_t size;
+ /**< Size in bytes of the license data following this header. */
+ /* uint8_t* data , data and padding follows this structure
+ * total packet size needs to be multiple of 4 Bytes
+ */
+
+};
+
+#define AVCS_CMD_GET_LICENSE_VALIDATION_RESULT 0x0001291A
+struct avcs_cmd_get_license_validation_result {
+ struct apr_hdr hdr;
+ uint32_t id; /**< A unique ID used to refer to this license */
+};
+
+#define AVCS_CMDRSP_GET_LICENSE_VALIDATION_RESULT 0x0001291B
+struct avcs_cmdrsp_get_license_validation_result {
+ uint32_t result;
+ /* ADSP_EOK if the license validation result was successfully retrieved.
+ * ADSP_ENOTEXIST if there is no license with the given id.
+ * ADSP_ENOTIMPL if there is no validation function for a license
+ * with this id.
+ */
+ uint32_t size;
+ /* Length in bytes of the result that follows this structure*/
+};
+
+/* Set Q6 topologies */
+/*
+ * Registers custom topologies in the aDSP for
+ * use in audio, voice, AFE and LSM.
+ */
+
+
+#define AVCS_CMD_SHARED_MEM_MAP_REGIONS 0x00012924
+#define AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00012925
+#define AVCS_CMD_SHARED_MEM_UNMAP_REGIONS 0x00012926
+
+
+#define AVCS_CMD_REGISTER_TOPOLOGIES 0x00012923
+
+/* The payload for the AVCS_CMD_REGISTER_TOPOLOGIES command */
+struct avcs_cmd_register_topologies {
+ struct apr_hdr hdr;
+ uint32_t payload_addr_lsw;
+ /* Lower 32 bits of the topology buffer address. */
+
+ uint32_t payload_addr_msw;
+ /* Upper 32 bits of the topology buffer address. */
+
+ uint32_t mem_map_handle;
+ /* Unique identifier for an address.
+ * -This memory map handle is returned by the aDSP through the
+ * memory map command.
+ * -NULL mem_map_handle is interpreted as in-band parameter
+ * passing.
+ * -Client has the flexibility to choose in-band or out-of-band.
+ * -Out-of-band is recommended in this case.
+ */
+
+ uint32_t payload_size;
+ /* Size in bytes of the valid data in the topology buffer. */
+} __packed;
+
+
+#define AVCS_CMD_DEREGISTER_TOPOLOGIES 0x0001292a
+
+/* The payload for the AVCS_CMD_DEREGISTER_TOPOLOGIES command */
+struct avcs_cmd_deregister_topologies {
+ struct apr_hdr hdr;
+ uint32_t payload_addr_lsw;
+ /* Lower 32 bits of the topology buffer address. */
+
+ uint32_t payload_addr_msw;
+ /* Upper 32 bits of the topology buffer address. */
+
+ uint32_t mem_map_handle;
+ /* Unique identifier for an address.
+ * -This memory map handle is returned by the aDSP through the
+ * memory map command.
+ * -NULL mem_map_handle is interpreted as in-band parameter
+ * passing.
+ * -Client has the flexibility to choose in-band or out-of-band.
+ * -Out-of-band is recommended in this case.
+ */
+
+ uint32_t payload_size;
+ /* Size in bytes of the valid data in the topology buffer. */
+
+ uint32_t mode;
+ /* 1: Deregister selected topologies
+ * 2: Deregister all topologies
+ */
+} __packed;
+
+#define AVCS_MODE_DEREGISTER_ALL_CUSTOM_TOPOLOGIES 2
+
+
+int32_t core_set_license(uint32_t key, uint32_t module_id);
+int32_t core_get_license_status(uint32_t module_id);
+
+#endif /* __Q6CORE_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
new file mode 100644
index 0000000..22a62da
--- /dev/null
+++ b/include/sound/q6lsm.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6LSM_H__
+#define __Q6LSM_H__
+
+#include <linux/list.h>
+#include <linux/msm_ion.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <linux/qdsp6v2/apr.h>
+
+#define MAX_NUM_CONFIDENCE 20
+
+typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv);
+
+struct lsm_sound_model {
+ dma_addr_t phys;
+ void *data;
+ size_t size; /* size of buffer */
+ uint32_t actual_size; /* actual number of bytes read by DSP */
+ struct ion_handle *handle;
+ struct ion_client *client;
+ uint32_t mem_map_handle;
+};
+
+struct snd_lsm_event_status_v2 {
+ uint16_t status;
+ uint16_t payload_size;
+ uint8_t confidence_value[0];
+};
+
+struct lsm_lab_buffer {
+ dma_addr_t phys;
+ void *data;
+ size_t size;
+ struct ion_handle *handle;
+ struct ion_client *client;
+ uint32_t mem_map_handle;
+};
+
+struct lsm_lab_hw_params {
+ u16 sample_rate;
+ u16 sample_size;
+ u32 buf_sz;
+ u32 period_count;
+};
+
+struct lsm_client {
+ int session;
+ lsm_app_cb cb;
+ atomic_t cmd_state;
+ void *priv;
+ struct apr_svc *apr;
+ struct apr_svc *mmap_apr;
+ struct mutex cmd_lock;
+ struct lsm_sound_model sound_model;
+ wait_queue_head_t cmd_wait;
+ uint32_t cmd_err_code;
+ uint16_t mode;
+ uint16_t connect_to_port;
+ uint8_t num_confidence_levels;
+ uint8_t *confidence_levels;
+ bool opened;
+ bool started;
+ dma_addr_t lsm_cal_phy_addr;
+ uint32_t lsm_cal_size;
+ uint32_t app_id;
+ bool lab_enable;
+ bool lab_started;
+ struct lsm_lab_buffer *lab_buffer;
+ struct lsm_lab_hw_params hw_params;
+ bool use_topology;
+};
+
+struct lsm_stream_cmd_open_tx {
+ struct apr_hdr hdr;
+ uint16_t app_id;
+ uint16_t reserved;
+ uint32_t sampling_rate;
+} __packed;
+
+struct lsm_stream_cmd_open_tx_v2 {
+ struct apr_hdr hdr;
+ uint32_t topology_id;
+} __packed;
+
+struct lsm_custom_topologies {
+ struct apr_hdr hdr;
+ uint32_t data_payload_addr_lsw;
+ uint32_t data_payload_addr_msw;
+ uint32_t mem_map_handle;
+ uint32_t buffer_size;
+} __packed;
+
+struct lsm_param_size_reserved {
+ uint16_t param_size;
+ uint16_t reserved;
+} __packed;
+
+union lsm_param_size {
+ uint32_t param_size;
+ struct lsm_param_size_reserved sr;
+} __packed;
+
+struct lsm_param_payload_common {
+ uint32_t module_id;
+ uint32_t param_id;
+ union lsm_param_size p_size;
+} __packed;
+
+struct lsm_param_op_mode {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ uint16_t mode;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_connect_to_port {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ /* AFE port id that receives voice wake up data */
+ uint16_t port_id;
+ uint16_t reserved;
+} __packed;
+
+
+/*
+ * This param cannot be sent in this format.
+ * The actual number of confidence level values
+ * need to appended to this param payload.
+ */
+struct lsm_param_min_confidence_levels {
+ struct lsm_param_payload_common common;
+ uint8_t num_confidence_levels;
+} __packed;
+
+struct lsm_set_params_hdr {
+ uint32_t data_payload_size;
+ uint32_t data_payload_addr_lsw;
+ uint32_t data_payload_addr_msw;
+ uint32_t mem_map_handle;
+} __packed;
+
+struct lsm_cmd_set_params {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr param_hdr;
+} __packed;
+
+struct lsm_cmd_set_params_conf {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr params_hdr;
+ struct lsm_param_min_confidence_levels conf_payload;
+} __packed;
+
+struct lsm_cmd_set_opmode_connectport {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr params_hdr;
+ struct lsm_param_connect_to_port connect_to_port;
+ struct lsm_param_op_mode op_mode;
+} __packed;
+
+struct lsm_param_epd_thres {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ uint32_t epd_begin;
+ uint32_t epd_end;
+} __packed;
+
+struct lsm_cmd_set_epd_threshold {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr param_hdr;
+ struct lsm_param_epd_thres epd_thres;
+} __packed;
+
+struct lsm_param_gain {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ uint16_t gain;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_cmd_set_gain {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr param_hdr;
+ struct lsm_param_gain lsm_gain;
+} __packed;
+
+struct lsm_cmd_reg_snd_model {
+ struct apr_hdr hdr;
+ uint32_t model_size;
+ uint32_t model_addr_lsw;
+ uint32_t model_addr_msw;
+ uint32_t mem_map_handle;
+} __packed;
+
+struct lsm_lab_enable {
+ struct lsm_param_payload_common common;
+ uint16_t enable;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_params_lab_enable {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr params_hdr;
+ struct lsm_lab_enable lab_enable;
+} __packed;
+
+struct lsm_lab_config {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ uint32_t wake_up_latency_ms;
+} __packed;
+
+
+struct lsm_params_lab_config {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr params_hdr;
+ struct lsm_lab_config lab_config;
+} __packed;
+
+struct lsm_cmd_read {
+ struct apr_hdr hdr;
+ uint32_t buf_addr_lsw;
+ uint32_t buf_addr_msw;
+ uint32_t mem_map_handle;
+ uint32_t buf_size;
+} __packed;
+
+struct lsm_cmd_read_done {
+ struct apr_hdr hdr;
+ uint32_t status;
+ uint32_t buf_addr_lsw;
+ uint32_t buf_addr_msw;
+ uint32_t mem_map_handle;
+ uint32_t total_size;
+ uint32_t offset;
+ uint32_t timestamp_lsw;
+ uint32_t timestamp_msw;
+ uint32_t flags;
+} __packed;
+
+struct lsm_client *q6lsm_client_alloc(lsm_app_cb cb, void *priv);
+void q6lsm_client_free(struct lsm_client *client);
+int q6lsm_open(struct lsm_client *client, uint16_t app_id);
+int q6lsm_start(struct lsm_client *client, bool wait);
+int q6lsm_stop(struct lsm_client *client, bool wait);
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
+ bool allocate_module_data);
+int q6lsm_snd_model_buf_free(struct lsm_client *client);
+int q6lsm_close(struct lsm_client *client);
+int q6lsm_register_sound_model(struct lsm_client *client,
+ enum lsm_detection_mode mode,
+ bool detectfailure);
+int q6lsm_set_data(struct lsm_client *client,
+ enum lsm_detection_mode mode,
+ bool detectfailure);
+int q6lsm_deregister_sound_model(struct lsm_client *client);
+void set_lsm_port(int lsm_port);
+int get_lsm_port(void);
+int q6lsm_lab_control(struct lsm_client *client, u32 enable);
+int q6lsm_stop_lab(struct lsm_client *client);
+int q6lsm_read(struct lsm_client *client, struct lsm_cmd_read *read);
+int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc);
+int q6lsm_set_one_param(struct lsm_client *client,
+ struct lsm_params_info *p_info, void *data,
+ enum LSM_PARAM_TYPE param_type);
+void q6lsm_sm_set_param_data(struct lsm_client *client,
+ struct lsm_params_info *p_info,
+ size_t *offset);
+#endif /* __Q6LSM_H__ */
diff --git a/include/sound/voice_params.h b/include/sound/voice_params.h
new file mode 100644
index 0000000..43e3b9d
--- /dev/null
+++ b/include/sound/voice_params.h
@@ -0,0 +1,14 @@
+#ifndef __VOICE_PARAMS_H__
+#define __VOICE_PARAMS_H__
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+enum voice_lch_mode {
+ VOICE_LCH_START = 1,
+ VOICE_LCH_STOP
+};
+
+#define SNDRV_VOICE_IOCTL_LCH _IOW('U', 0x00, enum voice_lch_mode)
+
+#endif
diff --git a/include/sound/voice_svc.h b/include/sound/voice_svc.h
new file mode 100644
index 0000000..035053f
--- /dev/null
+++ b/include/sound/voice_svc.h
@@ -0,0 +1,47 @@
+#ifndef __VOICE_SVC_H__
+#define __VOICE_SVC_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define VOICE_SVC_DRIVER_NAME "voice_svc"
+
+#define VOICE_SVC_MVM_STR "MVM"
+#define VOICE_SVC_CVS_STR "CVS"
+#define MAX_APR_SERVICE_NAME_LEN 64
+
+#define MSG_REGISTER 0x1
+#define MSG_REQUEST 0x2
+#define MSG_RESPONSE 0x3
+
+struct voice_svc_write_msg {
+ __u32 msg_type;
+ __u8 payload[0];
+};
+
+struct voice_svc_register {
+ char svc_name[MAX_APR_SERVICE_NAME_LEN];
+ __u32 src_port;
+ __u8 reg_flag;
+};
+
+struct voice_svc_cmd_response {
+ __u32 src_port;
+ __u32 dest_port;
+ __u32 token;
+ __u32 opcode;
+ __u32 payload_size;
+ __u8 payload[0];
+};
+
+struct voice_svc_cmd_request {
+ char svc_name[MAX_APR_SERVICE_NAME_LEN];
+ __u32 src_port;
+ __u32 dest_port;
+ __u32 token;
+ __u32 opcode;
+ __u32 payload_size;
+ __u8 payload[0];
+};
+
+#endif
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index ae6fa2f..6ce3d16 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -62,6 +62,7 @@
header-y += auto_fs4.h
header-y += auto_fs.h
header-y += auxvec.h
+header-y += avtimer.h
header-y += ax25.h
header-y += b1lli.h
header-y += baycom.h
@@ -281,6 +282,23 @@
header-y += mroute.h
header-y += msdos_fs.h
header-y += msg.h
+header-y += msm_audio.h
+header-y += msm_audio_aac.h
+header-y += msm_audio_ac3.h
+header-y += msm_audio_amrnb.h
+header-y += msm_audio_amrwb.h
+header-y += msm_audio_amrwbplus.h
+header-y += msm_audio_calibration.h
+header-y += msm_audio_mvs.h
+header-y += msm_audio_qcp.h
+header-y += msm_audio_sbc.h
+header-y += msm_audio_voicememo.h
+header-y += msm_audio_wma.h
+header-y += msm_audio_wmapro.h
+header-y += msm_audio_alac.h
+header-y += msm_audio_ape.h
+header-y += msm_audio_g711.h
+header-y += msm_audio_g711_dec.h
header-y += msm_ion.h
header-y += msm_ipc.h
header-y += msm_kgsl.h
diff --git a/include/uapi/linux/avtimer.h b/include/uapi/linux/avtimer.h
new file mode 100644
index 0000000..96b5483
--- /dev/null
+++ b/include/uapi/linux/avtimer.h
@@ -0,0 +1,10 @@
+#ifndef _UAPI_AVTIMER_H
+#define _UAPI_AVTIMER_H
+
+#include <linux/ioctl.h>
+
+#define MAJOR_NUM 100
+
+#define IOCTL_GET_AVTIMER_TICK _IOR(MAJOR_NUM, 0, uint64_t)
+
+#endif
diff --git a/include/uapi/linux/msm_audio.h b/include/uapi/linux/msm_audio.h
new file mode 100644
index 0000000..bde27d1
--- /dev/null
+++ b/include/uapi/linux/msm_audio.h
@@ -0,0 +1,464 @@
+/* include/linux/msm_audio.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2012, 2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _UAPI_LINUX_MSM_AUDIO_H
+#define _UAPI_LINUX_MSM_AUDIO_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* PCM Audio */
+
+#define AUDIO_IOCTL_MAGIC 'a'
+
+#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned int)
+#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned int)
+#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned int)
+#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, \
+ struct msm_audio_config)
+#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, \
+ struct msm_audio_config)
+#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, \
+ struct msm_audio_stats)
+#define AUDIO_ENABLE_AUDPP _IOW(AUDIO_IOCTL_MAGIC, 6, unsigned int)
+#define AUDIO_SET_ADRC _IOW(AUDIO_IOCTL_MAGIC, 7, unsigned int)
+#define AUDIO_SET_EQ _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned int)
+#define AUDIO_SET_RX_IIR _IOW(AUDIO_IOCTL_MAGIC, 9, unsigned int)
+#define AUDIO_SET_VOLUME _IOW(AUDIO_IOCTL_MAGIC, 10, unsigned int)
+#define AUDIO_PAUSE _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned int)
+#define AUDIO_PLAY_DTMF _IOW(AUDIO_IOCTL_MAGIC, 12, unsigned int)
+#define AUDIO_GET_EVENT _IOR(AUDIO_IOCTL_MAGIC, 13, \
+ struct msm_audio_event)
+#define AUDIO_ABORT_GET_EVENT _IOW(AUDIO_IOCTL_MAGIC, 14, unsigned int)
+#define AUDIO_REGISTER_PMEM _IOW(AUDIO_IOCTL_MAGIC, 15, unsigned int)
+#define AUDIO_DEREGISTER_PMEM _IOW(AUDIO_IOCTL_MAGIC, 16, unsigned int)
+#define AUDIO_ASYNC_WRITE _IOW(AUDIO_IOCTL_MAGIC, 17, \
+ struct msm_audio_aio_buf)
+#define AUDIO_ASYNC_READ _IOW(AUDIO_IOCTL_MAGIC, 18, \
+ struct msm_audio_aio_buf)
+#define AUDIO_SET_INCALL _IOW(AUDIO_IOCTL_MAGIC, 19, struct msm_voicerec_mode)
+#define AUDIO_GET_NUM_SND_DEVICE _IOR(AUDIO_IOCTL_MAGIC, 20, unsigned int)
+#define AUDIO_GET_SND_DEVICES _IOWR(AUDIO_IOCTL_MAGIC, 21, \
+ struct msm_snd_device_list)
+#define AUDIO_ENABLE_SND_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 22, unsigned int)
+#define AUDIO_DISABLE_SND_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 23, unsigned int)
+#define AUDIO_ROUTE_STREAM _IOW(AUDIO_IOCTL_MAGIC, 24, \
+ struct msm_audio_route_config)
+#define AUDIO_GET_PCM_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 30, unsigned int)
+#define AUDIO_SET_PCM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 31, unsigned int)
+#define AUDIO_SWITCH_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 32, unsigned int)
+#define AUDIO_SET_MUTE _IOW(AUDIO_IOCTL_MAGIC, 33, unsigned int)
+#define AUDIO_UPDATE_ACDB _IOW(AUDIO_IOCTL_MAGIC, 34, unsigned int)
+#define AUDIO_START_VOICE _IOW(AUDIO_IOCTL_MAGIC, 35, unsigned int)
+#define AUDIO_STOP_VOICE _IOW(AUDIO_IOCTL_MAGIC, 36, unsigned int)
+#define AUDIO_REINIT_ACDB _IOW(AUDIO_IOCTL_MAGIC, 39, unsigned int)
+#define AUDIO_OUTPORT_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 40, unsigned short)
+#define AUDIO_SET_ERR_THRESHOLD_VALUE _IOW(AUDIO_IOCTL_MAGIC, 41, \
+ unsigned short)
+#define AUDIO_GET_BITSTREAM_ERROR_INFO _IOR(AUDIO_IOCTL_MAGIC, 42, \
+ struct msm_audio_bitstream_error_info)
+
+#define AUDIO_SET_SRS_TRUMEDIA_PARAM _IOW(AUDIO_IOCTL_MAGIC, 43, unsigned int)
+
+/* Qualcomm technologies inc extensions */
+#define AUDIO_SET_STREAM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 80, \
+ struct msm_audio_stream_config)
+#define AUDIO_GET_STREAM_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 81, \
+ struct msm_audio_stream_config)
+#define AUDIO_GET_SESSION_ID _IOR(AUDIO_IOCTL_MAGIC, 82, unsigned short)
+#define AUDIO_GET_STREAM_INFO _IOR(AUDIO_IOCTL_MAGIC, 83, \
+ struct msm_audio_bitstream_info)
+#define AUDIO_SET_PAN _IOW(AUDIO_IOCTL_MAGIC, 84, unsigned int)
+#define AUDIO_SET_QCONCERT_PLUS _IOW(AUDIO_IOCTL_MAGIC, 85, unsigned int)
+#define AUDIO_SET_MBADRC _IOW(AUDIO_IOCTL_MAGIC, 86, unsigned int)
+#define AUDIO_SET_VOLUME_PATH _IOW(AUDIO_IOCTL_MAGIC, 87, \
+ struct msm_vol_info)
+#define AUDIO_SET_MAX_VOL_ALL _IOW(AUDIO_IOCTL_MAGIC, 88, unsigned int)
+#define AUDIO_ENABLE_AUDPRE _IOW(AUDIO_IOCTL_MAGIC, 89, unsigned int)
+#define AUDIO_SET_AGC _IOW(AUDIO_IOCTL_MAGIC, 90, unsigned int)
+#define AUDIO_SET_NS _IOW(AUDIO_IOCTL_MAGIC, 91, unsigned int)
+#define AUDIO_SET_TX_IIR _IOW(AUDIO_IOCTL_MAGIC, 92, unsigned int)
+#define AUDIO_GET_BUF_CFG _IOW(AUDIO_IOCTL_MAGIC, 93, \
+ struct msm_audio_buf_cfg)
+#define AUDIO_SET_BUF_CFG _IOW(AUDIO_IOCTL_MAGIC, 94, \
+ struct msm_audio_buf_cfg)
+#define AUDIO_SET_ACDB_BLK _IOW(AUDIO_IOCTL_MAGIC, 95, \
+ struct msm_acdb_cmd_device)
+#define AUDIO_GET_ACDB_BLK _IOW(AUDIO_IOCTL_MAGIC, 96, \
+ struct msm_acdb_cmd_device)
+
+#define AUDIO_REGISTER_ION _IOW(AUDIO_IOCTL_MAGIC, 97, \
+ struct msm_audio_ion_info)
+#define AUDIO_DEREGISTER_ION _IOW(AUDIO_IOCTL_MAGIC, 98, \
+ struct msm_audio_ion_info)
+#define AUDIO_SET_EFFECTS_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 99, \
+ struct msm_hwacc_effects_config)
+#define AUDIO_EFFECTS_SET_BUF_LEN _IOW(AUDIO_IOCTL_MAGIC, 100, \
+ struct msm_hwacc_buf_cfg)
+#define AUDIO_EFFECTS_GET_BUF_AVAIL _IOW(AUDIO_IOCTL_MAGIC, 101, \
+ struct msm_hwacc_buf_avail)
+#define AUDIO_EFFECTS_WRITE _IOW(AUDIO_IOCTL_MAGIC, 102, void *)
+#define AUDIO_EFFECTS_READ _IOWR(AUDIO_IOCTL_MAGIC, 103, void *)
+#define AUDIO_EFFECTS_SET_PP_PARAMS _IOW(AUDIO_IOCTL_MAGIC, 104, void *)
+
+#define AUDIO_PM_AWAKE _IOW(AUDIO_IOCTL_MAGIC, 105, unsigned int)
+#define AUDIO_PM_RELAX _IOW(AUDIO_IOCTL_MAGIC, 106, unsigned int)
+
+#define AUDIO_MAX_COMMON_IOCTL_NUM 107
+
+
+#define HANDSET_MIC 0x01
+#define HANDSET_SPKR 0x02
+#define HEADSET_MIC 0x03
+#define HEADSET_SPKR_MONO 0x04
+#define HEADSET_SPKR_STEREO 0x05
+#define SPKR_PHONE_MIC 0x06
+#define SPKR_PHONE_MONO 0x07
+#define SPKR_PHONE_STEREO 0x08
+#define BT_SCO_MIC 0x09
+#define BT_SCO_SPKR 0x0A
+#define BT_A2DP_SPKR 0x0B
+#define TTY_HEADSET_MIC 0x0C
+#define TTY_HEADSET_SPKR 0x0D
+
+/* Default devices are not supported in a */
+/* device switching context. Only supported */
+/* for stream devices. */
+/* DO NOT USE */
+#define DEFAULT_TX 0x0E
+#define DEFAULT_RX 0x0F
+
+#define BT_A2DP_TX 0x10
+
+#define HEADSET_MONO_PLUS_SPKR_MONO_RX 0x11
+#define HEADSET_MONO_PLUS_SPKR_STEREO_RX 0x12
+#define HEADSET_STEREO_PLUS_SPKR_MONO_RX 0x13
+#define HEADSET_STEREO_PLUS_SPKR_STEREO_RX 0x14
+
+#define I2S_RX 0x20
+#define I2S_TX 0x21
+
+#define ADRC_ENABLE 0x0001
+#define EQUALIZER_ENABLE 0x0002
+#define IIR_ENABLE 0x0004
+#define QCONCERT_PLUS_ENABLE 0x0008
+#define MBADRC_ENABLE 0x0010
+#define SRS_ENABLE 0x0020
+#define SRS_DISABLE 0x0040
+
+#define AGC_ENABLE 0x0001
+#define NS_ENABLE 0x0002
+#define TX_IIR_ENABLE 0x0004
+#define FLUENCE_ENABLE 0x0008
+
+#define VOC_REC_UPLINK 0x00
+#define VOC_REC_DOWNLINK 0x01
+#define VOC_REC_BOTH 0x02
+
+struct msm_audio_config {
+ uint32_t buffer_size;
+ uint32_t buffer_count;
+ uint32_t channel_count;
+ uint32_t sample_rate;
+ uint32_t type;
+ uint32_t meta_field;
+ uint32_t bits;
+ uint32_t unused[3];
+};
+
+struct msm_audio_stream_config {
+ uint32_t buffer_size;
+ uint32_t buffer_count;
+};
+
+struct msm_audio_buf_cfg {
+ uint32_t meta_info_enable;
+ uint32_t frames_per_buf;
+};
+
+struct msm_audio_stats {
+ uint32_t byte_count;
+ uint32_t sample_count;
+ uint32_t unused[2];
+};
+
+struct msm_audio_ion_info {
+ int fd;
+ void *vaddr;
+};
+
+struct msm_audio_pmem_info {
+ int fd;
+ void *vaddr;
+};
+
+struct msm_audio_aio_buf {
+ void *buf_addr;
+ uint32_t buf_len;
+ uint32_t data_len;
+ void *private_data;
+ unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+/* Audio routing */
+
+#define SND_IOCTL_MAGIC 's'
+
+#define SND_MUTE_UNMUTED 0
+#define SND_MUTE_MUTED 1
+
+struct msm_mute_info {
+ uint32_t mute;
+ uint32_t path;
+};
+
+struct msm_vol_info {
+ uint32_t vol;
+ uint32_t path;
+};
+
+struct msm_voicerec_mode {
+ uint32_t rec_mode;
+};
+
+struct msm_snd_device_config {
+ uint32_t device;
+ uint32_t ear_mute;
+ uint32_t mic_mute;
+};
+
+#define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *)
+
+enum cad_device_path_type {
+ CAD_DEVICE_PATH_RX, /*For Decoding session*/
+ CAD_DEVICE_PATH_TX, /* For Encoding session*/
+ CAD_DEVICE_PATH_RX_TX, /* For Voice call */
+ CAD_DEVICE_PATH_LB, /* For loopback (FM Analog)*/
+ CAD_DEVICE_PATH_MAX
+};
+
+struct cad_devices_type {
+ uint32_t rx_device;
+ uint32_t tx_device;
+ enum cad_device_path_type pathtype;
+};
+
+struct msm_cad_device_config {
+ struct cad_devices_type device;
+ uint32_t ear_mute;
+ uint32_t mic_mute;
+};
+
+#define CAD_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_cad_device_config *)
+
+#define SND_METHOD_VOICE 0
+#define SND_METHOD_MIDI 4
+
+struct msm_snd_volume_config {
+ uint32_t device;
+ uint32_t method;
+ uint32_t volume;
+};
+
+#define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *)
+
+struct msm_cad_volume_config {
+ struct cad_devices_type device;
+ uint32_t method;
+ uint32_t volume;
+};
+
+#define CAD_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_cad_volume_config *)
+
+/* Returns the number of SND endpoints supported. */
+
+#define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned int *)
+
+struct msm_snd_endpoint {
+ int id; /* input and output */
+ char name[64]; /* output only */
+};
+
+/* Takes an index between 0 and one less than the number returned by
+ * SND_GET_NUM_ENDPOINTS, and returns the SND index and name of a
+ * SND endpoint. On input, the .id field contains the number of the
+ * endpoint, and on exit it contains the SND index, while .name contains
+ * the description of the endpoint.
+ */
+
+#define SND_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_snd_endpoint *)
+
+
+#define SND_AVC_CTL _IOW(SND_IOCTL_MAGIC, 6, unsigned int *)
+#define SND_AGC_CTL _IOW(SND_IOCTL_MAGIC, 7, unsigned int *)
+
+/*return the number of CAD endpoints supported. */
+
+#define CAD_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned int *)
+
+struct msm_cad_endpoint {
+ int id; /* input and output */
+ char name[64]; /* output only */
+};
+
+/* Takes an index between 0 and one less than the number returned by
+ * SND_GET_NUM_ENDPOINTS, and returns the CAD index and name of a
+ * CAD endpoint. On input, the .id field contains the number of the
+ * endpoint, and on exit it contains the SND index, while .name contains
+ * the description of the endpoint.
+ */
+
+#define CAD_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_cad_endpoint *)
+
+struct msm_audio_pcm_config {
+ uint32_t pcm_feedback; /* 0 - disable > 0 - enable */
+ uint32_t buffer_count; /* Number of buffers to allocate */
+ uint32_t buffer_size; /* Size of buffer for capturing of
+ * PCM samples
+ */
+};
+
+#define AUDIO_EVENT_SUSPEND 0
+#define AUDIO_EVENT_RESUME 1
+#define AUDIO_EVENT_WRITE_DONE 2
+#define AUDIO_EVENT_READ_DONE 3
+#define AUDIO_EVENT_STREAM_INFO 4
+#define AUDIO_EVENT_BITSTREAM_ERROR_INFO 5
+
+#define AUDIO_CODEC_TYPE_MP3 0
+#define AUDIO_CODEC_TYPE_AAC 1
+
+struct msm_audio_bitstream_info {
+ uint32_t codec_type;
+ uint32_t chan_info;
+ uint32_t sample_rate;
+ uint32_t bit_stream_info;
+ uint32_t bit_rate;
+ uint32_t unused[3];
+};
+
+struct msm_audio_bitstream_error_info {
+ uint32_t dec_id;
+ uint32_t err_msg_indicator;
+ uint32_t err_type;
+};
+
+union msm_audio_event_payload {
+ struct msm_audio_aio_buf aio_buf;
+ struct msm_audio_bitstream_info stream_info;
+ struct msm_audio_bitstream_error_info error_info;
+ int reserved;
+};
+
+struct msm_audio_event {
+ int event_type;
+ int timeout_ms;
+ union msm_audio_event_payload event_payload;
+};
+
+#define MSM_SNDDEV_CAP_RX 0x1
+#define MSM_SNDDEV_CAP_TX 0x2
+#define MSM_SNDDEV_CAP_VOICE 0x4
+
+struct msm_snd_device_info {
+ uint32_t dev_id;
+ uint32_t dev_cap; /* bitmask describe capability of device */
+ char dev_name[64];
+};
+
+struct msm_snd_device_list {
+ uint32_t num_dev; /* Indicate number of device info to be retrieved */
+ struct msm_snd_device_info *list;
+};
+
+struct msm_dtmf_config {
+ uint16_t path;
+ uint16_t dtmf_hi;
+ uint16_t dtmf_low;
+ uint16_t duration;
+ uint16_t tx_gain;
+ uint16_t rx_gain;
+ uint16_t mixing;
+};
+
+#define AUDIO_ROUTE_STREAM_VOICE_RX 0
+#define AUDIO_ROUTE_STREAM_VOICE_TX 1
+#define AUDIO_ROUTE_STREAM_PLAYBACK 2
+#define AUDIO_ROUTE_STREAM_REC 3
+
+struct msm_audio_route_config {
+ uint32_t stream_type;
+ uint32_t stream_id;
+ uint32_t dev_id;
+};
+
+#define AUDIO_MAX_EQ_BANDS 12
+
+struct msm_audio_eq_band {
+ uint16_t band_idx; /* The band index, 0 .. 11 */
+ uint32_t filter_type; /* Filter band type */
+ uint32_t center_freq_hz; /* Filter band center frequency */
+ uint32_t filter_gain; /* Filter band initial gain (dB) */
+ /* Range is +12 dB to -12 dB with 1dB increments. */
+ uint32_t q_factor;
+} __attribute__ ((packed));
+
+struct msm_audio_eq_stream_config {
+ uint32_t enable; /* Number of consequtive bands specified */
+ uint32_t num_bands;
+ struct msm_audio_eq_band eq_bands[AUDIO_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+struct msm_acdb_cmd_device {
+ uint32_t command_id;
+ uint32_t device_id;
+ uint32_t network_id;
+ uint32_t sample_rate_id; /* Actual sample rate value */
+ uint32_t interface_id; /* See interface id's above */
+ uint32_t algorithm_block_id; /* See enumerations above */
+ uint32_t total_bytes; /* Length in bytes used by buffer */
+ uint32_t *phys_buf; /* Physical Address of data */
+};
+
+struct msm_hwacc_data_config {
+ __u32 buf_size;
+ __u32 num_buf;
+ __u32 num_channels;
+ __u8 channel_map[8];
+ __u32 sample_rate;
+ __u32 bits_per_sample;
+};
+
+struct msm_hwacc_buf_cfg {
+ __u32 input_len;
+ __u32 output_len;
+};
+
+struct msm_hwacc_buf_avail {
+ __u32 input_num_avail;
+ __u32 output_num_avail;
+};
+
+struct msm_hwacc_effects_config {
+ struct msm_hwacc_data_config input;
+ struct msm_hwacc_data_config output;
+ struct msm_hwacc_buf_cfg buf_cfg;
+ __u32 meta_mode_enabled;
+ __u32 overwrite_topology;
+ __s32 topology;
+};
+
+#endif
diff --git a/include/uapi/linux/msm_audio_aac.h b/include/uapi/linux/msm_audio_aac.h
new file mode 100644
index 0000000..7e1e1b7
--- /dev/null
+++ b/include/uapi/linux/msm_audio_aac.h
@@ -0,0 +1,76 @@
+#ifndef _UAPI_MSM_AUDIO_AAC_H
+#define _UAPI_MSM_AUDIO_AAC_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_AAC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_aac_config)
+#define AUDIO_GET_AAC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_aac_config)
+
+#define AUDIO_SET_AAC_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_aac_enc_config)
+
+#define AUDIO_GET_AAC_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+4), struct msm_audio_aac_enc_config)
+
+#define AUDIO_SET_AAC_MIX_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+5), uint32_t)
+
+#define AUDIO_AAC_FORMAT_ADTS -1
+#define AUDIO_AAC_FORMAT_RAW 0x0000
+#define AUDIO_AAC_FORMAT_PSUEDO_RAW 0x0001
+#define AUDIO_AAC_FORMAT_LOAS 0x0002
+#define AUDIO_AAC_FORMAT_ADIF 0x0003
+
+#define AUDIO_AAC_OBJECT_LC 0x0002
+#define AUDIO_AAC_OBJECT_LTP 0x0004
+#define AUDIO_AAC_OBJECT_ERLC 0x0011
+#define AUDIO_AAC_OBJECT_BSAC 0x0016
+
+#define AUDIO_AAC_SEC_DATA_RES_ON 0x0001
+#define AUDIO_AAC_SEC_DATA_RES_OFF 0x0000
+
+#define AUDIO_AAC_SCA_DATA_RES_ON 0x0001
+#define AUDIO_AAC_SCA_DATA_RES_OFF 0x0000
+
+#define AUDIO_AAC_SPEC_DATA_RES_ON 0x0001
+#define AUDIO_AAC_SPEC_DATA_RES_OFF 0x0000
+
+#define AUDIO_AAC_SBR_ON_FLAG_ON 0x0001
+#define AUDIO_AAC_SBR_ON_FLAG_OFF 0x0000
+
+#define AUDIO_AAC_SBR_PS_ON_FLAG_ON 0x0001
+#define AUDIO_AAC_SBR_PS_ON_FLAG_OFF 0x0000
+
+/* Primary channel on both left and right channels */
+#define AUDIO_AAC_DUAL_MONO_PL_PR 0
+/* Secondary channel on both left and right channels */
+#define AUDIO_AAC_DUAL_MONO_SL_SR 1
+/* Primary channel on right channel and 2nd on left channel */
+#define AUDIO_AAC_DUAL_MONO_SL_PR 2
+/* 2nd channel on right channel and primary on left channel */
+#define AUDIO_AAC_DUAL_MONO_PL_SR 3
+
+struct msm_audio_aac_config {
+ signed short format;
+ unsigned short audio_object;
+ unsigned short ep_config; /* 0 ~ 3 useful only obj = ERLC */
+ unsigned short aac_section_data_resilience_flag;
+ unsigned short aac_scalefactor_data_resilience_flag;
+ unsigned short aac_spectral_data_resilience_flag;
+ unsigned short sbr_on_flag;
+ unsigned short sbr_ps_on_flag;
+ unsigned short dual_mono_mode;
+ unsigned short channel_configuration;
+ unsigned short sample_rate;
+};
+
+struct msm_audio_aac_enc_config {
+ uint32_t channels;
+ uint32_t sample_rate;
+ uint32_t bit_rate;
+ uint32_t stream_format;
+};
+
+#endif /* _UAPI_MSM_AUDIO_AAC_H */
diff --git a/include/uapi/linux/msm_audio_ac3.h b/include/uapi/linux/msm_audio_ac3.h
new file mode 100644
index 0000000..1df6e69
--- /dev/null
+++ b/include/uapi/linux/msm_audio_ac3.h
@@ -0,0 +1,41 @@
+#ifndef _UAPI_MSM_AUDIO_AC3_H
+#define _UAPI_MSM_AUDIO_AC3_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_AC3_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned int)
+#define AUDIO_GET_AC3_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned int)
+
+#define AUDAC3_DEF_WORDSIZE 0
+#define AUDAC3_DEF_USER_DOWNMIX_FLAG 0x0
+#define AUDAC3_DEF_USER_KARAOKE_FLAG 0x0
+#define AUDAC3_DEF_ERROR_CONCEALMENT 0
+#define AUDAC3_DEF_MAX_REPEAT_COUNT 0
+
+struct msm_audio_ac3_config {
+ unsigned short numChans;
+ unsigned short wordSize;
+ unsigned short kCapableMode;
+ unsigned short compMode;
+ unsigned short outLfeOn;
+ unsigned short outputMode;
+ unsigned short stereoMode;
+ unsigned short dualMonoMode;
+ unsigned short fsCod;
+ unsigned short pcmScaleFac;
+ unsigned short dynRngScaleHi;
+ unsigned short dynRngScaleLow;
+ unsigned short user_downmix_flag;
+ unsigned short user_karaoke_flag;
+ unsigned short dm_address_high;
+ unsigned short dm_address_low;
+ unsigned short ko_address_high;
+ unsigned short ko_address_low;
+ unsigned short error_concealment;
+ unsigned short max_rep_count;
+ unsigned short channel_routing_mode[6];
+};
+
+#endif /* _UAPI_MSM_AUDIO_AC3_H */
diff --git a/include/uapi/linux/msm_audio_alac.h b/include/uapi/linux/msm_audio_alac.h
new file mode 100644
index 0000000..5476e96
--- /dev/null
+++ b/include/uapi/linux/msm_audio_alac.h
@@ -0,0 +1,24 @@
+#ifndef _UAPI_MSM_AUDIO_ALAC_H
+#define _UAPI_MSM_AUDIO_ALAC_H
+
+#define AUDIO_GET_ALAC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_alac_config)
+#define AUDIO_SET_ALAC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_alac_config)
+
+struct msm_audio_alac_config {
+ uint32_t frameLength;
+ uint8_t compatVersion;
+ uint8_t bitDepth;
+ uint8_t pb; /* currently unused */
+ uint8_t mb; /* currently unused */
+ uint8_t kb; /* currently unused */
+ uint8_t channelCount;
+ uint16_t maxRun; /* currently unused */
+ uint32_t maxSize;
+ uint32_t averageBitRate;
+ uint32_t sampleRate;
+ uint32_t channelLayout;
+};
+
+#endif /* _UAPI_MSM_AUDIO_ALAC_H */
diff --git a/include/uapi/linux/msm_audio_amrnb.h b/include/uapi/linux/msm_audio_amrnb.h
new file mode 100644
index 0000000..619f928
--- /dev/null
+++ b/include/uapi/linux/msm_audio_amrnb.h
@@ -0,0 +1,34 @@
+#ifndef _UAPI_MSM_AUDIO_AMRNB_H
+#define _UAPI_MSM_AUDIO_AMRNB_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_GET_AMRNB_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned int)
+#define AUDIO_SET_AMRNB_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned int)
+#define AUDIO_GET_AMRNB_ENC_CONFIG_V2 _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2), \
+ struct msm_audio_amrnb_enc_config_v2)
+#define AUDIO_SET_AMRNB_ENC_CONFIG_V2 _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), \
+ struct msm_audio_amrnb_enc_config_v2)
+
+struct msm_audio_amrnb_enc_config {
+ unsigned short voicememoencweight1;
+ unsigned short voicememoencweight2;
+ unsigned short voicememoencweight3;
+ unsigned short voicememoencweight4;
+ unsigned short dtx_mode_enable; /* 0xFFFF - enable, 0- disable */
+ unsigned short test_mode_enable; /* 0xFFFF - enable, 0- disable */
+ unsigned short enc_mode; /* 0-MR475,1-MR515,2-MR59,3-MR67,4-MR74
+ * 5-MR795, 6- MR102, 7- MR122(default)
+ */
+};
+
+struct msm_audio_amrnb_enc_config_v2 {
+ uint32_t band_mode;
+ uint32_t dtx_enable;
+ uint32_t frame_format;
+};
+#endif /* _UAPI_MSM_AUDIO_AMRNB_H */
diff --git a/include/uapi/linux/msm_audio_amrwb.h b/include/uapi/linux/msm_audio_amrwb.h
new file mode 100644
index 0000000..5124038
--- /dev/null
+++ b/include/uapi/linux/msm_audio_amrwb.h
@@ -0,0 +1,18 @@
+#ifndef _UAPI_MSM_AUDIO_AMRWB_H
+#define _UAPI_MSM_AUDIO_AMRWB_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_GET_AMRWB_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), \
+ struct msm_audio_amrwb_enc_config)
+#define AUDIO_SET_AMRWB_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), \
+ struct msm_audio_amrwb_enc_config)
+
+struct msm_audio_amrwb_enc_config {
+ uint32_t band_mode;
+ uint32_t dtx_enable;
+ uint32_t frame_format;
+};
+#endif /* _UAPI_MSM_AUDIO_AMRWB_H */
diff --git a/include/uapi/linux/msm_audio_amrwbplus.h b/include/uapi/linux/msm_audio_amrwbplus.h
new file mode 100644
index 0000000..ba2d06e
--- /dev/null
+++ b/include/uapi/linux/msm_audio_amrwbplus.h
@@ -0,0 +1,18 @@
+#ifndef _UAPI_MSM_AUDIO_AMR_WB_PLUS_H
+#define _UAPI_MSM_AUDIO_AMR_WB_PLUS_H
+
+#define AUDIO_GET_AMRWBPLUS_CONFIG_V2 _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2), struct msm_audio_amrwbplus_config_v2)
+#define AUDIO_SET_AMRWBPLUS_CONFIG_V2 _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_amrwbplus_config_v2)
+
+struct msm_audio_amrwbplus_config_v2 {
+ unsigned int size_bytes;
+ unsigned int version;
+ unsigned int num_channels;
+ unsigned int amr_band_mode;
+ unsigned int amr_dtx_mode;
+ unsigned int amr_frame_fmt;
+ unsigned int amr_lsf_idx;
+};
+#endif /* _UAPI_MSM_AUDIO_AMR_WB_PLUS_H */
diff --git a/include/uapi/linux/msm_audio_ape.h b/include/uapi/linux/msm_audio_ape.h
new file mode 100644
index 0000000..587d3bc
--- /dev/null
+++ b/include/uapi/linux/msm_audio_ape.h
@@ -0,0 +1,26 @@
+/* The following structure has been taken
+ * from Monkey's Audio SDK with permission
+ */
+
+#ifndef _UAPI_MSM_AUDIO_APE_H
+#define _UAPI_MSM_AUDIO_APE_H
+
+#define AUDIO_GET_APE_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_ape_config)
+#define AUDIO_SET_APE_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_ape_config)
+
+struct msm_audio_ape_config {
+ uint16_t compatibleVersion;
+ uint16_t compressionLevel;
+ uint32_t formatFlags;
+ uint32_t blocksPerFrame;
+ uint32_t finalFrameBlocks;
+ uint32_t totalFrames;
+ uint16_t bitsPerSample;
+ uint16_t numChannels;
+ uint32_t sampleRate;
+ uint32_t seekTablePresent;
+};
+
+#endif /* _UAPI_MSM_AUDIO_APE_H */
diff --git a/include/uapi/linux/msm_audio_calibration.h b/include/uapi/linux/msm_audio_calibration.h
new file mode 100644
index 0000000..11af32e
--- /dev/null
+++ b/include/uapi/linux/msm_audio_calibration.h
@@ -0,0 +1,692 @@
+#ifndef _UAPI_MSM_AUDIO_CALIBRATION_H
+#define _UAPI_MSM_AUDIO_CALIBRATION_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define CAL_IOCTL_MAGIC 'a'
+
+#define AUDIO_ALLOCATE_CALIBRATION _IOWR(CAL_IOCTL_MAGIC, \
+ 200, void *)
+#define AUDIO_DEALLOCATE_CALIBRATION _IOWR(CAL_IOCTL_MAGIC, \
+ 201, void *)
+#define AUDIO_PREPARE_CALIBRATION _IOWR(CAL_IOCTL_MAGIC, \
+ 202, void *)
+#define AUDIO_SET_CALIBRATION _IOWR(CAL_IOCTL_MAGIC, \
+ 203, void *)
+#define AUDIO_GET_CALIBRATION _IOWR(CAL_IOCTL_MAGIC, \
+ 204, void *)
+#define AUDIO_POST_CALIBRATION _IOWR(CAL_IOCTL_MAGIC, \
+ 205, void *)
+
+/* For Real-Time Audio Calibration */
+#define AUDIO_GET_RTAC_ADM_INFO _IOR(CAL_IOCTL_MAGIC, \
+ 207, void *)
+#define AUDIO_GET_RTAC_VOICE_INFO _IOR(CAL_IOCTL_MAGIC, \
+ 208, void *)
+#define AUDIO_GET_RTAC_ADM_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 209, void *)
+#define AUDIO_SET_RTAC_ADM_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 210, void *)
+#define AUDIO_GET_RTAC_ASM_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 211, void *)
+#define AUDIO_SET_RTAC_ASM_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 212, void *)
+#define AUDIO_GET_RTAC_CVS_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 213, void *)
+#define AUDIO_SET_RTAC_CVS_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 214, void *)
+#define AUDIO_GET_RTAC_CVP_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 215, void *)
+#define AUDIO_SET_RTAC_CVP_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 216, void *)
+#define AUDIO_GET_RTAC_AFE_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 217, void *)
+#define AUDIO_SET_RTAC_AFE_CAL _IOWR(CAL_IOCTL_MAGIC, \
+ 218, void *)
+enum {
+ CVP_VOC_RX_TOPOLOGY_CAL_TYPE = 0,
+ CVP_VOC_TX_TOPOLOGY_CAL_TYPE,
+ CVP_VOCPROC_STATIC_CAL_TYPE,
+ CVP_VOCPROC_DYNAMIC_CAL_TYPE,
+ CVS_VOCSTRM_STATIC_CAL_TYPE,
+ CVP_VOCDEV_CFG_CAL_TYPE,
+ CVP_VOCPROC_STATIC_COL_CAL_TYPE,
+ CVP_VOCPROC_DYNAMIC_COL_CAL_TYPE,
+ CVS_VOCSTRM_STATIC_COL_CAL_TYPE,
+
+ ADM_TOPOLOGY_CAL_TYPE,
+ ADM_CUST_TOPOLOGY_CAL_TYPE,
+ ADM_AUDPROC_CAL_TYPE,
+ ADM_AUDVOL_CAL_TYPE,
+
+ ASM_TOPOLOGY_CAL_TYPE,
+ ASM_CUST_TOPOLOGY_CAL_TYPE,
+ ASM_AUDSTRM_CAL_TYPE,
+
+ AFE_COMMON_RX_CAL_TYPE,
+ AFE_COMMON_TX_CAL_TYPE,
+ AFE_ANC_CAL_TYPE,
+ AFE_AANC_CAL_TYPE,
+ AFE_FB_SPKR_PROT_CAL_TYPE,
+ AFE_HW_DELAY_CAL_TYPE,
+ AFE_SIDETONE_CAL_TYPE,
+ AFE_TOPOLOGY_CAL_TYPE,
+ AFE_CUST_TOPOLOGY_CAL_TYPE,
+
+ LSM_CUST_TOPOLOGY_CAL_TYPE,
+ LSM_TOPOLOGY_CAL_TYPE,
+ LSM_CAL_TYPE,
+
+ ADM_RTAC_INFO_CAL_TYPE,
+ VOICE_RTAC_INFO_CAL_TYPE,
+ ADM_RTAC_APR_CAL_TYPE,
+ ASM_RTAC_APR_CAL_TYPE,
+ VOICE_RTAC_APR_CAL_TYPE,
+
+ MAD_CAL_TYPE,
+ ULP_AFE_CAL_TYPE,
+ ULP_LSM_CAL_TYPE,
+
+ DTS_EAGLE_CAL_TYPE,
+ AUDIO_CORE_METAINFO_CAL_TYPE,
+ SRS_TRUMEDIA_CAL_TYPE,
+
+ CORE_CUSTOM_TOPOLOGIES_CAL_TYPE,
+ ADM_RTAC_AUDVOL_CAL_TYPE,
+
+ ULP_LSM_TOPOLOGY_ID_CAL_TYPE,
+ AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE,
+ AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE,
+ MAX_CAL_TYPES,
+};
+
+#define AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE
+#define AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE
+
+enum {
+ VERSION_0_0,
+};
+
+enum {
+ PER_VOCODER_CAL_BIT_MASK = 0x10000,
+};
+
+#define MAX_IOCTL_CMD_SIZE 512
+
+/* common structures */
+
+struct audio_cal_header {
+ int32_t data_size;
+ int32_t version;
+ int32_t cal_type;
+ int32_t cal_type_size;
+};
+
+struct audio_cal_type_header {
+ int32_t version;
+ int32_t buffer_number;
+};
+
+struct audio_cal_data {
+ /* Size of cal data at mem_handle allocation or at vaddr */
+ int32_t cal_size;
+ /* If mem_handle if shared memory is used*/
+ int32_t mem_handle;
+ /* size of virtual memory if shared memory not used */
+};
+
+
+/* AUDIO_ALLOCATE_CALIBRATION */
+struct audio_cal_type_alloc {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+};
+
+struct audio_cal_alloc {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_alloc cal_type;
+};
+
+
+/* AUDIO_DEALLOCATE_CALIBRATION */
+struct audio_cal_type_dealloc {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+};
+
+struct audio_cal_dealloc {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_dealloc cal_type;
+};
+
+
+/* AUDIO_PREPARE_CALIBRATION */
+struct audio_cal_type_prepare {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+};
+
+struct audio_cal_prepare {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_prepare cal_type;
+};
+
+
+/* AUDIO_POST_CALIBRATION */
+struct audio_cal_type_post {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+};
+
+struct audio_cal_post {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_post cal_type;
+};
+
+/*AUDIO_CORE_META_INFO */
+
+struct audio_cal_info_metainfo {
+ uint32_t nKey;
+};
+
+/* Cal info types */
+enum {
+ RX_DEVICE,
+ TX_DEVICE,
+ MAX_PATH_TYPE
+};
+
+struct audio_cal_info_adm_top {
+ int32_t topology;
+ int32_t acdb_id;
+ /* RX_DEVICE or TX_DEVICE */
+ int32_t path;
+ int32_t app_type;
+ int32_t sample_rate;
+};
+
+struct audio_cal_info_audproc {
+ int32_t acdb_id;
+ /* RX_DEVICE or TX_DEVICE */
+ int32_t path;
+ int32_t app_type;
+ int32_t sample_rate;
+};
+
+struct audio_cal_info_audvol {
+ int32_t acdb_id;
+ /* RX_DEVICE or TX_DEVICE */
+ int32_t path;
+ int32_t app_type;
+ int32_t vol_index;
+};
+
+struct audio_cal_info_afe {
+ int32_t acdb_id;
+ /* RX_DEVICE or TX_DEVICE */
+ int32_t path;
+ int32_t sample_rate;
+};
+
+struct audio_cal_info_afe_top {
+ int32_t topology;
+ int32_t acdb_id;
+ /* RX_DEVICE or TX_DEVICE */
+ int32_t path;
+ int32_t sample_rate;
+};
+
+struct audio_cal_info_asm_top {
+ int32_t topology;
+ int32_t app_type;
+};
+
+struct audio_cal_info_audstrm {
+ int32_t app_type;
+};
+
+struct audio_cal_info_aanc {
+ int32_t acdb_id;
+};
+
+#define MAX_HW_DELAY_ENTRIES 25
+
+struct audio_cal_hw_delay_entry {
+ uint32_t sample_rate;
+ uint32_t delay_usec;
+};
+
+struct audio_cal_hw_delay_data {
+ uint32_t num_entries;
+ struct audio_cal_hw_delay_entry entry[MAX_HW_DELAY_ENTRIES];
+};
+
+struct audio_cal_info_hw_delay {
+ int32_t acdb_id;
+ /* RX_DEVICE or TX_DEVICE */
+ int32_t path;
+ int32_t property_type;
+ struct audio_cal_hw_delay_data data;
+};
+
+enum msm_spkr_prot_states {
+ MSM_SPKR_PROT_CALIBRATED,
+ MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS,
+ MSM_SPKR_PROT_DISABLED,
+ MSM_SPKR_PROT_NOT_CALIBRATED,
+ MSM_SPKR_PROT_PRE_CALIBRATED,
+ MSM_SPKR_PROT_IN_FTM_MODE
+};
+#define MSM_SPKR_PROT_IN_FTM_MODE MSM_SPKR_PROT_IN_FTM_MODE
+
+enum msm_spkr_count {
+ SP_V2_SPKR_1,
+ SP_V2_SPKR_2,
+ SP_V2_NUM_MAX_SPKRS
+};
+
+struct audio_cal_info_spk_prot_cfg {
+ int32_t r0[SP_V2_NUM_MAX_SPKRS];
+ int32_t t0[SP_V2_NUM_MAX_SPKRS];
+ uint32_t quick_calib_flag;
+ uint32_t mode;
+ /*
+ * 0 - Start spk prot
+ * 1 - Start calib
+ * 2 - Disable spk prot
+ */
+};
+
+struct audio_cal_info_sp_th_vi_ftm_cfg {
+ uint32_t wait_time[SP_V2_NUM_MAX_SPKRS];
+ uint32_t ftm_time[SP_V2_NUM_MAX_SPKRS];
+ uint32_t mode;
+ /*
+ * 0 - normal running mode
+ * 1 - Calibration
+ * 2 - FTM mode
+ */
+};
+
+struct audio_cal_info_sp_ex_vi_ftm_cfg {
+ uint32_t wait_time[SP_V2_NUM_MAX_SPKRS];
+ uint32_t ftm_time[SP_V2_NUM_MAX_SPKRS];
+ uint32_t mode;
+ /*
+ * 0 - normal running mode
+ * 2 - FTM mode
+ */
+};
+
+struct audio_cal_info_sp_ex_vi_param {
+ int32_t freq_q20[SP_V2_NUM_MAX_SPKRS];
+ int32_t resis_q24[SP_V2_NUM_MAX_SPKRS];
+ int32_t qmct_q24[SP_V2_NUM_MAX_SPKRS];
+ int32_t status[SP_V2_NUM_MAX_SPKRS];
+};
+
+struct audio_cal_info_sp_th_vi_param {
+ int32_t r_dc_q24[SP_V2_NUM_MAX_SPKRS];
+ int32_t temp_q22[SP_V2_NUM_MAX_SPKRS];
+ int32_t status[SP_V2_NUM_MAX_SPKRS];
+};
+
+struct audio_cal_info_msm_spk_prot_status {
+ int32_t r0[SP_V2_NUM_MAX_SPKRS];
+ int32_t status;
+};
+
+struct audio_cal_info_sidetone {
+ uint16_t enable;
+ uint16_t gain;
+ int32_t tx_acdb_id;
+ int32_t rx_acdb_id;
+ int32_t mid;
+ int32_t pid;
+};
+
+struct audio_cal_info_lsm_top {
+ int32_t topology;
+ int32_t acdb_id;
+ int32_t app_type;
+};
+
+
+struct audio_cal_info_lsm {
+ int32_t acdb_id;
+ /* RX_DEVICE or TX_DEVICE */
+ int32_t path;
+ int32_t app_type;
+};
+
+struct audio_cal_info_voc_top {
+ int32_t topology;
+ int32_t acdb_id;
+};
+
+struct audio_cal_info_vocproc {
+ int32_t tx_acdb_id;
+ int32_t rx_acdb_id;
+ int32_t tx_sample_rate;
+ int32_t rx_sample_rate;
+};
+
+enum {
+ DEFAULT_FEATURE_SET,
+ VOL_BOOST_FEATURE_SET,
+};
+
+struct audio_cal_info_vocvol {
+ int32_t tx_acdb_id;
+ int32_t rx_acdb_id;
+ /* DEFAULT_ or VOL_BOOST_FEATURE_SET */
+ int32_t feature_set;
+};
+
+struct audio_cal_info_vocdev_cfg {
+ int32_t tx_acdb_id;
+ int32_t rx_acdb_id;
+};
+
+#define MAX_VOICE_COLUMNS 20
+
+union audio_cal_col_na {
+ uint8_t val8;
+ uint16_t val16;
+ uint32_t val32;
+ uint64_t val64;
+} __packed;
+
+struct audio_cal_col {
+ uint32_t id;
+ uint32_t type;
+ union audio_cal_col_na na_value;
+} __packed;
+
+struct audio_cal_col_data {
+ uint32_t num_columns;
+ struct audio_cal_col column[MAX_VOICE_COLUMNS];
+} __packed;
+
+struct audio_cal_info_voc_col {
+ int32_t table_id;
+ int32_t tx_acdb_id;
+ int32_t rx_acdb_id;
+ struct audio_cal_col_data data;
+};
+
+/* AUDIO_SET_CALIBRATION & */
+struct audio_cal_type_basic {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+};
+
+struct audio_cal_basic {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_basic cal_type;
+};
+
+struct audio_cal_type_adm_top {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_adm_top cal_info;
+};
+
+struct audio_cal_adm_top {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_adm_top cal_type;
+};
+
+struct audio_cal_type_metainfo {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_metainfo cal_info;
+};
+
+struct audio_core_metainfo {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_metainfo cal_type;
+};
+
+struct audio_cal_type_audproc {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_audproc cal_info;
+};
+
+struct audio_cal_audproc {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_audproc cal_type;
+};
+
+struct audio_cal_type_audvol {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_audvol cal_info;
+};
+
+struct audio_cal_audvol {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_audvol cal_type;
+};
+
+struct audio_cal_type_asm_top {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_asm_top cal_info;
+};
+
+struct audio_cal_asm_top {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_asm_top cal_type;
+};
+
+struct audio_cal_type_audstrm {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_audstrm cal_info;
+};
+
+struct audio_cal_audstrm {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_audstrm cal_type;
+};
+
+struct audio_cal_type_afe {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_afe cal_info;
+};
+
+struct audio_cal_afe {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_afe cal_type;
+};
+
+struct audio_cal_type_afe_top {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_afe_top cal_info;
+};
+
+struct audio_cal_afe_top {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_afe_top cal_type;
+};
+
+struct audio_cal_type_aanc {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_aanc cal_info;
+};
+
+struct audio_cal_aanc {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_aanc cal_type;
+};
+
+struct audio_cal_type_fb_spk_prot_cfg {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_spk_prot_cfg cal_info;
+};
+
+struct audio_cal_fb_spk_prot_cfg {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_fb_spk_prot_cfg cal_type;
+};
+
+struct audio_cal_type_sp_th_vi_ftm_cfg {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_sp_th_vi_ftm_cfg cal_info;
+};
+
+struct audio_cal_sp_th_vi_ftm_cfg {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_sp_th_vi_ftm_cfg cal_type;
+};
+
+struct audio_cal_type_sp_ex_vi_ftm_cfg {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_sp_ex_vi_ftm_cfg cal_info;
+};
+
+struct audio_cal_sp_ex_vi_ftm_cfg {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_sp_ex_vi_ftm_cfg cal_type;
+};
+struct audio_cal_type_hw_delay {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_hw_delay cal_info;
+};
+
+struct audio_cal_hw_delay {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_hw_delay cal_type;
+};
+
+struct audio_cal_type_sidetone {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_sidetone cal_info;
+};
+
+struct audio_cal_sidetone {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_sidetone cal_type;
+};
+
+struct audio_cal_type_lsm_top {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_lsm_top cal_info;
+};
+
+struct audio_cal_lsm_top {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_lsm_top cal_type;
+};
+
+struct audio_cal_type_lsm {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_lsm cal_info;
+};
+
+struct audio_cal_lsm {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_lsm cal_type;
+};
+
+struct audio_cal_type_voc_top {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_voc_top cal_info;
+};
+
+struct audio_cal_voc_top {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_voc_top cal_type;
+};
+
+struct audio_cal_type_vocproc {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_vocproc cal_info;
+};
+
+struct audio_cal_vocproc {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_vocproc cal_type;
+};
+
+struct audio_cal_type_vocvol {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_vocvol cal_info;
+};
+
+struct audio_cal_vocvol {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_vocvol cal_type;
+};
+
+struct audio_cal_type_vocdev_cfg {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_vocdev_cfg cal_info;
+};
+
+struct audio_cal_vocdev_cfg {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_vocdev_cfg cal_type;
+};
+
+struct audio_cal_type_voc_col {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_voc_col cal_info;
+};
+
+struct audio_cal_voc_col {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_voc_col cal_type;
+};
+
+/* AUDIO_GET_CALIBRATION */
+struct audio_cal_type_fb_spk_prot_status {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_msm_spk_prot_status cal_info;
+};
+
+struct audio_cal_fb_spk_prot_status {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_fb_spk_prot_status cal_type;
+};
+
+struct audio_cal_type_sp_th_vi_param {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_sp_th_vi_param cal_info;
+};
+
+struct audio_cal_sp_th_vi_param {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_sp_th_vi_param cal_type;
+};
+struct audio_cal_type_sp_ex_vi_param {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_sp_ex_vi_param cal_info;
+};
+
+struct audio_cal_sp_ex_vi_param {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_sp_ex_vi_param cal_type;
+};
+#endif /* _UAPI_MSM_AUDIO_CALIBRATION_H */
diff --git a/include/uapi/linux/msm_audio_g711.h b/include/uapi/linux/msm_audio_g711.h
new file mode 100644
index 0000000..48ebd6a
--- /dev/null
+++ b/include/uapi/linux/msm_audio_g711.h
@@ -0,0 +1,17 @@
+#ifndef _UAPI_MSM_AUDIO_G711_H
+#define _UAPI_MSM_AUDIO_G711_H
+
+#include <linux/msm_audio.h>
+
+struct msm_audio_g711_enc_config {
+ uint32_t sample_rate;
+};
+
+#define AUDIO_SET_G711_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config)
+
+#define AUDIO_GET_G711_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config)
+
+
+#endif /* _UAPI_MSM_AUDIO_G711_H */
diff --git a/include/uapi/linux/msm_audio_g711_dec.h b/include/uapi/linux/msm_audio_g711_dec.h
new file mode 100644
index 0000000..ff7e4ce
--- /dev/null
+++ b/include/uapi/linux/msm_audio_g711_dec.h
@@ -0,0 +1,16 @@
+#ifndef _UAPI_MSM_AUDIO_G711_H
+#define _UAPI_MSM_AUDIO_G711_H
+
+#include <linux/msm_audio.h>
+
+struct msm_audio_g711_dec_config {
+ uint32_t sample_rate;
+};
+
+#define AUDIO_SET_G711_DEC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config)
+
+#define AUDIO_GET_G711_DEC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config)
+
+#endif /* _UAPI_MSM_AUDIO_G711_H */
diff --git a/include/uapi/linux/msm_audio_mvs.h b/include/uapi/linux/msm_audio_mvs.h
new file mode 100644
index 0000000..5b76bf9
--- /dev/null
+++ b/include/uapi/linux/msm_audio_mvs.h
@@ -0,0 +1,155 @@
+#ifndef _UAPI_MSM_AUDIO_MVS_H
+#define _UAPI_MSM_AUDIO_MVS_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_GET_MVS_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM + 0), unsigned int)
+#define AUDIO_SET_MVS_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM + 1), unsigned int)
+
+/* MVS modes */
+#define MVS_MODE_IS733 0x1 /*QCELP 13K*/
+#define MVS_MODE_IS127 0x2 /*EVRC-8k*/
+#define MVS_MODE_4GV_NB 0x3 /*EVRC-B*/
+#define MVS_MODE_4GV_WB 0x4 /*EVRC-WB*/
+#define MVS_MODE_AMR 0x5
+#define MVS_MODE_EFR 0x6
+#define MVS_MODE_FR 0x7
+#define MVS_MODE_HR 0x8
+#define MVS_MODE_LINEAR_PCM 0x9
+#define MVS_MODE_G711 0xA
+#define MVS_MODE_PCM 0xC
+#define MVS_MODE_AMR_WB 0xD
+#define MVS_MODE_G729A 0xE
+#define MVS_MODE_G711A 0xF
+#define MVS_MODE_G722 0x10
+#define MVS_MODE_PCM_WB 0x12
+
+enum msm_audio_amr_mode {
+ MVS_AMR_MODE_0475, /* AMR 4.75 kbps */
+ MVS_AMR_MODE_0515, /* AMR 5.15 kbps */
+ MVS_AMR_MODE_0590, /* AMR 5.90 kbps */
+ MVS_AMR_MODE_0670, /* AMR 6.70 kbps */
+ MVS_AMR_MODE_0740, /* AMR 7.40 kbps */
+ MVS_AMR_MODE_0795, /* AMR 7.95 kbps */
+ MVS_AMR_MODE_1020, /* AMR 10.20 kbps */
+ MVS_AMR_MODE_1220, /* AMR 12.20 kbps */
+ MVS_AMR_MODE_0660, /* AMR-WB 6.60 kbps */
+ MVS_AMR_MODE_0885, /* AMR-WB 8.85 kbps */
+ MVS_AMR_MODE_1265, /* AMR-WB 12.65 kbps */
+ MVS_AMR_MODE_1425, /* AMR-WB 14.25 kbps */
+ MVS_AMR_MODE_1585, /* AMR-WB 15.85 kbps */
+ MVS_AMR_MODE_1825, /* AMR-WB 18.25 kbps */
+ MVS_AMR_MODE_1985, /* AMR-WB 19.85 kbps */
+ MVS_AMR_MODE_2305, /* AMR-WB 23.05 kbps */
+ MVS_AMR_MODE_2385, /* AMR-WB 23.85 kbps */
+ MVS_AMR_MODE_UNDEF
+};
+
+/* The MVS VOC rate type is used to identify the rate of QCELP 13K(IS733),
+ * EVRC(IS127), 4GV, or 4GV-WB frame.
+ */
+enum msm_audio_voc_rate {
+ MVS_VOC_0_RATE, /* Blank frame */
+ MVS_VOC_8_RATE, /* 1/8 rate */
+ MVS_VOC_4_RATE, /* 1/4 rate */
+ MVS_VOC_2_RATE, /* 1/2 rate */
+ MVS_VOC_1_RATE, /* Full rate */
+ MVS_VOC_ERASURE, /* erasure frame */
+ MVS_VOC_RATE_MAX,
+ MVS_VOC_RATE_UNDEF = MVS_VOC_RATE_MAX
+};
+
+enum msm_audio_amr_frame_type {
+ MVS_AMR_SPEECH_GOOD, /* Good speech frame */
+ MVS_AMR_SPEECH_DEGRADED, /* Speech degraded */
+ MVS_AMR_ONSET, /* Onset */
+ MVS_AMR_SPEECH_BAD, /* Corrupt speech frame (bad CRC) */
+ MVS_AMR_SID_FIRST, /* First silence descriptor */
+ MVS_AMR_SID_UPDATE, /* Comfort noise frame */
+ MVS_AMR_SID_BAD, /* Corrupt SID frame (bad CRC) */
+ MVS_AMR_NO_DATA, /* Nothing to transmit */
+ MVS_AMR_SPEECH_LOST /* Downlink speech lost */
+};
+
+enum msm_audio_g711a_mode {
+ MVS_G711A_MODE_MULAW,
+ MVS_G711A_MODE_ALAW
+};
+
+enum msm_audio_g711_mode {
+ MVS_G711_MODE_MULAW,
+ MVS_G711_MODE_ALAW
+};
+
+enum mvs_g722_mode_type {
+ MVS_G722_MODE_01,
+ MVS_G722_MODE_02,
+ MVS_G722_MODE_03,
+ MVS_G722_MODE_MAX,
+ MVS_G722_MODE_UNDEF
+};
+
+enum msm_audio_g711a_frame_type {
+ MVS_G711A_SPEECH_GOOD,
+ MVS_G711A_SID,
+ MVS_G711A_NO_DATA,
+ MVS_G711A_ERASURE
+};
+
+enum msm_audio_g729a_frame_type {
+ MVS_G729A_NO_DATA,
+ MVS_G729A_SPEECH_GOOD,
+ MVS_G729A_SID,
+ MVS_G729A_ERASURE
+};
+
+struct min_max_rate {
+ uint32_t min_rate;
+ uint32_t max_rate;
+};
+
+struct msm_audio_mvs_config {
+ uint32_t mvs_mode;
+ uint32_t rate_type;
+ struct min_max_rate min_max_rate;
+ uint32_t dtx_mode;
+};
+
+#define MVS_MAX_VOC_PKT_SIZE 640
+
+struct gsm_header {
+ uint8_t bfi;
+ uint8_t sid;
+ uint8_t taf;
+ uint8_t ufi;
+};
+
+struct q6_msm_audio_mvs_frame {
+ union {
+ uint32_t frame_type;
+ uint32_t packet_rate;
+ struct gsm_header gsm_frame_type;
+ } header;
+ uint32_t len;
+ uint8_t voc_pkt[MVS_MAX_VOC_PKT_SIZE];
+
+};
+
+struct msm_audio_mvs_frame {
+ uint32_t frame_type;
+ uint32_t len;
+ uint8_t voc_pkt[MVS_MAX_VOC_PKT_SIZE];
+
+};
+
+#define Q5V2_MVS_MAX_VOC_PKT_SIZE 320
+
+struct q5v2_msm_audio_mvs_frame {
+ uint32_t frame_type;
+ uint32_t len;
+ uint8_t voc_pkt[Q5V2_MVS_MAX_VOC_PKT_SIZE];
+
+};
+#endif /* _UAPI_MSM_AUDIO_MVS_H */
diff --git a/include/uapi/linux/msm_audio_qcp.h b/include/uapi/linux/msm_audio_qcp.h
new file mode 100644
index 0000000..fdb234e
--- /dev/null
+++ b/include/uapi/linux/msm_audio_qcp.h
@@ -0,0 +1,37 @@
+#ifndef _UAPI_MSM_AUDIO_QCP_H
+#define _UAPI_MSM_AUDIO_QCP_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_QCELP_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ 0, struct msm_audio_qcelp_enc_config)
+
+#define AUDIO_GET_QCELP_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ 1, struct msm_audio_qcelp_enc_config)
+
+#define AUDIO_SET_EVRC_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ 2, struct msm_audio_evrc_enc_config)
+
+#define AUDIO_GET_EVRC_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ 3, struct msm_audio_evrc_enc_config)
+
+#define CDMA_RATE_BLANK 0x00
+#define CDMA_RATE_EIGHTH 0x01
+#define CDMA_RATE_QUARTER 0x02
+#define CDMA_RATE_HALF 0x03
+#define CDMA_RATE_FULL 0x04
+#define CDMA_RATE_ERASURE 0x05
+
+struct msm_audio_qcelp_enc_config {
+ uint32_t cdma_rate;
+ uint32_t min_bit_rate;
+ uint32_t max_bit_rate;
+};
+
+struct msm_audio_evrc_enc_config {
+ uint32_t cdma_rate;
+ uint32_t min_bit_rate;
+ uint32_t max_bit_rate;
+};
+
+#endif /* _UAPI_MSM_AUDIO_QCP_H */
diff --git a/include/uapi/linux/msm_audio_sbc.h b/include/uapi/linux/msm_audio_sbc.h
new file mode 100644
index 0000000..1c7c63d
--- /dev/null
+++ b/include/uapi/linux/msm_audio_sbc.h
@@ -0,0 +1,36 @@
+#ifndef _UAPI_MSM_AUDIO_SBC_H
+#define _UAPI_MSM_AUDIO_SBC_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_SBC_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_sbc_enc_config)
+
+#define AUDIO_GET_SBC_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_sbc_enc_config)
+
+#define AUDIO_SBC_BA_LOUDNESS 0x0
+#define AUDIO_SBC_BA_SNR 0x1
+
+#define AUDIO_SBC_MODE_MONO 0x0
+#define AUDIO_SBC_MODE_DUAL 0x1
+#define AUDIO_SBC_MODE_STEREO 0x2
+#define AUDIO_SBC_MODE_JSTEREO 0x3
+
+#define AUDIO_SBC_BANDS_8 0x1
+
+#define AUDIO_SBC_BLOCKS_4 0x0
+#define AUDIO_SBC_BLOCKS_8 0x1
+#define AUDIO_SBC_BLOCKS_12 0x2
+#define AUDIO_SBC_BLOCKS_16 0x3
+
+struct msm_audio_sbc_enc_config {
+ uint32_t channels;
+ uint32_t sample_rate;
+ uint32_t bit_allocation;
+ uint32_t number_of_subbands;
+ uint32_t number_of_blocks;
+ uint32_t bit_rate;
+ uint32_t mode;
+};
+#endif /* _UAPI_MSM_AUDIO_SBC_H */
diff --git a/include/uapi/linux/msm_audio_voicememo.h b/include/uapi/linux/msm_audio_voicememo.h
new file mode 100644
index 0000000..a7a7a4d
--- /dev/null
+++ b/include/uapi/linux/msm_audio_voicememo.h
@@ -0,0 +1,66 @@
+#ifndef _UAPI_MSM_AUDIO_VOICEMEMO_H
+#define _UAPI_MSM_AUDIO_VOICEMEMO_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_GET_VOICEMEMO_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned int)
+#define AUDIO_SET_VOICEMEMO_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned int)
+
+/* rec_type */
+enum rpc_voc_rec_dir_type {
+ RPC_VOC_REC_NONE,
+ RPC_VOC_REC_FORWARD,
+ RPC_VOC_REC_REVERSE,
+ RPC_VOC_REC_BOTH,
+ RPC_VOC_MAX_REC_TYPE
+};
+
+/* capability */
+enum rpc_voc_capability_type {
+ RPC_VOC_CAP_IS733 = 4,
+ RPC_VOC_CAP_IS127 = 8,
+ RPC_VOC_CAP_AMR = 64,
+ RPC_VOC_CAP_32BIT_DUMMY = 2147483647
+};
+
+/* Rate */
+enum rpc_voc_rate_type {
+ RPC_VOC_0_RATE = 0,
+ RPC_VOC_8_RATE,
+ RPC_VOC_4_RATE,
+ RPC_VOC_2_RATE,
+ RPC_VOC_1_RATE,
+ RPC_VOC_ERASURE,
+ RPC_VOC_ERR_RATE,
+ RPC_VOC_AMR_RATE_475 = 0,
+ RPC_VOC_AMR_RATE_515 = 1,
+ RPC_VOC_AMR_RATE_590 = 2,
+ RPC_VOC_AMR_RATE_670 = 3,
+ RPC_VOC_AMR_RATE_740 = 4,
+ RPC_VOC_AMR_RATE_795 = 5,
+ RPC_VOC_AMR_RATE_1020 = 6,
+ RPC_VOC_AMR_RATE_1220 = 7,
+};
+
+/* frame_format */
+enum rpc_voc_pb_len_rate_var_type {
+ RPC_VOC_PB_NATIVE_QCP = 3,
+ RPC_VOC_PB_AMR,
+ RPC_VOC_PB_EVB
+};
+
+struct msm_audio_voicememo_config {
+ uint32_t rec_type;
+ uint32_t rec_interval_ms;
+ uint32_t auto_stop_ms;
+ uint32_t capability;
+ uint32_t max_rate;
+ uint32_t min_rate;
+ uint32_t frame_format;
+ uint32_t dtx_enable;
+ uint32_t data_req_ms;
+};
+
+#endif /* _UAPI_MSM_AUDIO_VOICEMEMO_H */
diff --git a/include/uapi/linux/msm_audio_wma.h b/include/uapi/linux/msm_audio_wma.h
new file mode 100644
index 0000000..523fade
--- /dev/null
+++ b/include/uapi/linux/msm_audio_wma.h
@@ -0,0 +1,33 @@
+#ifndef _UAPI_MSM_AUDIO_WMA_H
+#define _UAPI_MSM_AUDIO_WMA_H
+
+#define AUDIO_GET_WMA_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned int)
+#define AUDIO_SET_WMA_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned int)
+
+#define AUDIO_GET_WMA_CONFIG_V2 _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2), struct msm_audio_wma_config_v2)
+#define AUDIO_SET_WMA_CONFIG_V2 _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_wma_config_v2)
+
+struct msm_audio_wma_config {
+ unsigned short armdatareqthr;
+ unsigned short channelsdecoded;
+ unsigned short wmabytespersec;
+ unsigned short wmasamplingfreq;
+ unsigned short wmaencoderopts;
+};
+
+struct msm_audio_wma_config_v2 {
+ unsigned short format_tag;
+ unsigned short numchannels;
+ uint32_t samplingrate;
+ uint32_t avgbytespersecond;
+ unsigned short block_align;
+ unsigned short validbitspersample;
+ uint32_t channelmask;
+ unsigned short encodeopt;
+};
+
+#endif /* _UAPI_MSM_AUDIO_WMA_H */
diff --git a/include/uapi/linux/msm_audio_wmapro.h b/include/uapi/linux/msm_audio_wmapro.h
new file mode 100644
index 0000000..64cbf9e
--- /dev/null
+++ b/include/uapi/linux/msm_audio_wmapro.h
@@ -0,0 +1,22 @@
+#ifndef _UAPI_MSM_AUDIO_WMAPRO_H
+#define _UAPI_MSM_AUDIO_WMAPRO_H
+
+#define AUDIO_GET_WMAPRO_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_wmapro_config)
+#define AUDIO_SET_WMAPRO_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_wmapro_config)
+
+struct msm_audio_wmapro_config {
+ unsigned short armdatareqthr;
+ uint8_t validbitspersample;
+ uint8_t numchannels;
+ unsigned short formattag;
+ uint32_t samplingrate;
+ uint32_t avgbytespersecond;
+ unsigned short asfpacketlength;
+ uint32_t channelmask;
+ unsigned short encodeopt;
+ unsigned short advancedencodeopt;
+ uint32_t advancedencodeopt2;
+};
+#endif /* _UAPI_MSM_AUDIO_WMAPRO_H */
diff --git a/include/uapi/sound/Kbuild b/include/uapi/sound/Kbuild
index 9578d8b..5b0a9bc 100644
--- a/include/uapi/sound/Kbuild
+++ b/include/uapi/sound/Kbuild
@@ -14,3 +14,10 @@
header-y += tlv.h
header-y += usb_stream.h
header-y += snd_sst_tokens.h
+header-y += lsm_params.h
+header-y += audio_slimslave.h
+header-y += voice_params.h
+header-y += audio_effects.h
+header-y += voice_svc.h
+header-y += devdep_params.h
+header-y += msmcal-hwdep.h
diff --git a/include/uapi/sound/audio_effects.h b/include/uapi/sound/audio_effects.h
new file mode 100644
index 0000000..063b5c1
--- /dev/null
+++ b/include/uapi/sound/audio_effects.h
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _AUDIO_EFFECTS_H
+#define _AUDIO_EFFECTS_H
+
+/** AUDIO EFFECTS **/
+
+
+/* CONFIG GET/SET */
+#define CONFIG_CACHE 0
+#define CONFIG_SET 1
+#define CONFIG_GET 2
+
+/* CONFIG HEADER */
+/*
+ * MODULE_ID,
+ * DEVICE,
+ * NUM_COMMANDS,
+ * COMMAND_ID_1,
+ * CONFIG_CACHE/SET/GET,
+ * OFFSET_1,
+ * LENGTH_1,
+ * VALUES_1,
+ * ...,
+ * ...,
+ * COMMAND_ID_2,
+ * CONFIG_CACHE/SET/GET,
+ * OFFSET_2,
+ * LENGTH_2,
+ * VALUES_2,
+ * ...,
+ * ...,
+ * COMMAND_ID_3,
+ * ...
+ */
+
+
+/* CONFIG PARAM IDs */
+#define VIRTUALIZER_MODULE 0x00001000
+#define VIRTUALIZER_ENABLE 0x00001001
+#define VIRTUALIZER_STRENGTH 0x00001002
+#define VIRTUALIZER_OUT_TYPE 0x00001003
+#define VIRTUALIZER_GAIN_ADJUST 0x00001004
+#define VIRTUALIZER_ENABLE_PARAM_LEN 1
+#define VIRTUALIZER_STRENGTH_PARAM_LEN 1
+#define VIRTUALIZER_OUT_TYPE_PARAM_LEN 1
+#define VIRTUALIZER_GAIN_ADJUST_PARAM_LEN 1
+
+#define REVERB_MODULE 0x00002000
+#define REVERB_ENABLE 0x00002001
+#define REVERB_MODE 0x00002002
+#define REVERB_PRESET 0x00002003
+#define REVERB_WET_MIX 0x00002004
+#define REVERB_GAIN_ADJUST 0x00002005
+#define REVERB_ROOM_LEVEL 0x00002006
+#define REVERB_ROOM_HF_LEVEL 0x00002007
+#define REVERB_DECAY_TIME 0x00002008
+#define REVERB_DECAY_HF_RATIO 0x00002009
+#define REVERB_REFLECTIONS_LEVEL 0x0000200a
+#define REVERB_REFLECTIONS_DELAY 0x0000200b
+#define REVERB_LEVEL 0x0000200c
+#define REVERB_DELAY 0x0000200d
+#define REVERB_DIFFUSION 0x0000200e
+#define REVERB_DENSITY 0x0000200f
+#define REVERB_ENABLE_PARAM_LEN 1
+#define REVERB_MODE_PARAM_LEN 1
+#define REVERB_PRESET_PARAM_LEN 1
+#define REVERB_WET_MIX_PARAM_LEN 1
+#define REVERB_GAIN_ADJUST_PARAM_LEN 1
+#define REVERB_ROOM_LEVEL_PARAM_LEN 1
+#define REVERB_ROOM_HF_LEVEL_PARAM_LEN 1
+#define REVERB_DECAY_TIME_PARAM_LEN 1
+#define REVERB_DECAY_HF_RATIO_PARAM_LEN 1
+#define REVERB_REFLECTIONS_LEVEL_PARAM_LEN 1
+#define REVERB_REFLECTIONS_DELAY_PARAM_LEN 1
+#define REVERB_LEVEL_PARAM_LEN 1
+#define REVERB_DELAY_PARAM_LEN 1
+#define REVERB_DIFFUSION_PARAM_LEN 1
+#define REVERB_DENSITY_PARAM_LEN 1
+
+#define BASS_BOOST_MODULE 0x00003000
+#define BASS_BOOST_ENABLE 0x00003001
+#define BASS_BOOST_MODE 0x00003002
+#define BASS_BOOST_STRENGTH 0x00003003
+#define BASS_BOOST_ENABLE_PARAM_LEN 1
+#define BASS_BOOST_MODE_PARAM_LEN 1
+#define BASS_BOOST_STRENGTH_PARAM_LEN 1
+
+#define EQ_MODULE 0x00004000
+#define EQ_ENABLE 0x00004001
+#define EQ_CONFIG 0x00004002
+#define EQ_NUM_BANDS 0x00004003
+#define EQ_BAND_LEVELS 0x00004004
+#define EQ_BAND_LEVEL_RANGE 0x00004005
+#define EQ_BAND_FREQS 0x00004006
+#define EQ_SINGLE_BAND_FREQ_RANGE 0x00004007
+#define EQ_SINGLE_BAND_FREQ 0x00004008
+#define EQ_BAND_INDEX 0x00004009
+#define EQ_PRESET_ID 0x0000400a
+#define EQ_NUM_PRESETS 0x0000400b
+#define EQ_PRESET_NAME 0x0000400c
+#define EQ_ENABLE_PARAM_LEN 1
+#define EQ_CONFIG_PARAM_LEN 3
+#define EQ_CONFIG_PER_BAND_PARAM_LEN 5
+#define EQ_NUM_BANDS_PARAM_LEN 1
+#define EQ_BAND_LEVELS_PARAM_LEN 13
+#define EQ_BAND_LEVEL_RANGE_PARAM_LEN 2
+#define EQ_BAND_FREQS_PARAM_LEN 13
+#define EQ_SINGLE_BAND_FREQ_RANGE_PARAM_LEN 2
+#define EQ_SINGLE_BAND_FREQ_PARAM_LEN 1
+#define EQ_BAND_INDEX_PARAM_LEN 1
+#define EQ_PRESET_ID_PARAM_LEN 1
+#define EQ_NUM_PRESETS_PARAM_LEN 1
+#define EQ_PRESET_NAME_PARAM_LEN 32
+
+#define EQ_TYPE_NONE 0
+#define EQ_BASS_BOOST 1
+#define EQ_BASS_CUT 2
+#define EQ_TREBLE_BOOST 3
+#define EQ_TREBLE_CUT 4
+#define EQ_BAND_BOOST 5
+#define EQ_BAND_CUT 6
+
+#define SOFT_VOLUME_MODULE 0x00006000
+#define SOFT_VOLUME_ENABLE 0x00006001
+#define SOFT_VOLUME_GAIN_2CH 0x00006002
+#define SOFT_VOLUME_GAIN_MASTER 0x00006003
+#define SOFT_VOLUME_ENABLE_PARAM_LEN 1
+#define SOFT_VOLUME_GAIN_2CH_PARAM_LEN 2
+#define SOFT_VOLUME_GAIN_MASTER_PARAM_LEN 1
+
+#define SOFT_VOLUME2_MODULE 0x00007000
+#define SOFT_VOLUME2_ENABLE 0x00007001
+#define SOFT_VOLUME2_GAIN_2CH 0x00007002
+#define SOFT_VOLUME2_GAIN_MASTER 0x00007003
+#define SOFT_VOLUME2_ENABLE_PARAM_LEN SOFT_VOLUME_ENABLE_PARAM_LEN
+#define SOFT_VOLUME2_GAIN_2CH_PARAM_LEN SOFT_VOLUME_GAIN_2CH_PARAM_LEN
+#define SOFT_VOLUME2_GAIN_MASTER_PARAM_LEN \
+ SOFT_VOLUME_GAIN_MASTER_PARAM_LEN
+
+#define PBE_CONF_MODULE_ID 0x00010C2A
+#define PBE_CONF_PARAM_ID 0x00010C49
+
+#define PBE_MODULE 0x00008000
+#define PBE_ENABLE 0x00008001
+#define PBE_CONFIG 0x00008002
+#define PBE_ENABLE_PARAM_LEN 1
+#define PBE_CONFIG_PARAM_LEN 28
+
+#define COMMAND_PAYLOAD_LEN 3
+#define COMMAND_PAYLOAD_SZ (COMMAND_PAYLOAD_LEN * sizeof(uint32_t))
+#define MAX_INBAND_PARAM_SZ 4096
+#define Q27_UNITY (1 << 27)
+#define Q8_UNITY (1 << 8)
+#define CUSTOM_OPENSL_PRESET 18
+
+#define VIRTUALIZER_ENABLE_PARAM_SZ \
+ (VIRTUALIZER_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_STRENGTH_PARAM_SZ \
+ (VIRTUALIZER_STRENGTH_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_OUT_TYPE_PARAM_SZ \
+ (VIRTUALIZER_OUT_TYPE_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_GAIN_ADJUST_PARAM_SZ \
+ (VIRTUALIZER_GAIN_ADJUST_PARAM_LEN*sizeof(uint32_t))
+struct virtualizer_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ uint32_t strength;
+ uint32_t out_type;
+ int32_t gain_adjust;
+};
+
+#define NUM_OSL_REVERB_PRESETS_SUPPORTED 6
+#define REVERB_ENABLE_PARAM_SZ \
+ (REVERB_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_MODE_PARAM_SZ \
+ (REVERB_MODE_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_PRESET_PARAM_SZ \
+ (REVERB_PRESET_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_WET_MIX_PARAM_SZ \
+ (REVERB_WET_MIX_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_GAIN_ADJUST_PARAM_SZ \
+ (REVERB_GAIN_ADJUST_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_ROOM_LEVEL_PARAM_SZ \
+ (REVERB_ROOM_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_ROOM_HF_LEVEL_PARAM_SZ \
+ (REVERB_ROOM_HF_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DECAY_TIME_PARAM_SZ \
+ (REVERB_DECAY_TIME_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DECAY_HF_RATIO_PARAM_SZ \
+ (REVERB_DECAY_HF_RATIO_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_REFLECTIONS_LEVEL_PARAM_SZ \
+ (REVERB_REFLECTIONS_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_REFLECTIONS_DELAY_PARAM_SZ \
+ (REVERB_REFLECTIONS_DELAY_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_LEVEL_PARAM_SZ \
+ (REVERB_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DELAY_PARAM_SZ \
+ (REVERB_DELAY_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DIFFUSION_PARAM_SZ \
+ (REVERB_DIFFUSION_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DENSITY_PARAM_SZ \
+ (REVERB_DENSITY_PARAM_LEN*sizeof(uint32_t))
+struct reverb_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ uint32_t mode;
+ uint32_t preset;
+ uint32_t wet_mix;
+ int32_t gain_adjust;
+ int32_t room_level;
+ int32_t room_hf_level;
+ uint32_t decay_time;
+ uint32_t decay_hf_ratio;
+ int32_t reflections_level;
+ uint32_t reflections_delay;
+ int32_t level;
+ uint32_t delay;
+ uint32_t diffusion;
+ uint32_t density;
+};
+
+#define BASS_BOOST_ENABLE_PARAM_SZ \
+ (BASS_BOOST_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define BASS_BOOST_MODE_PARAM_SZ \
+ (BASS_BOOST_MODE_PARAM_LEN*sizeof(uint32_t))
+#define BASS_BOOST_STRENGTH_PARAM_SZ \
+ (BASS_BOOST_STRENGTH_PARAM_LEN*sizeof(uint32_t))
+struct bass_boost_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ uint32_t mode;
+ uint32_t strength;
+};
+
+
+#define MAX_EQ_BANDS 12
+#define MAX_OSL_EQ_BANDS 5
+#define EQ_ENABLE_PARAM_SZ \
+ (EQ_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PARAM_SZ \
+ (EQ_CONFIG_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PER_BAND_PARAM_SZ \
+ (EQ_CONFIG_PER_BAND_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PARAM_MAX_LEN (EQ_CONFIG_PARAM_LEN+\
+ MAX_EQ_BANDS*EQ_CONFIG_PER_BAND_PARAM_LEN)
+#define EQ_CONFIG_PARAM_MAX_SZ \
+ (EQ_CONFIG_PARAM_MAX_LEN*sizeof(uint32_t))
+#define EQ_NUM_BANDS_PARAM_SZ \
+ (EQ_NUM_BANDS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_LEVELS_PARAM_SZ \
+ (EQ_BAND_LEVELS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_LEVEL_RANGE_PARAM_SZ \
+ (EQ_BAND_LEVEL_RANGE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_FREQS_PARAM_SZ \
+ (EQ_BAND_FREQS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_SINGLE_BAND_FREQ_RANGE_PARAM_SZ \
+ (EQ_SINGLE_BAND_FREQ_RANGE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_SINGLE_BAND_FREQ_PARAM_SZ \
+ (EQ_SINGLE_BAND_FREQ_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_INDEX_PARAM_SZ \
+ (EQ_BAND_INDEX_PARAM_LEN*sizeof(uint32_t))
+#define EQ_PRESET_ID_PARAM_SZ \
+ (EQ_PRESET_ID_PARAM_LEN*sizeof(uint32_t))
+#define EQ_NUM_PRESETS_PARAM_SZ \
+ (EQ_NUM_PRESETS_PARAM_LEN*sizeof(uint8_t))
+struct eq_config_t {
+ int32_t eq_pregain;
+ int32_t preset_id;
+ uint32_t num_bands;
+};
+struct eq_per_band_config_t {
+ int32_t band_idx;
+ uint32_t filter_type;
+ uint32_t freq_millihertz;
+ int32_t gain_millibels;
+ uint32_t quality_factor;
+};
+struct eq_per_band_freq_range_t {
+ uint32_t band_index;
+ uint32_t min_freq_millihertz;
+ uint32_t max_freq_millihertz;
+};
+
+struct eq_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ struct eq_config_t config;
+ struct eq_per_band_config_t per_band_cfg[MAX_EQ_BANDS];
+ struct eq_per_band_freq_range_t per_band_freq_range[MAX_EQ_BANDS];
+ uint32_t band_index;
+ uint32_t freq_millihertz;
+};
+
+#define PBE_ENABLE_PARAM_SZ \
+ (PBE_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define PBE_CONFIG_PARAM_SZ \
+ (PBE_CONFIG_PARAM_LEN*sizeof(uint16_t))
+struct pbe_config_t {
+ int16_t real_bass_mix;
+ int16_t bass_color_control;
+ uint16_t main_chain_delay;
+ uint16_t xover_filter_order;
+ uint16_t bandpass_filter_order;
+ int16_t drc_delay;
+ uint16_t rms_tav;
+ int16_t exp_threshold;
+ uint16_t exp_slope;
+ int16_t comp_threshold;
+ uint16_t comp_slope;
+ uint16_t makeup_gain;
+ uint32_t comp_attack;
+ uint32_t comp_release;
+ uint32_t exp_attack;
+ uint32_t exp_release;
+ int16_t limiter_bass_threshold;
+ int16_t limiter_high_threshold;
+ int16_t limiter_bass_makeup_gain;
+ int16_t limiter_high_makeup_gain;
+ int16_t limiter_bass_gc;
+ int16_t limiter_high_gc;
+ int16_t limiter_delay;
+ uint16_t reserved;
+ /* place holder for filter coeffs to be followed */
+ int32_t p1LowPassCoeffs[5*2];
+ int32_t p1HighPassCoeffs[5*2];
+ int32_t p1BandPassCoeffs[5*3];
+ int32_t p1BassShelfCoeffs[5];
+ int32_t p1TrebleShelfCoeffs[5];
+} __packed;
+
+struct pbe_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ uint32_t cfg_len;
+ struct pbe_config_t config;
+};
+
+#define SOFT_VOLUME_ENABLE_PARAM_SZ \
+ (SOFT_VOLUME_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define SOFT_VOLUME_GAIN_MASTER_PARAM_SZ \
+ (SOFT_VOLUME_GAIN_MASTER_PARAM_LEN*sizeof(uint32_t))
+#define SOFT_VOLUME_GAIN_2CH_PARAM_SZ \
+ (SOFT_VOLUME_GAIN_2CH_PARAM_LEN*sizeof(uint16_t))
+struct soft_volume_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ uint32_t master_gain;
+ uint32_t left_gain;
+ uint32_t right_gain;
+};
+
+struct msm_nt_eff_all_config {
+ struct bass_boost_params bass_boost;
+ struct pbe_params pbe;
+ struct virtualizer_params virtualizer;
+ struct reverb_params reverb;
+ struct eq_params equalizer;
+ struct soft_volume_params saplus_vol;
+ struct soft_volume_params topo_switch_vol;
+};
+
+#endif /*_MSM_AUDIO_EFFECTS_H*/
diff --git a/include/uapi/sound/devdep_params.h b/include/uapi/sound/devdep_params.h
new file mode 100644
index 0000000..5061ec0
--- /dev/null
+++ b/include/uapi/sound/devdep_params.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DEV_DEP_H
+#define _DEV_DEP_H
+
+struct dolby_param_data {
+ int32_t version;
+ int32_t device_id;
+ int32_t be_id;
+ int32_t param_id;
+ int32_t length;
+ int32_t __user *data;
+};
+
+struct dolby_param_license {
+ int32_t dmid;
+ int32_t license_key;
+};
+
+#define SNDRV_DEVDEP_DAP_IOCTL_SET_PARAM\
+ _IOWR('U', 0x10, struct dolby_param_data)
+#define SNDRV_DEVDEP_DAP_IOCTL_GET_PARAM\
+ _IOR('U', 0x11, struct dolby_param_data)
+#define SNDRV_DEVDEP_DAP_IOCTL_DAP_COMMAND\
+ _IOWR('U', 0x13, struct dolby_param_data)
+#define SNDRV_DEVDEP_DAP_IOCTL_DAP_LICENSE\
+ _IOWR('U', 0x14, struct dolby_param_license)
+#define SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER\
+ _IOR('U', 0x15, struct dolby_param_data)
+
+#define DTS_EAGLE_MODULE 0x00005000
+#define DTS_EAGLE_MODULE_ENABLE 0x00005001
+#define EAGLE_DRIVER_ID 0xF2
+#define DTS_EAGLE_IOCTL_GET_CACHE_SIZE _IOR(EAGLE_DRIVER_ID, 0, int)
+#define DTS_EAGLE_IOCTL_SET_CACHE_SIZE _IOW(EAGLE_DRIVER_ID, 1, int)
+#define DTS_EAGLE_IOCTL_GET_PARAM _IOR(EAGLE_DRIVER_ID, 2, void*)
+#define DTS_EAGLE_IOCTL_SET_PARAM _IOW(EAGLE_DRIVER_ID, 3, void*)
+#define DTS_EAGLE_IOCTL_SET_CACHE_BLOCK _IOW(EAGLE_DRIVER_ID, 4, void*)
+#define DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE _IOW(EAGLE_DRIVER_ID, 5, void*)
+#define DTS_EAGLE_IOCTL_GET_LICENSE _IOR(EAGLE_DRIVER_ID, 6, void*)
+#define DTS_EAGLE_IOCTL_SET_LICENSE _IOW(EAGLE_DRIVER_ID, 7, void*)
+#define DTS_EAGLE_IOCTL_SEND_LICENSE _IOW(EAGLE_DRIVER_ID, 8, int)
+#define DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS _IOW(EAGLE_DRIVER_ID, 9, void*)
+#define DTS_EAGLE_FLAG_IOCTL_PRE (1<<30)
+#define DTS_EAGLE_FLAG_IOCTL_JUSTSETCACHE (1<<31)
+#define DTS_EAGLE_FLAG_IOCTL_GETFROMCORE DTS_EAGLE_FLAG_IOCTL_JUSTSETCACHE
+#define DTS_EAGLE_FLAG_IOCTL_MASK (~(DTS_EAGLE_FLAG_IOCTL_PRE | \
+ DTS_EAGLE_FLAG_IOCTL_JUSTSETCACHE))
+#define DTS_EAGLE_FLAG_ALSA_GET (1<<31)
+
+struct dts_eagle_param_desc {
+ uint32_t id;
+ uint32_t size;
+ int32_t offset;
+ uint32_t device;
+} __packed;
+
+#endif
diff --git a/include/uapi/sound/lsm_params.h b/include/uapi/sound/lsm_params.h
new file mode 100644
index 0000000..eafdc11
--- /dev/null
+++ b/include/uapi/sound/lsm_params.h
@@ -0,0 +1,175 @@
+#ifndef _UAPI_LSM_PARAMS_H__
+#define _UAPI_LSM_PARAMS_H__
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+
+#define LSM_OUT_FORMAT_PCM (0)
+#define LSM_OUT_FORMAT_ADPCM (1 << 0)
+
+#define LSM_OUT_DATA_RAW (0)
+#define LSM_OUT_DATA_PACKED (1)
+
+#define LSM_OUT_DATA_EVENTS_DISABLED (0)
+#define LSM_OUT_DATA_EVENTS_ENABLED (1)
+
+#define LSM_OUT_TRANSFER_MODE_RT (0)
+#define LSM_OUT_TRANSFER_MODE_FTRT (1)
+
+enum lsm_app_id {
+ LSM_VOICE_WAKEUP_APP_ID = 1,
+ LSM_VOICE_WAKEUP_APP_ID_V2 = 2,
+};
+
+enum lsm_detection_mode {
+ LSM_MODE_KEYWORD_ONLY_DETECTION = 1,
+ LSM_MODE_USER_KEYWORD_DETECTION
+};
+
+enum lsm_vw_status {
+ LSM_VOICE_WAKEUP_STATUS_RUNNING = 1,
+ LSM_VOICE_WAKEUP_STATUS_DETECTED,
+ LSM_VOICE_WAKEUP_STATUS_END_SPEECH,
+ LSM_VOICE_WAKEUP_STATUS_REJECTED
+};
+
+enum LSM_PARAM_TYPE {
+ LSM_ENDPOINT_DETECT_THRESHOLD = 0,
+ LSM_OPERATION_MODE,
+ LSM_GAIN,
+ LSM_MIN_CONFIDENCE_LEVELS,
+ LSM_REG_SND_MODEL,
+ LSM_DEREG_SND_MODEL,
+ LSM_CUSTOM_PARAMS,
+ /* driver ioctl will parse only so many params */
+ LSM_PARAMS_MAX,
+};
+
+/*
+ * Data for LSM_ENDPOINT_DETECT_THRESHOLD param_type
+ * @epd_begin: Begin threshold
+ * @epd_end: End threshold
+ */
+struct snd_lsm_ep_det_thres {
+ __u32 epd_begin;
+ __u32 epd_end;
+};
+
+/*
+ * Data for LSM_OPERATION_MODE param_type
+ * @mode: The detection mode to be used
+ * @detect_failure: Setting to enable failure detections.
+ */
+struct snd_lsm_detect_mode {
+ enum lsm_detection_mode mode;
+ bool detect_failure;
+};
+
+/*
+ * Data for LSM_GAIN param_type
+ * @gain: The gain to be applied on LSM
+ */
+struct snd_lsm_gain {
+ __u16 gain;
+};
+
+
+struct snd_lsm_sound_model_v2 {
+ __u8 __user *data;
+ __u8 *confidence_level;
+ __u32 data_size;
+ enum lsm_detection_mode detection_mode;
+ __u8 num_confidence_levels;
+ bool detect_failure;
+};
+
+struct snd_lsm_session_data {
+ enum lsm_app_id app_id;
+};
+
+struct snd_lsm_event_status {
+ __u16 status;
+ __u16 payload_size;
+ __u8 payload[0];
+};
+
+struct snd_lsm_detection_params {
+ __u8 *conf_level;
+ enum lsm_detection_mode detect_mode;
+ __u8 num_confidence_levels;
+ bool detect_failure;
+};
+
+/*
+ * Param info for each parameter type
+ * @module_id: Module to which parameter is to be set
+ * @param_id: Parameter that is to be set
+ * @param_size: size (in number of bytes) for the data
+ * in param_data.
+ * For confidence levels, this is num_conf_levels
+ * For REG_SND_MODEL, this is size of sound model
+ * For CUSTOM_PARAMS, this is size of the entire blob of data
+ * @param_data: Data for the parameter.
+ * For some param_types this is a structure defined, ex: LSM_GAIN
+ * For CONFIDENCE_LEVELS, this is array of confidence levels
+ * For REG_SND_MODEL, this is the sound model data
+ * For CUSTOM_PARAMS, this is the blob of custom data.
+ */
+struct lsm_params_info {
+ __u32 module_id;
+ __u32 param_id;
+ __u32 param_size;
+ __u8 __user *param_data;
+ enum LSM_PARAM_TYPE param_type;
+};
+
+/*
+ * Data passed to the SET_PARAM_V2 IOCTL
+ * @num_params: Number of params that are to be set
+ * should not be greater than LSM_PARAMS_MAX
+ * @params: Points to an array of lsm_params_info
+ * Each entry points to one parameter to set
+ * @data_size: size (in bytes) for params
+ * should be equal to
+ * num_params * sizeof(struct lsm_parms_info)
+ */
+struct snd_lsm_module_params {
+ __u8 __user *params;
+ __u32 num_params;
+ __u32 data_size;
+};
+
+/*
+ * Data passed to LSM_OUT_FORMAT_CFG IOCTL
+ * @format: The media format enum
+ * @packing: indicates the packing method used for data path
+ * @events: indicates whether data path events need to be enabled
+ * @transfer_mode: indicates whether FTRT mode or RT mode.
+ */
+struct snd_lsm_output_format_cfg {
+ __u8 format;
+ __u8 packing;
+ __u8 events;
+ __u8 mode;
+};
+
+#define SNDRV_LSM_DEREG_SND_MODEL _IOW('U', 0x01, int)
+#define SNDRV_LSM_EVENT_STATUS _IOW('U', 0x02, struct snd_lsm_event_status)
+#define SNDRV_LSM_ABORT_EVENT _IOW('U', 0x03, int)
+#define SNDRV_LSM_START _IOW('U', 0x04, int)
+#define SNDRV_LSM_STOP _IOW('U', 0x05, int)
+#define SNDRV_LSM_SET_SESSION_DATA _IOW('U', 0x06, struct snd_lsm_session_data)
+#define SNDRV_LSM_REG_SND_MODEL_V2 _IOW('U', 0x07,\
+ struct snd_lsm_sound_model_v2)
+#define SNDRV_LSM_LAB_CONTROL _IOW('U', 0x08, uint32_t)
+#define SNDRV_LSM_STOP_LAB _IO('U', 0x09)
+#define SNDRV_LSM_SET_PARAMS _IOW('U', 0x0A, \
+ struct snd_lsm_detection_params)
+#define SNDRV_LSM_SET_MODULE_PARAMS _IOW('U', 0x0B, \
+ struct snd_lsm_module_params)
+#define SNDRV_LSM_OUT_FORMAT_CFG _IOW('U', 0x0C, \
+ struct snd_lsm_output_format_cfg)
+
+#endif
diff --git a/include/uapi/sound/msmcal-hwdep.h b/include/uapi/sound/msmcal-hwdep.h
new file mode 100644
index 0000000..2a29482
--- /dev/null
+++ b/include/uapi/sound/msmcal-hwdep.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CALIB_HWDEP_H
+#define _CALIB_HWDEP_H
+
+#define WCD9XXX_CODEC_HWDEP_NODE 1000
+enum wcd_cal_type {
+ WCD9XXX_MIN_CAL,
+ WCD9XXX_ANC_CAL = WCD9XXX_MIN_CAL,
+ WCD9XXX_MAD_CAL,
+ WCD9XXX_MBHC_CAL,
+ WCD9XXX_VBAT_CAL,
+ WCD9XXX_MAX_CAL,
+};
+
+struct wcdcal_ioctl_buffer {
+ __u32 size;
+ __u8 __user *buffer;
+ enum wcd_cal_type cal_type;
+};
+
+#define SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE \
+ _IOW('U', 0x1, struct wcdcal_ioctl_buffer)
+
+#endif /*_CALIB_HWDEP_H*/
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 182d92e..22b3073 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -54,6 +54,7 @@
source "sound/soc/img/Kconfig"
source "sound/soc/intel/Kconfig"
source "sound/soc/mediatek/Kconfig"
+source "sound/soc/msm/Kconfig"
source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/qcom/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 9a30f21..1466075 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -31,6 +31,7 @@
obj-$(CONFIG_SND_SOC) += img/
obj-$(CONFIG_SND_SOC) += intel/
obj-$(CONFIG_SND_SOC) += mediatek/
+obj-$(CONFIG_SND_SOC) += msm/
obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
new file mode 100644
index 0000000..a5cd94f
--- /dev/null
+++ b/sound/soc/msm/Kconfig
@@ -0,0 +1,236 @@
+menu "MSM SoC Audio support"
+
+config SND_SOC_MSM_HOSTLESS_PCM
+ tristate
+
+config SND_SOC_MSM_QDSP6V2_INTF
+ bool "SoC Q6 audio driver for MSM/APQ"
+ depends on MSM_QDSP6_APRV2_GLINK
+ help
+ To add support for SoC audio on MSM/APQ.
+ This will enable all the platform specific
+ interactions towards DSP. It includes asm,
+ adm and afe interfaces on the DSP.
+
+config SND_SOC_QDSP6V2
+ tristate "SoC ALSA audio driver for QDSP6V2"
+ select SND_SOC_MSM_QDSP6V2_INTF
+ select SND_SOC_COMPRESS
+ help
+ To add support for MSM QDSP6V2 Soc Audio.
+ This will enable sound soc platform specific
+ audio drivers. This includes q6asm, q6adm,
+ q6afe interfaces to DSP using apr.
+
+config SND_SOC_QDSP_DEBUG
+ bool "QDSP Audio Driver Debug Feature"
+ help
+ Configuration to enable debugging utilities for
+ QDSP6 based audio drivers. One debugging utility
+ is inducing kernel panic upon encountering critical
+ errors from DSP audio modules
+
+config DOLBY_DAP
+ bool "Enable Dolby DAP"
+ depends on SND_SOC_MSM_QDSP6V2_INTF
+ help
+ To add support for dolby DAP post processing.
+ This support is to configure the post processing parameters
+ to DSP. The configuration includes sending the end point
+ device, end point dependent post processing parameters and
+ the various posrt processing parameters
+
+config DOLBY_DS2
+ bool "Enable Dolby DS2"
+ depends on SND_SOC_MSM_QDSP6V2_INTF
+ help
+ To add support for dolby DAP post processing.
+ This support is to configure the post processing parameters
+ to DSP. The configuration includes sending the end point
+ device, end point dependent post processing parameters and
+ the various posrt processing parameters
+
+config DTS_EAGLE
+ bool "Enable DTS Eagle Support"
+ depends on SND_SOC_MSM_QDSP6V2_INTF
+ select SND_HWDEP
+ help
+ To add DTS Eagle support on QDSP6 targets.
+ Eagle is a DTS pre/post processing
+ package that includes HeadphoneX. The configuration
+ includes sending tuning parameters of various modules.
+
+config DTS_SRS_TM
+ bool "Enable DTS SRS"
+ depends on SND_SOC_MSM_QDSP6V2_INTF
+ help
+ To add support for DTS SRS post processing.
+ This support is to configure the post processing
+ parameters to DSP. The configuration includes sending
+ tuning parameters of various modules.
+
+config QTI_PP
+ bool "Enable QTI PP"
+ depends on SND_SOC_MSM_QDSP6V2_INTF
+ help
+ To add support for default QTI post processing.
+ This support is to configure the post processing
+ parameters to DSP. The configuration includes sending
+ tuning parameters of various modules such as equalizer,
+ customized mixing.
+
+config QTI_PP_AUDIOSPHERE
+ bool "Enable QTI AUDIOSPHERE PP"
+ depends on SND_SOC_MSM_QDSP6V2_INTF
+ help
+ To add support for QTI audio sphere post processing.
+ This support is to configure the post processing
+ parameters to DSP. The configuration includes sending
+ tuning parameters of audio sphere module.
+
+config SND_SOC_CPE
+ tristate "CPE drivers"
+ depends on SND_SOC_WCD_CPE
+ help
+ To add support for Codec Processing Engine. This support
+ is to enable CPE block on the codec and this config needs
+ to be added to codecs that contain the CPE hardware block.
+ The configuration includes the cpe lsm driver to enable
+ listen on codec.
+
+config SND_SOC_INT_CODEC
+ tristate "SoC Machine driver for MSMFALCON_INT"
+ depends on ARCH_QCOM
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_DYNAMIC_MINORS
+ select MSM_QDSP6_APRV2_GLINK
+ select MSM_QDSP6_SSR
+ select MSM_QDSP6_PDR
+ select MSM_QDSP6_NOTIFIER
+ select MSM_QDSP6V2_CODECS
+ select SND_SOC_MSM_SWR
+ select SND_SOC_MSM8X16_WCD
+ select QTI_PP
+ select DTS_SRS_TM
+ select DOLBY_DAP
+ select DOLBY_DS2
+ select SND_HWDEP
+ select MSM_ULTRASOUND
+ select DTS_EAGLE
+ select SND_SOC_MSMFALCON_COMMON
+ select SND_SOC_COMPRESS
+ help
+ To add support for SoC audio on MSM_INT.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine driver and the corresponding
+ DAI-links
+
+config SND_SOC_EXT_CODEC
+ tristate "SoC Machine driver for MSMFALCON_EXT"
+ depends on ARCH_QCOM
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_DYNAMIC_MINORS
+ select MSM_QDSP6_APRV2_GLINK
+ select MSM_QDSP6_SSR
+ select MSM_QDSP6_PDR
+ select MSM_QDSP6_NOTIFIER
+ select MSM_QDSP6V2_CODECS
+ select SND_SOC_WCD9335
+ select SND_SOC_WCD934X
+ select SND_SOC_WSA881X
+ select MFD_CORE
+ select QTI_PP
+ select DTS_SRS_TM
+ select DOLBY_DAP
+ select DOLBY_DS2
+ select SND_SOC_CPE
+ select SND_SOC_WCD_CPE
+ select SND_HWDEP
+ select MSM_ULTRASOUND
+ select DTS_EAGLE
+ select SND_SOC_MSMFALCON_COMMON
+ select SND_SOC_COMPRESS
+ help
+ To add support for SoC audio on MSM_EXT.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine driver and the corresponding
+ DAI-links
+
+config SND_SOC_MSM8996
+ tristate "SoC Machine driver for MSM8996 boards"
+ depends on ARCH_MSM8996
+ select SND_SOC_COMPRESS
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_DYNAMIC_MINORS
+ select MSM_QDSP6_APRV2
+ select MSM_QDSP6V2_CODECS
+ select SND_SOC_WCD9335
+ select SND_SOC_WSA881X
+ select SND_SOC_MSM_HDMI_CODEC_RX
+ select DTS_SRS_TM
+ select QTI_PP
+ select QTI_PP_AUDIOSPHERE
+ select SND_SOC_CPE
+ select MSM_ULTRASOUND
+ select DOLBY_DS2
+ select SND_HWDEP
+ select DTS_EAGLE
+ help
+ To add support for SoC audio on MSM8996.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine driver and the corresponding
+ DAI-links
+
+config SND_SOC_MSM8998
+ tristate "SoC Machine driver for MSM8998 boards"
+ depends on ARCH_QCOM
+ select SND_SOC_COMPRESS
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_DYNAMIC_MINORS
+ select MSM_QDSP6_APRV2_GLINK
+ select MSM_QDSP6_SSR
+ select MSM_QDSP6_PDR
+ select MSM_QDSP6_NOTIFIER
+ select MSM_QDSP6V2_CODECS
+ select SND_SOC_WCD9335
+ select SND_SOC_WCD934X
+ select SND_SOC_WSA881X
+ select SND_SOC_MSM_HDMI_CODEC_RX
+ select DTS_SRS_TM
+ select QTI_PP
+ select SND_SOC_CPE
+ select MSM_ULTRASOUND
+ select DOLBY_DS2
+ select SND_HWDEP
+ select DTS_EAGLE
+ help
+ To add support for SoC audio on MSM8998.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine driver and the corresponding
+ DAI-links
+
+config SND_SOC_FALCON
+ tristate "SoC Machine driver for MSMFALCON boards"
+ depends on ARCH_MSMFALCON
+ select SND_SOC_INT_CODEC
+ select SND_SOC_EXT_CODEC
+ help
+ To add support for SoC audio on MSMFALCON.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine driver and the corresponding
+ DAI-links
+
+endmenu
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
new file mode 100644
index 0000000..8df7fad
--- /dev/null
+++ b/sound/soc/msm/Makefile
@@ -0,0 +1,35 @@
+# MSM Machine Support
+
+snd-soc-hostless-pcm-objs := msm-pcm-hostless.o
+obj-$(CONFIG_SND_SOC_MSM_HOSTLESS_PCM) += snd-soc-hostless-pcm.o
+
+obj-$(CONFIG_SND_SOC_MSM_QDSP6V2_INTF) += qdsp6v2/
+
+snd-soc-qdsp6v2-objs := msm-dai-fe.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o
+
+#for CPE drivers
+snd-soc-cpe-objs := msm-cpe-lsm.o
+obj-$(CONFIG_SND_SOC_CPE) += snd-soc-cpe.o
+
+# for MSM8996 sound card driver
+snd-soc-msm8996-objs := msm8996.o
+obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-msm8996.o
+
+# for MSM8998 sound card driver
+snd-soc-msm8998-objs := msm8998.o
+obj-$(CONFIG_SND_SOC_MSM8998) += snd-soc-msm8998.o
+
+# for MSMFALCON sound card driver
+snd-soc-msmfalcon-common-objs := msm-audio-pinctrl.o msmfalcon-common.o
+obj-$(CONFIG_SND_SOC_MSMFALCON_COMMON) += snd-soc-msmfalcon-common.o
+
+# for MSMFALCON sound card driver
+snd-soc-int-codec-objs := msmfalcon-internal.o
+obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-msmfalcon-common.o
+obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-int-codec.o
+
+# for MSMFALCON sound card driver
+snd-soc-ext-codec-objs := msmfalcon-external.o msmfalcon-ext-dai-links.o
+obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-msmfalcon-common.o
+obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-ext-codec.o
diff --git a/sound/soc/msm/device_event.h b/sound/soc/msm/device_event.h
new file mode 100644
index 0000000..408d114
--- /dev/null
+++ b/sound/soc/msm/device_event.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DEVICE_EVENT_H
+#define __DEVICE_EVENT_H
+
+#define QC_AUDIO_EXTERNAL_SPK_1_EVENT "qc_ext_spk_1"
+#define QC_AUDIO_EXTERNAL_SPK_2_EVENT "qc_ext_spk_2"
+#define QC_AUDIO_EXTERNAL_MIC_EVENT "qc_ext_mic"
+
+#endif /* __DEVICE_EVENT_H */
diff --git a/sound/soc/msm/msm-audio-pinctrl.c b/sound/soc/msm/msm-audio-pinctrl.c
new file mode 100644
index 0000000..f0fba84
--- /dev/null
+++ b/sound/soc/msm/msm-audio-pinctrl.c
@@ -0,0 +1,316 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include "msm-audio-pinctrl.h"
+
+/*
+ * pinctrl -- handle to query pinctrl apis
+ * cdc lines -- stores pinctrl handles for pinctrl states
+ * active_set -- maintain the overall pinctrl state
+ */
+struct cdc_pinctrl_info {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state **cdc_lines;
+ int active_set;
+};
+
+/*
+ * gpiosets -- stores all gpiosets mentioned in dtsi file
+ * gpiosets_comb_names -- stores all possible gpioset combinations
+ * gpioset_state -- maintains counter for each gpioset
+ * gpiosets_max -- maintain the total supported gpiosets
+ * gpiosets_comb_max -- maintain the total gpiosets combinations
+ */
+struct cdc_gpioset_info {
+ char **gpiosets;
+ char **gpiosets_comb_names;
+ uint8_t *gpioset_state;
+ int gpiosets_max;
+ int gpiosets_comb_max;
+};
+
+static struct cdc_pinctrl_info pinctrl_info[MAX_PINCTRL_CLIENT];
+static struct cdc_gpioset_info gpioset_info[MAX_PINCTRL_CLIENT];
+
+/* Finds the index for the gpio set in the dtsi file */
+int msm_get_gpioset_index(enum pinctrl_client client, char *keyword)
+{
+ int i;
+
+ for (i = 0; i < gpioset_info[client].gpiosets_max; i++) {
+ if (!(strcmp(gpioset_info[client].gpiosets[i], keyword)))
+ break;
+ }
+ /* Checking if the keyword is present in dtsi or not */
+ if (i != gpioset_info[client].gpiosets_max)
+ return i;
+ else
+ return -EINVAL;
+}
+
+/*
+ * This function reads the following from dtsi file
+ * 1. All gpio sets
+ * 2. All combinations of gpio sets
+ * 3. Pinctrl handles to gpio sets
+ *
+ * Returns error if there is
+ * 1. Problem reading from dtsi file
+ * 2. Memory allocation failure
+ */
+int msm_gpioset_initialize(enum pinctrl_client client,
+ struct device *dev)
+{
+ struct pinctrl *pinctrl;
+ const char *gpioset_names = "qcom,msm-gpios";
+ const char *gpioset_combinations = "qcom,pinctrl-names";
+ const char *gpioset_names_str = NULL;
+ const char *gpioset_comb_str = NULL;
+ int num_strings = 0;
+ int ret = 0;
+ int i = 0;
+
+ pr_debug("%s\n", __func__);
+ pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pinctrl)) {
+ pr_err("%s: Unable to get pinctrl handle\n",
+ __func__);
+ return -EINVAL;
+ }
+ pinctrl_info[client].pinctrl = pinctrl;
+
+ /* Reading of gpio sets */
+ num_strings = of_property_count_strings(dev->of_node,
+ gpioset_names);
+ if (num_strings < 0) {
+ dev_err(dev,
+ "%s: missing %s in dt node or length is incorrect\n",
+ __func__, gpioset_names);
+ goto err;
+ }
+ gpioset_info[client].gpiosets_max = num_strings;
+ gpioset_info[client].gpiosets = devm_kzalloc(dev,
+ gpioset_info[client].gpiosets_max *
+ sizeof(char *), GFP_KERNEL);
+ if (!gpioset_info[client].gpiosets) {
+ dev_err(dev, "Can't allocate memory for gpio set names\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < num_strings; i++) {
+ ret = of_property_read_string_index(dev->of_node,
+ gpioset_names, i, &gpioset_names_str);
+
+ gpioset_info[client].gpiosets[i] = devm_kzalloc(dev,
+ (strlen(gpioset_names_str) + 1), GFP_KERNEL);
+
+ if (!gpioset_info[client].gpiosets[i]) {
+ dev_err(dev, "%s: Can't allocate gpiosets[%d] data\n",
+ __func__, i);
+ ret = -ENOMEM;
+ goto err;
+ }
+ strlcpy(gpioset_info[client].gpiosets[i],
+ gpioset_names_str, strlen(gpioset_names_str)+1);
+ gpioset_names_str = NULL;
+ }
+ num_strings = 0;
+
+ /* Allocating memory for gpio set counter */
+ gpioset_info[client].gpioset_state = devm_kzalloc(dev,
+ gpioset_info[client].gpiosets_max *
+ sizeof(uint8_t), GFP_KERNEL);
+ if (!gpioset_info[client].gpioset_state) {
+ dev_err(dev, "Can't allocate memory for gpio set counter\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Reading of all combinations of gpio sets */
+ num_strings = of_property_count_strings(dev->of_node,
+ gpioset_combinations);
+ if (num_strings < 0) {
+ dev_err(dev,
+ "%s: missing %s in dt node or length is incorrect\n",
+ __func__, gpioset_combinations);
+ goto err;
+ }
+ gpioset_info[client].gpiosets_comb_max = num_strings;
+ gpioset_info[client].gpiosets_comb_names = devm_kzalloc(dev,
+ num_strings * sizeof(char *), GFP_KERNEL);
+ if (!gpioset_info[client].gpiosets_comb_names) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) {
+ ret = of_property_read_string_index(dev->of_node,
+ gpioset_combinations, i, &gpioset_comb_str);
+
+ gpioset_info[client].gpiosets_comb_names[i] = devm_kzalloc(dev,
+ (strlen(gpioset_comb_str) + 1), GFP_KERNEL);
+ if (!gpioset_info[client].gpiosets_comb_names[i]) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ strlcpy(gpioset_info[client].gpiosets_comb_names[i],
+ gpioset_comb_str,
+ strlen(gpioset_comb_str)+1);
+ pr_debug("%s: GPIO configuration %s\n",
+ __func__,
+ gpioset_info[client].gpiosets_comb_names[i]);
+ gpioset_comb_str = NULL;
+ }
+
+ /* Allocating memory for handles to pinctrl states */
+ pinctrl_info[client].cdc_lines = devm_kzalloc(dev,
+ num_strings * sizeof(char *), GFP_KERNEL);
+ if (!pinctrl_info[client].cdc_lines) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Get pinctrl handles for gpio sets in dtsi file */
+ for (i = 0; i < num_strings; i++) {
+ pinctrl_info[client].cdc_lines[i] = pinctrl_lookup_state(
+ pinctrl,
+ (const char *)gpioset_info[client].
+ gpiosets_comb_names[i]);
+ if (IS_ERR(pinctrl_info[client].cdc_lines[i]))
+ pr_err("%s: Unable to get pinctrl handle for %s\n",
+ __func__, gpioset_info[client].
+ gpiosets_comb_names[i]);
+ }
+ goto success;
+
+err:
+ /* Free up memory allocated for gpio set combinations */
+ for (i = 0; i < gpioset_info[client].gpiosets_max; i++) {
+ if (gpioset_info[client].gpiosets[i] != NULL) {
+ devm_kfree(dev, gpioset_info[client].gpiosets[i]);
+ gpioset_info[client].gpiosets[i] = NULL;
+ }
+ }
+ if (gpioset_info[client].gpiosets != NULL) {
+ devm_kfree(dev, gpioset_info[client].gpiosets);
+ gpioset_info[client].gpiosets = NULL;
+ }
+
+ /* Free up memory allocated for gpio set combinations */
+ for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) {
+ if (gpioset_info[client].gpiosets_comb_names[i] != NULL) {
+ devm_kfree(dev,
+ gpioset_info[client].gpiosets_comb_names[i]);
+ gpioset_info[client].gpiosets_comb_names[i] = NULL;
+ }
+ }
+ if (gpioset_info[client].gpiosets_comb_names != NULL) {
+ devm_kfree(dev, gpioset_info[client].gpiosets_comb_names);
+ gpioset_info[client].gpiosets_comb_names = NULL;
+ }
+
+ /* Free up memory allocated for handles to pinctrl states */
+ if (pinctrl_info[client].cdc_lines != NULL) {
+ devm_kfree(dev, pinctrl_info[client].cdc_lines);
+ pinctrl_info[client].cdc_lines = NULL;
+ }
+
+ /* Free up memory allocated for counter of gpio sets */
+ if (gpioset_info[client].gpioset_state != NULL) {
+ devm_kfree(dev, gpioset_info[client].gpioset_state);
+ gpioset_info[client].gpioset_state = NULL;
+ }
+
+success:
+ return ret;
+}
+
+int msm_gpioset_activate(enum pinctrl_client client, char *keyword)
+{
+ int ret = 0;
+ int gp_set = 0;
+ int active_set = 0;
+
+ gp_set = msm_get_gpioset_index(client, keyword);
+ if (gp_set < 0) {
+ pr_err("%s: gpio set name does not exist\n",
+ __func__);
+ return gp_set;
+ }
+
+ if (!gpioset_info[client].gpioset_state[gp_set]) {
+ /*
+ * If pinctrl pointer is not valid,
+ * no need to proceed further
+ */
+ active_set = pinctrl_info[client].active_set;
+ if (IS_ERR(pinctrl_info[client].cdc_lines[active_set]))
+ return 0;
+
+ pinctrl_info[client].active_set |= (1 << gp_set);
+ active_set = pinctrl_info[client].active_set;
+ pr_debug("%s: pinctrl.active_set: %d\n", __func__, active_set);
+
+ /* Select the appropriate pinctrl state */
+ ret = pinctrl_select_state(pinctrl_info[client].pinctrl,
+ pinctrl_info[client].cdc_lines[active_set]);
+ }
+ gpioset_info[client].gpioset_state[gp_set]++;
+
+ return ret;
+}
+
+int msm_gpioset_suspend(enum pinctrl_client client, char *keyword)
+{
+ int ret = 0;
+ int gp_set = 0;
+ int active_set = 0;
+
+ gp_set = msm_get_gpioset_index(client, keyword);
+ if (gp_set < 0) {
+ pr_err("%s: gpio set name does not exist\n",
+ __func__);
+ return gp_set;
+ }
+
+ if (gpioset_info[client].gpioset_state[gp_set] == 1) {
+ pinctrl_info[client].active_set &= ~(1 << gp_set);
+ /*
+ * If pinctrl pointer is not valid,
+ * no need to proceed further
+ */
+ active_set = pinctrl_info[client].active_set;
+ if (IS_ERR(pinctrl_info[client].cdc_lines[active_set]))
+ return -EINVAL;
+
+ pr_debug("%s: pinctrl.active_set: %d\n", __func__,
+ pinctrl_info[client].active_set);
+ /* Select the appropriate pinctrl state */
+ ret = pinctrl_select_state(pinctrl_info[client].pinctrl,
+ pinctrl_info[client].cdc_lines[pinctrl_info[client].
+ active_set]);
+ }
+ if (!(gpioset_info[client].gpioset_state[gp_set])) {
+ pr_err("%s: Invalid call to de activate gpios: %d\n", __func__,
+ gpioset_info[client].gpioset_state[gp_set]);
+ return -EINVAL;
+ }
+
+ gpioset_info[client].gpioset_state[gp_set]--;
+
+ return ret;
+}
diff --git a/sound/soc/msm/msm-audio-pinctrl.h b/sound/soc/msm/msm-audio-pinctrl.h
new file mode 100644
index 0000000..ec7c6aa
--- /dev/null
+++ b/sound/soc/msm/msm-audio-pinctrl.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_AUDIO_PINCTRL_H
+#define __MSM_AUDIO_PINCTRL_H
+
+enum pinctrl_client {
+ CLIENT_WCD,
+ CLIENT_WSA_BONGO_1,
+ CLIENT_WSA_BONGO_2,
+ MAX_PINCTRL_CLIENT,
+};
+
+
+/* finds the index for the gpio set in the dtsi file */
+int msm_get_gpioset_index(enum pinctrl_client client, char *keyword);
+
+/*
+ * this function reads the following from dtsi file
+ * 1. all gpio sets
+ * 2. all combinations of gpio sets
+ * 3. pinctrl handles to gpio sets
+ *
+ * returns error if there is
+ * 1. problem reading from dtsi file
+ * 2. memory allocation failure
+ */
+int msm_gpioset_initialize(enum pinctrl_client client, struct device *dev);
+
+int msm_gpioset_activate(enum pinctrl_client client, char *keyword);
+
+int msm_gpioset_suspend(enum pinctrl_client client, char *keyword);
+
+#endif /* __MSM_AUDIO_PINCTRL_H */
diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c
new file mode 100644
index 0000000..1149c4a
--- /dev/null
+++ b/sound/soc/msm/msm-cpe-lsm.c
@@ -0,0 +1,3143 @@
+/*
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/kthread.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/freezer.h>
+#include <sound/soc.h>
+#include <sound/cpe_core.h>
+#include <sound/lsm_params.h>
+#include <sound/pcm_params.h>
+#include <sound/msm-slim-dma.h>
+
+#define SAMPLE_RATE_48KHZ 48000
+#define SAMPLE_RATE_16KHZ 16000
+#define LSM_VOICE_WAKEUP_APP_V2 2
+#define AFE_PORT_ID_1 1
+#define AFE_PORT_ID_3 3
+#define AFE_OUT_PORT_2 2
+#define LISTEN_MIN_NUM_PERIODS 2
+#define LISTEN_MAX_NUM_PERIODS 12
+#define LISTEN_MAX_PERIOD_SIZE 61440
+#define LISTEN_MIN_PERIOD_SIZE 320
+#define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256
+#define MSM_CPE_MAX_CUSTOM_PARAM_SIZE 2048
+
+#define MSM_CPE_LAB_THREAD_TIMEOUT (3 * (HZ/10))
+
+#define MSM_CPE_LSM_GRAB_LOCK(lock, name) \
+{ \
+ pr_debug("%s: %s lock acquire\n", \
+ __func__, name); \
+ mutex_lock(lock); \
+}
+
+#define MSM_CPE_LSM_REL_LOCK(lock, name) \
+{ \
+ pr_debug("%s: %s lock release\n", \
+ __func__, name); \
+ mutex_unlock(lock); \
+}
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 8000, 16000, 48000, 192000, 384000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+
+static struct snd_pcm_hardware msm_pcm_hardware_listen = {
+ .info = (SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .rates = (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000),
+ .rate_min = 16000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = LISTEN_MAX_NUM_PERIODS *
+ LISTEN_MAX_PERIOD_SIZE,
+ .period_bytes_min = LISTEN_MIN_PERIOD_SIZE,
+ .period_bytes_max = LISTEN_MAX_PERIOD_SIZE,
+ .periods_min = LISTEN_MIN_NUM_PERIODS,
+ .periods_max = LISTEN_MAX_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+enum {
+ AFE_CMD_INVALID = 0,
+ AFE_CMD_PORT_START,
+ AFE_CMD_PORT_SUSPEND,
+ AFE_CMD_PORT_RESUME,
+ AFE_CMD_PORT_STOP,
+};
+
+enum cpe_lab_thread_status {
+ MSM_LSM_LAB_THREAD_STOP,
+ MSM_LSM_LAB_THREAD_RUNNING,
+ MSM_LSM_LAB_THREAD_ERROR,
+};
+
+struct cpe_hw_params {
+ u32 sample_rate;
+ u16 sample_size;
+ u32 buf_sz;
+ u32 period_count;
+ u16 channels;
+};
+
+struct cpe_data_pcm_buf {
+ u8 *mem;
+ phys_addr_t phys;
+};
+
+struct cpe_lsm_lab {
+ atomic_t in_count;
+ atomic_t abort_read;
+ u32 dma_write;
+ u32 buf_idx;
+ u32 pcm_size;
+ enum cpe_lab_thread_status thread_status;
+ struct cpe_data_pcm_buf *pcm_buf;
+ wait_queue_head_t period_wait;
+ struct completion comp;
+ struct completion thread_complete;
+};
+
+struct cpe_priv {
+ void *core_handle;
+ struct snd_soc_codec *codec;
+ struct wcd_cpe_lsm_ops lsm_ops;
+ struct wcd_cpe_afe_ops afe_ops;
+ bool afe_mad_ctl;
+ u32 input_port_id;
+};
+
+struct cpe_lsm_data {
+ struct device *dev;
+ struct cpe_lsm_session *lsm_session;
+ struct mutex lsm_api_lock;
+ struct cpe_lsm_lab lab;
+ struct cpe_hw_params hw_params;
+ struct snd_pcm_substream *substream;
+
+ wait_queue_head_t event_wait;
+ atomic_t event_avail;
+ atomic_t event_stop;
+
+ u8 ev_det_status;
+ u8 ev_det_pld_size;
+ u8 *ev_det_payload;
+
+ bool cpe_prepared;
+};
+
+static int msm_cpe_afe_mad_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cpe_priv *cpe = kcontrol->private_data;
+
+ ucontrol->value.integer.value[0] = cpe->afe_mad_ctl;
+ return 0;
+}
+
+static int msm_cpe_afe_mad_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cpe_priv *cpe = kcontrol->private_data;
+
+ cpe->afe_mad_ctl = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static struct snd_kcontrol_new msm_cpe_kcontrols[] = {
+ SOC_SINGLE_EXT("CPE AFE MAD Enable", SND_SOC_NOPM, 0, 1, 0,
+ msm_cpe_afe_mad_ctl_get, msm_cpe_afe_mad_ctl_put),
+};
+
+/*
+ * cpe_get_private_data: obtain ASoC platform driver private data
+ * @substream: ASoC substream for which private data to be obtained
+ */
+static struct cpe_priv *cpe_get_private_data(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: %s is invalid\n",
+ __func__,
+ (!substream) ? "substream" : "private_data");
+ goto err_ret;
+ }
+
+ rtd = substream->private_data;
+
+ if (!rtd || !rtd->platform) {
+ pr_err("%s: %s is invalid\n",
+ __func__,
+ (!rtd) ? "runtime" : "platform");
+ goto err_ret;
+ }
+
+ return snd_soc_platform_get_drvdata(rtd->platform);
+
+err_ret:
+ return NULL;
+}
+
+/*
+ * cpe_get_lsm_data: obtain the lsm session data given the substream
+ * @substream: ASoC substream for which lsm session data to be obtained
+ */
+static struct cpe_lsm_data *cpe_get_lsm_data(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return runtime->private_data;
+}
+
+static void msm_cpe_process_event_status(void *data,
+ u8 detect_status, u8 size, u8 *payload)
+{
+ struct cpe_lsm_data *lsm_d = data;
+
+ lsm_d->ev_det_status = detect_status;
+ lsm_d->ev_det_pld_size = size;
+
+ lsm_d->ev_det_payload = kzalloc(size, GFP_KERNEL);
+ if (!lsm_d->ev_det_payload)
+ return;
+
+ memcpy(lsm_d->ev_det_payload, payload, size);
+
+ atomic_set(&lsm_d->event_avail, 1);
+ wake_up(&lsm_d->event_wait);
+}
+
+static void msm_cpe_process_event_status_done(struct cpe_lsm_data *lsm_data)
+{
+ kfree(lsm_data->ev_det_payload);
+ lsm_data->ev_det_payload = NULL;
+
+ lsm_data->ev_det_status = 0;
+ lsm_data->ev_det_pld_size = 0;
+}
+
+/*
+ * msm_cpe_afe_port_cntl: Perform the afe port control
+ * @substream: substream for which afe port command to be performed
+ * @core_handle: handle to core
+ * @afe_ops: handle to the afe operations
+ * @afe_cfg: afe port configuration data
+ * @cmd: command to be sent to AFE
+ *
+ */
+static int msm_cpe_afe_port_cntl(
+ struct snd_pcm_substream *substream,
+ void *core_handle,
+ struct wcd_cpe_afe_ops *afe_ops,
+ struct wcd_cpe_afe_port_cfg *afe_cfg,
+ int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int rc = 0;
+
+ if (!afe_cfg->port_id) {
+ /*
+ * It is possible driver can get closed without prepare,
+ * in which case afe ports will not be initialized.
+ */
+ dev_dbg(rtd->dev,
+ "%s: Invalid afe port id\n",
+ __func__);
+ return 0;
+ }
+
+ switch (cmd) {
+ case AFE_CMD_PORT_START:
+ rc = afe_ops->afe_port_start(core_handle, afe_cfg);
+ if (rc != 0)
+ dev_err(rtd->dev,
+ "%s: AFE port start failed\n",
+ __func__);
+ break;
+ case AFE_CMD_PORT_SUSPEND:
+ rc = afe_ops->afe_port_suspend(core_handle, afe_cfg);
+ if (rc != 0)
+ dev_err(rtd->dev,
+ "%s: afe_suspend failed, err = %d\n",
+ __func__, rc);
+ break;
+ case AFE_CMD_PORT_RESUME:
+ rc = afe_ops->afe_port_resume(core_handle, afe_cfg);
+ if (rc != 0)
+ dev_err(rtd->dev,
+ "%s: afe_resume failed, err = %d\n",
+ __func__, rc);
+ break;
+ case AFE_CMD_PORT_STOP:
+ rc = afe_ops->afe_port_stop(core_handle, afe_cfg);
+ if (rc != 0)
+ dev_err(rtd->dev,
+ "%s: afe_stopfailed, err = %d\n",
+ __func__, rc);
+ break;
+ }
+
+ return rc;
+}
+
+static int msm_cpe_lsm_lab_stop(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct cpe_priv *cpe = cpe_get_private_data(substream);
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ struct wcd_cpe_afe_ops *afe_ops;
+ struct cpe_lsm_session *session;
+ struct cpe_lsm_lab *lab_d = &lsm_d->lab;
+ struct msm_slim_dma_data *dma_data = NULL;
+ int rc;
+
+ /*
+ * the caller is not aware of LAB status and will
+ * try to stop lab even if it is already stopped.
+ * return success right away is LAB is already stopped
+ */
+ if (lab_d->thread_status == MSM_LSM_LAB_THREAD_STOP) {
+ dev_dbg(rtd->dev,
+ "%s: lab already stopped\n",
+ __func__);
+ return 0;
+ }
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ lsm_ops = &cpe->lsm_ops;
+ afe_ops = &cpe->afe_ops;
+ session = lsm_d->lsm_session;
+ if (rtd->cpu_dai)
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
+ substream);
+ if (!dma_data || !dma_data->dai_channel_ctl) {
+ dev_err(rtd->dev,
+ "%s: dma_data is not set\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (lab_d->thread_status == MSM_LSM_LAB_THREAD_RUNNING) {
+ dev_dbg(rtd->dev, "%s: stopping lab thread\n",
+ __func__);
+ rc = kthread_stop(session->lsm_lab_thread);
+
+ /*
+ * kthread_stop returns EINTR if the thread_fn
+ * was not scheduled before calling kthread_stop.
+ * In this case, we dont need to wait for lab
+ * thread to complete as lab thread will not be
+ * scheduled at all.
+ */
+ if (rc == -EINTR)
+ goto done;
+
+ /* Wait for the lab thread to exit */
+ rc = wait_for_completion_timeout(
+ &lab_d->thread_complete,
+ MSM_CPE_LAB_THREAD_TIMEOUT);
+ if (!rc) {
+ dev_err(rtd->dev,
+ "%s: Wait for lab thread timedout\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ rc = lsm_ops->lab_ch_setup(cpe->core_handle,
+ session,
+ WCD_CPE_PRE_DISABLE);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: PRE ch teardown failed, err = %d\n",
+ __func__, rc);
+ /* continue with teardown even if any intermediate step fails */
+ rc = dma_data->dai_channel_ctl(dma_data, rtd->cpu_dai, false);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: open data failed %d\n", __func__, rc);
+ dma_data->ph = 0;
+
+ /*
+ * Even though LAB stop failed,
+ * output AFE port needs to be stopped
+ */
+ rc = afe_ops->afe_port_stop(cpe->core_handle,
+ &session->afe_out_port_cfg);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: AFE out port stop failed, err = %d\n",
+ __func__, rc);
+
+ rc = lsm_ops->lab_ch_setup(cpe->core_handle,
+ session,
+ WCD_CPE_POST_DISABLE);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: POST ch teardown failed, err = %d\n",
+ __func__, rc);
+
+done:
+ lab_d->thread_status = MSM_LSM_LAB_THREAD_STOP;
+ lab_d->buf_idx = 0;
+ atomic_set(&lab_d->in_count, 0);
+ lab_d->dma_write = 0;
+
+ return 0;
+}
+
+static int msm_cpe_lab_buf_alloc(struct snd_pcm_substream *substream,
+ struct cpe_lsm_session *session,
+ struct msm_slim_dma_data *dma_data)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct cpe_lsm_lab *lab_d = &lsm_d->lab;
+ struct cpe_hw_params *hw_params = &lsm_d->hw_params;
+ struct cpe_data_pcm_buf *pcm_buf = NULL;
+ int rc = 0;
+ int dma_alloc = 0;
+ u32 count = 0;
+ u32 bufsz, bufcnt;
+
+ if (lab_d->pcm_buf &&
+ lab_d->pcm_buf->mem) {
+ dev_dbg(rtd->dev,
+ "%s: LAB buf already allocated\n",
+ __func__);
+ goto exit;
+ }
+
+ bufsz = hw_params->buf_sz;
+ bufcnt = hw_params->period_count;
+
+ dev_dbg(rtd->dev,
+ "%s:Buf Size %d Buf count %d\n",
+ __func__,
+ bufsz, bufcnt);
+
+ pcm_buf = kzalloc(((sizeof(struct cpe_data_pcm_buf)) * bufcnt),
+ GFP_KERNEL);
+ if (!pcm_buf) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ lab_d->pcm_buf = pcm_buf;
+ dma_alloc = bufsz * bufcnt;
+ pcm_buf->mem = NULL;
+ pcm_buf->mem = dma_alloc_coherent(dma_data->sdev->dev.parent,
+ dma_alloc,
+ &(pcm_buf->phys),
+ GFP_KERNEL);
+ if (!pcm_buf->mem) {
+ dev_err(rtd->dev,
+ "%s:DMA alloc failed size = %x\n",
+ __func__, dma_alloc);
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ count = 0;
+ while (count < bufcnt) {
+ pcm_buf[count].mem = pcm_buf[0].mem + (count * bufsz);
+ pcm_buf[count].phys = pcm_buf[0].phys + (count * bufsz);
+ dev_dbg(rtd->dev,
+ "%s: pcm_buf[%d].mem %pK pcm_buf[%d].phys %pK\n",
+ __func__, count,
+ (void *)pcm_buf[count].mem,
+ count, &(pcm_buf[count].phys));
+ count++;
+ }
+
+ return 0;
+fail:
+ if (pcm_buf) {
+ if (pcm_buf->mem)
+ dma_free_coherent(dma_data->sdev->dev.parent, dma_alloc,
+ pcm_buf->mem, pcm_buf->phys);
+ kfree(pcm_buf);
+ lab_d->pcm_buf = NULL;
+ }
+exit:
+ return rc;
+}
+
+static int msm_cpe_lab_buf_dealloc(struct snd_pcm_substream *substream,
+ struct cpe_lsm_session *session, struct msm_slim_dma_data *dma_data)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct cpe_lsm_lab *lab_d = &lsm_d->lab;
+ struct cpe_hw_params *hw_params = &lsm_d->hw_params;
+ int rc = 0;
+ int dma_alloc = 0;
+ struct cpe_data_pcm_buf *pcm_buf = NULL;
+ int bufsz, bufcnt;
+
+ bufsz = hw_params->buf_sz;
+ bufcnt = hw_params->period_count;
+
+ dev_dbg(rtd->dev,
+ "%s:Buf Size %d Buf count %d\n", __func__,
+ bufsz, bufcnt);
+
+ if (bufcnt <= 0 || bufsz <= 0) {
+ dev_err(rtd->dev,
+ "%s: Invalid params, bufsz = %u, bufcnt = %u\n",
+ __func__, bufsz, bufcnt);
+ return -EINVAL;
+ }
+
+ pcm_buf = lab_d->pcm_buf;
+ dma_alloc = bufsz * bufcnt;
+ if (dma_data && pcm_buf)
+ dma_free_coherent(dma_data->sdev->dev.parent, dma_alloc,
+ pcm_buf->mem, pcm_buf->phys);
+ kfree(pcm_buf);
+ lab_d->pcm_buf = NULL;
+ return rc;
+}
+
+/*
+ * msm_cpe_lab_thread: Initiated on KW detection
+ * @data: lab data
+ *
+ * Start lab thread and call CPE core API for SLIM
+ * read operations.
+ */
+static int msm_cpe_lab_thread(void *data)
+{
+ struct cpe_lsm_data *lsm_d = data;
+ struct cpe_lsm_session *session = lsm_d->lsm_session;
+ struct snd_pcm_substream *substream = lsm_d->substream;
+ struct cpe_lsm_lab *lab_d = &lsm_d->lab;
+ struct cpe_hw_params *hw_params = &lsm_d->hw_params;
+ struct cpe_priv *cpe = cpe_get_private_data(substream);
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ struct wcd_cpe_afe_ops *afe_ops;
+ struct cpe_data_pcm_buf *cur_buf, *next_buf;
+ struct msm_slim_dma_data *dma_data = NULL;
+ struct snd_soc_pcm_runtime *rtd = NULL;
+ bool wait_timedout = false;
+ int rc = 0;
+ u32 done_len = 0;
+ u32 buf_count = 0;
+ u32 prd_cnt;
+
+ allow_signal(SIGKILL);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ pr_debug("%s: Lab thread start\n", __func__);
+ init_completion(&lab_d->comp);
+
+ if (PCM_RUNTIME_CHECK(substream)) {
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (!cpe || !cpe->core_handle) {
+ pr_err("%s: Handle to %s is invalid\n",
+ __func__,
+ (!cpe) ? "cpe" : "core");
+ rc = -EINVAL;
+ goto done;
+ }
+
+ rtd = substream->private_data;
+ if (rtd->cpu_dai)
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
+ substream);
+ if (!dma_data || !dma_data->dai_channel_ctl) {
+ pr_err("%s: dma_data is not set\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ lsm_ops = &cpe->lsm_ops;
+ afe_ops = &cpe->afe_ops;
+
+ rc = lsm_ops->lab_ch_setup(cpe->core_handle,
+ session,
+ WCD_CPE_PRE_ENABLE);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: PRE ch setup failed, err = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ rc = dma_data->dai_channel_ctl(dma_data, rtd->cpu_dai, true);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: open data failed %d\n", __func__, rc);
+ goto done;
+ }
+
+ dev_dbg(rtd->dev, "%s: Established data channel\n",
+ __func__);
+
+ init_waitqueue_head(&lab_d->period_wait);
+ memset(lab_d->pcm_buf[0].mem, 0, lab_d->pcm_size);
+
+ rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
+ lab_d->pcm_buf[0].phys,
+ hw_params->buf_sz, &lab_d->comp);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: buf[0] slim_port_xfer failed, err = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
+ lab_d->pcm_buf[1].phys,
+ hw_params->buf_sz, &lab_d->comp);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: buf[0] slim_port_xfer failed, err = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ cur_buf = &lab_d->pcm_buf[0];
+ next_buf = &lab_d->pcm_buf[2];
+ prd_cnt = hw_params->period_count;
+ rc = lsm_ops->lab_ch_setup(cpe->core_handle,
+ session,
+ WCD_CPE_POST_ENABLE);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: POST ch setup failed, err = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ rc = afe_ops->afe_port_start(cpe->core_handle,
+ &session->afe_out_port_cfg);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: AFE out port start failed, err = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ while (!kthread_should_stop() &&
+ lab_d->thread_status != MSM_LSM_LAB_THREAD_ERROR) {
+
+ rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
+ next_buf->phys,
+ hw_params->buf_sz, &lab_d->comp);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: slim_port_xfer failed, err = %d\n",
+ __func__, rc);
+ lab_d->thread_status = MSM_LSM_LAB_THREAD_ERROR;
+ }
+
+ rc = wait_for_completion_timeout(&lab_d->comp, (2 * HZ/10));
+ if (!rc) {
+ dev_err(rtd->dev,
+ "%s: wait timedout for slim buffer\n",
+ __func__);
+ wait_timedout = true;
+ } else {
+ wait_timedout = false;
+ }
+
+ rc = slim_port_get_xfer_status(dma_data->sdev,
+ dma_data->ph,
+ &cur_buf->phys, &done_len);
+ if (rc ||
+ (!rc && wait_timedout)) {
+ dev_err(rtd->dev,
+ "%s: xfer_status failure, rc = %d, wait_timedout = %s\n",
+ __func__, rc,
+ (wait_timedout ? "true" : "false"));
+ lab_d->thread_status = MSM_LSM_LAB_THREAD_ERROR;
+ }
+
+ if (done_len ||
+ ((!done_len) &&
+ lab_d->thread_status == MSM_LSM_LAB_THREAD_ERROR)) {
+ atomic_inc(&lab_d->in_count);
+ lab_d->dma_write += snd_pcm_lib_period_bytes(substream);
+ snd_pcm_period_elapsed(substream);
+ wake_up(&lab_d->period_wait);
+ buf_count++;
+
+ cur_buf = &lab_d->pcm_buf[buf_count % prd_cnt];
+ next_buf = &lab_d->pcm_buf[(buf_count + 2) % prd_cnt];
+ dev_dbg(rtd->dev,
+ "%s: Cur buf.mem = %pK Next Buf.mem = %pK\n"
+ " buf count = 0x%x\n", __func__,
+ cur_buf->mem, next_buf->mem, buf_count);
+ } else {
+ dev_err(rtd->dev,
+ "%s: SB get status, invalid len = 0x%x\n",
+ __func__, done_len);
+ }
+ done_len = 0;
+ }
+
+done:
+ if (rc)
+ lab_d->thread_status = MSM_LSM_LAB_THREAD_ERROR;
+ pr_debug("%s: Exit lab_thread, exit_status=%d, thread_status=%d\n",
+ __func__, rc, lab_d->thread_status);
+ complete(&lab_d->thread_complete);
+
+ return 0;
+}
+
+/*
+ * msm_cpe_lsm_open: ASoC call to open the stream
+ * @substream: substream that is to be opened
+ *
+ * Create session data for lsm session and open the lsm session
+ * on CPE.
+ */
+static int msm_cpe_lsm_open(struct snd_pcm_substream *substream)
+{
+ struct cpe_lsm_data *lsm_d;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_priv *cpe = cpe_get_private_data(substream);
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ int rc = 0;
+
+ if (!cpe || !cpe->codec) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ runtime->hw = msm_pcm_hardware_listen;
+
+ rc = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (rc < 0) {
+ pr_err("snd_pcm_hw_constraint_list failed rc %d\n", rc);
+ return -EINVAL;
+ }
+
+ /* Ensure that buffer size is a multiple of period size */
+ rc = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (rc < 0) {
+ pr_err("%s: Unable to set pcm_param_periods, rc %d\n",
+ __func__, rc);
+ return -EINVAL;
+ }
+
+ rc = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ LISTEN_MIN_NUM_PERIODS * LISTEN_MIN_PERIOD_SIZE,
+ LISTEN_MAX_NUM_PERIODS * LISTEN_MAX_PERIOD_SIZE);
+ if (rc < 0) {
+ pr_err("%s: Unable to set pcm constraints, rc %d\n",
+ __func__, rc);
+ return -EINVAL;
+ }
+
+ cpe->core_handle = wcd_cpe_get_core_handle(cpe->codec);
+
+ if (!cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid handle to codec core\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ lsm_ops = &cpe->lsm_ops;
+ lsm_d = kzalloc(sizeof(struct cpe_lsm_data), GFP_KERNEL);
+ if (!lsm_d) {
+ dev_err(rtd->dev,
+ "%s: ENOMEM for lsm session, size = %zd\n",
+ __func__, sizeof(struct cpe_lsm_data));
+ rc = -ENOMEM;
+ goto fail_return;
+ }
+ mutex_init(&lsm_d->lsm_api_lock);
+
+ lsm_d->lsm_session = lsm_ops->lsm_alloc_session(cpe->core_handle,
+ lsm_d, msm_cpe_process_event_status);
+ if (!lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: session allocation failed",
+ __func__);
+ rc = -EINVAL;
+ goto fail_session_alloc;
+ }
+ /* Explicitly Assign the LAB thread to STOP state */
+ lsm_d->lab.thread_status = MSM_LSM_LAB_THREAD_STOP;
+ lsm_d->lsm_session->started = false;
+ lsm_d->substream = substream;
+ init_waitqueue_head(&lsm_d->lab.period_wait);
+ lsm_d->cpe_prepared = false;
+
+ dev_dbg(rtd->dev, "%s: allocated session with id = %d\n",
+ __func__, lsm_d->lsm_session->id);
+
+
+ rc = lsm_ops->lsm_open_tx(cpe->core_handle, lsm_d->lsm_session,
+ LSM_VOICE_WAKEUP_APP_V2, 16000);
+ if (rc < 0) {
+ dev_err(rtd->dev,
+ "%s: OPEN_TX cmd failed, err = %d\n",
+ __func__, rc);
+ goto fail_open_tx;
+ }
+
+ init_waitqueue_head(&lsm_d->event_wait);
+ atomic_set(&lsm_d->event_avail, 0);
+ atomic_set(&lsm_d->event_stop, 0);
+ runtime->private_data = lsm_d;
+
+ return 0;
+
+fail_open_tx:
+ lsm_ops->lsm_dealloc_session(cpe->core_handle, lsm_d->lsm_session);
+
+fail_session_alloc:
+ mutex_destroy(&lsm_d->lsm_api_lock);
+ kfree(lsm_d);
+fail_return:
+ return rc;
+}
+
+/*
+ * msm_cpe_lsm_close: ASoC call to close/cleanup the stream
+ * @substream: substream that is to be closed
+ *
+ * Deallocate the session and release the AFE port. It is not
+ * required to deregister the sound model as long as we close
+ * the lsm session on CPE.
+ */
+static int msm_cpe_lsm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct cpe_priv *cpe = cpe_get_private_data(substream);
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ struct cpe_lsm_session *session;
+ struct wcd_cpe_afe_ops *afe_ops;
+ struct wcd_cpe_afe_port_cfg *afe_cfg;
+ int rc = 0;
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ lsm_ops = &cpe->lsm_ops;
+ session = lsm_d->lsm_session;
+ afe_ops = &cpe->afe_ops;
+ afe_cfg = &(lsm_d->lsm_session->afe_port_cfg);
+
+ /*
+ * If driver is closed without stopping LAB,
+ * explicitly stop LAB before cleaning up the
+ * driver resources.
+ */
+ rc = msm_cpe_lsm_lab_stop(substream);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: Failed to stop lab, error = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = msm_cpe_afe_port_cntl(substream,
+ cpe->core_handle,
+ afe_ops, afe_cfg,
+ AFE_CMD_PORT_STOP);
+
+ lsm_d->cpe_prepared = false;
+
+ rc = lsm_ops->lsm_close_tx(cpe->core_handle, session);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: lsm_close fail, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ lsm_ops->lsm_dealloc_session(cpe->core_handle, session);
+ runtime->private_data = NULL;
+ mutex_destroy(&lsm_d->lsm_api_lock);
+ kfree(lsm_d);
+
+ return rc;
+}
+
+static int msm_cpe_lsm_get_conf_levels(
+ struct cpe_lsm_session *session,
+ u8 *conf_levels_ptr)
+{
+ int rc = 0;
+
+ if (session->num_confidence_levels <= 0) {
+ pr_debug("%s: conf_levels (%u), skip set params\n",
+ __func__,
+ session->num_confidence_levels);
+ goto done;
+ }
+
+ session->conf_levels = kzalloc(session->num_confidence_levels,
+ GFP_KERNEL);
+ if (!session->conf_levels) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ if (copy_from_user(session->conf_levels,
+ conf_levels_ptr,
+ session->num_confidence_levels)) {
+ pr_err("%s: copy_from_user failed for confidence levels %u\n",
+ __func__, session->num_confidence_levels);
+ kfree(session->conf_levels);
+ session->conf_levels = NULL;
+ rc = -EFAULT;
+ goto done;
+ }
+
+done:
+ return rc;
+}
+
+static int msm_cpe_lsm_validate_out_format(
+ struct snd_pcm_substream *substream,
+ struct snd_lsm_output_format_cfg *cfg)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int rc = 0;
+
+ if (!cfg) {
+ dev_err(rtd->dev,
+ "%s: Invalid lsm out cfg\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (cfg->format != LSM_OUT_FORMAT_PCM &&
+ cfg->format != LSM_OUT_FORMAT_ADPCM) {
+ dev_err(rtd->dev,
+ "%s: Invalid format %u\n",
+ __func__, cfg->format);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (cfg->packing != LSM_OUT_DATA_RAW &&
+ cfg->packing != LSM_OUT_DATA_PACKED) {
+ dev_err(rtd->dev,
+ "%s: Invalid packing method %u\n",
+ __func__, cfg->packing);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (cfg->events != LSM_OUT_DATA_EVENTS_DISABLED &&
+ cfg->events != LSM_OUT_DATA_EVENTS_ENABLED) {
+ dev_err(rtd->dev,
+ "%s: Invalid events provided %u\n",
+ __func__, cfg->events);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (cfg->mode != LSM_OUT_TRANSFER_MODE_RT &&
+ cfg->mode != LSM_OUT_TRANSFER_MODE_FTRT) {
+ dev_err(rtd->dev,
+ "%s: Invalid transfer mode %u\n",
+ __func__, cfg->mode);
+ rc = -EINVAL;
+ goto done;
+ }
+
+done:
+ return rc;
+}
+
+/*
+ * msm_cpe_lsm_ioctl_shared: Shared IOCTL for this platform driver
+ * @substream: ASoC substream for which the operation is invoked
+ * @cmd: command for the ioctl
+ * @arg: argument for the ioctl
+ *
+ * Perform dedicated listen functions like register sound model,
+ * deregister sound model, etc
+ * Called with lsm_api_lock acquired.
+ */
+static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_lsm_sound_model_v2 snd_model;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct cpe_priv *cpe = cpe_get_private_data(substream);
+ struct cpe_lsm_session *session;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ struct cpe_lsm_lab *lab_d = &lsm_d->lab;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct msm_slim_dma_data *dma_data = NULL;
+ struct snd_lsm_event_status *user;
+ struct snd_lsm_detection_params det_params;
+ int rc = 0;
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ switch (cmd) {
+ case SNDRV_LSM_STOP_LAB:
+ dev_dbg(rtd->dev,
+ "%s: %s, lab_enable = %d, lab_thread_ststus = %d\n",
+ __func__, "SNDRV_LSM_STOP_LAB",
+ session->lab_enable,
+ lab_d->thread_status);
+
+ if (session->lab_enable &&
+ lab_d->thread_status != MSM_LSM_LAB_THREAD_STOP) {
+ atomic_inc(&lab_d->abort_read);
+ wake_up(&lab_d->period_wait);
+ rc = msm_cpe_lsm_lab_stop(substream);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: stop LAB failed, error = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ } else if (!session->lab_enable) {
+ dev_dbg(rtd->dev,
+ "%s: LAB already stopped\n",
+ __func__);
+ }
+
+ break;
+
+ case SNDRV_LSM_LAB_CONTROL:
+ if (copy_from_user(&session->lab_enable, (void *)arg,
+ sizeof(u32))) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed, size %zd\n",
+ __func__, sizeof(u32));
+ return -EFAULT;
+ }
+
+ dev_dbg(rtd->dev,
+ "%s: %s, lab_enable = %d\n",
+ __func__, "SNDRV_LSM_LAB_CONTROL",
+ session->lab_enable);
+ if (rtd->cpu_dai)
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
+ substream);
+ if (!dma_data || !dma_data->dai_channel_ctl) {
+ dev_err(rtd->dev,
+ "%s: dma_data is not set\n", __func__);
+ return -EINVAL;
+ }
+
+ if (session->lab_enable) {
+ rc = msm_cpe_lab_buf_alloc(substream,
+ session, dma_data);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(rtd->dev,
+ "%s: lab buffer alloc failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = lab_d->pcm_buf[0].mem;
+ dma_buf->addr = lab_d->pcm_buf[0].phys;
+ dma_buf->bytes = (lsm_d->hw_params.buf_sz *
+ lsm_d->hw_params.period_count);
+ init_completion(&lab_d->thread_complete);
+ snd_pcm_set_runtime_buffer(substream,
+ &substream->dma_buffer);
+ rc = lsm_ops->lsm_lab_control(cpe->core_handle,
+ session, true);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(rtd->dev,
+ "%s: Lab Enable Failed rc %d\n",
+ __func__, rc);
+ return rc;
+ }
+ } else {
+ /*
+ * It is possible that lab is still enabled
+ * when trying to de-allocate the lab buffer.
+ * Make sure to disable lab before de-allocating
+ * the lab buffer.
+ */
+ rc = msm_cpe_lsm_lab_stop(substream);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(rtd->dev,
+ "%s: LAB stop failed, error = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ /*
+ * Buffer has to be de-allocated even if
+ * lab_control failed.
+ */
+ rc = msm_cpe_lab_buf_dealloc(substream,
+ session, dma_data);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(rtd->dev,
+ "%s: lab buffer free failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+ break;
+ case SNDRV_LSM_REG_SND_MODEL_V2:
+ dev_dbg(rtd->dev,
+ "%s: %s\n",
+ __func__, "SNDRV_LSM_REG_SND_MODEL_V2");
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: Invalid argument to ioctl %s\n",
+ __func__,
+ "SNDRV_LSM_REG_SND_MODEL_V2");
+ return -EINVAL;
+ }
+
+ memcpy(&snd_model, arg,
+ sizeof(struct snd_lsm_sound_model_v2));
+
+ session->num_confidence_levels =
+ snd_model.num_confidence_levels;
+ rc = msm_cpe_lsm_get_conf_levels(session,
+ snd_model.confidence_level);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: %s get_conf_levels fail, err = %d\n",
+ __func__, "SNDRV_LSM_REG_SND_MODEL_V2",
+ rc);
+ break;
+ }
+
+ session->snd_model_data = kzalloc(snd_model.data_size,
+ GFP_KERNEL);
+ if (!session->snd_model_data) {
+ kfree(session->conf_levels);
+ session->conf_levels = NULL;
+ return -ENOMEM;
+ }
+ session->snd_model_size = snd_model.data_size;
+
+ if (copy_from_user(session->snd_model_data,
+ snd_model.data, snd_model.data_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed for snd_model\n",
+ __func__);
+ kfree(session->conf_levels);
+ kfree(session->snd_model_data);
+ session->conf_levels = NULL;
+ session->snd_model_data = NULL;
+ return -EFAULT;
+ }
+
+ rc = lsm_ops->lsm_shmem_alloc(cpe->core_handle, session,
+ session->snd_model_size);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: shared memory allocation failed, err = %d\n",
+ __func__, rc);
+ kfree(session->snd_model_data);
+ kfree(session->conf_levels);
+ session->snd_model_data = NULL;
+ session->conf_levels = NULL;
+ return rc;
+ }
+
+ rc = lsm_ops->lsm_register_snd_model(cpe->core_handle, session,
+ snd_model.detection_mode,
+ snd_model.detect_failure);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: snd_model_reg failed, err = %d\n",
+ __func__, rc);
+ lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
+ kfree(session->snd_model_data);
+ kfree(session->conf_levels);
+ session->snd_model_data = NULL;
+ session->conf_levels = NULL;
+ return rc;
+ }
+
+ break;
+
+ case SNDRV_LSM_DEREG_SND_MODEL:
+ dev_dbg(rtd->dev,
+ "%s: %s\n",
+ __func__, "SNDRV_LSM_DEREG_SND_MODEL");
+
+ if (session->lab_enable) {
+ /*
+ * It is possible that lab is still enabled
+ * when trying to deregister sound model.
+ * Make sure to disable lab before de-allocating
+ * the lab buffer.
+ */
+ rc = msm_cpe_lsm_lab_stop(substream);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: LAB stop failed, error = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = lsm_ops->lsm_lab_control(cpe->core_handle,
+ session, false);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Lab Disable Failed rc %d\n",
+ __func__, rc);
+
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
+ substream);
+ if (!dma_data || !dma_data->dai_channel_ctl)
+ dev_err(rtd->dev,
+ "%s: dma_data is not set\n", __func__);
+
+ /*
+ * Buffer has to be de-allocated even if
+ * lab_control failed and/or dma data is invalid.
+ */
+ rc = msm_cpe_lab_buf_dealloc(substream,
+ session, dma_data);
+ if (IS_ERR_VALUE(rc))
+ dev_err(rtd->dev,
+ "%s: lab buffer free failed, err = %d\n",
+ __func__, rc);
+ }
+
+ rc = lsm_ops->lsm_deregister_snd_model(
+ cpe->core_handle, session);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: snd_model de-reg failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ kfree(session->snd_model_data);
+ kfree(session->conf_levels);
+ session->snd_model_data = NULL;
+ session->conf_levels = NULL;
+
+ rc = lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: LSM shared memory dealloc failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ break;
+
+ case SNDRV_LSM_EVENT_STATUS:
+ dev_dbg(rtd->dev,
+ "%s: %s\n",
+ __func__, "SNDRV_LSM_EVENT_STATUS");
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: Invalid argument to ioctl %s\n",
+ __func__,
+ "SNDRV_LSM_EVENT_STATUS");
+ return -EINVAL;
+ }
+
+ user = arg;
+
+ /*
+ * Release the api lock before wait to allow
+ * other IOCTLs to be invoked while waiting
+ * for event
+ */
+ MSM_CPE_LSM_REL_LOCK(&lsm_d->lsm_api_lock,
+ "lsm_api_lock");
+
+ rc = wait_event_freezable(lsm_d->event_wait,
+ (atomic_read(&lsm_d->event_avail) == 1) ||
+ (atomic_read(&lsm_d->event_stop) == 1));
+
+ MSM_CPE_LSM_GRAB_LOCK(&lsm_d->lsm_api_lock,
+ "lsm_api_lock");
+
+ if (!rc) {
+ if (atomic_read(&lsm_d->event_avail) == 1) {
+ rc = 0;
+ atomic_set(&lsm_d->event_avail, 0);
+ if (lsm_d->ev_det_pld_size >
+ user->payload_size) {
+ dev_err(rtd->dev,
+ "%s: avail pld_bytes = %u, needed = %u\n",
+ __func__,
+ user->payload_size,
+ lsm_d->ev_det_pld_size);
+ return -EINVAL;
+ }
+
+ user->status = lsm_d->ev_det_status;
+ user->payload_size = lsm_d->ev_det_pld_size;
+
+ memcpy(user->payload,
+ lsm_d->ev_det_payload,
+ lsm_d->ev_det_pld_size);
+
+ } else if (atomic_read(&lsm_d->event_stop) == 1) {
+ dev_dbg(rtd->dev,
+ "%s: wait_aborted\n", __func__);
+ user->payload_size = 0;
+ rc = 0;
+ }
+ }
+
+ break;
+
+ case SNDRV_LSM_ABORT_EVENT:
+ dev_dbg(rtd->dev,
+ "%s: %s\n",
+ __func__, "SNDRV_LSM_ABORT_EVENT");
+ atomic_set(&lsm_d->event_stop, 1);
+ wake_up(&lsm_d->event_wait);
+ break;
+
+ case SNDRV_LSM_START:
+ dev_dbg(rtd->dev,
+ "%s: %s\n",
+ __func__, "SNDRV_LSM_START");
+ rc = lsm_ops->lsm_start(cpe->core_handle, session);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: lsm_start fail, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ session->started = true;
+ break;
+
+ case SNDRV_LSM_STOP:
+ dev_dbg(rtd->dev,
+ "%s: %s, lab_enable = %d, lab_thread_status = %d\n",
+ __func__, "SNDRV_LSM_STOP",
+ session->lab_enable,
+ lab_d->thread_status);
+ if ((session->lab_enable &&
+ lab_d->thread_status ==
+ MSM_LSM_LAB_THREAD_RUNNING)) {
+ /* Explicitly stop LAB */
+ rc = msm_cpe_lsm_lab_stop(substream);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: lab_stop failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ rc = lsm_ops->lsm_stop(cpe->core_handle, session);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: lsm_stop fail err = %d\n",
+ __func__, rc);
+
+ return rc;
+ }
+ session->started = false;
+ break;
+
+ case SNDRV_LSM_SET_PARAMS:
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: %s Invalid argument\n",
+ __func__, "SNDRV_LSM_SET_PARAMS");
+ return -EINVAL;
+ }
+ memcpy(&det_params, arg,
+ sizeof(det_params));
+ if (det_params.num_confidence_levels <= 0) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid confidence levels %u\n",
+ __func__, "SNDRV_LSM_SET_PARAMS",
+ det_params.num_confidence_levels);
+ return -EINVAL;
+ }
+
+ session->num_confidence_levels =
+ det_params.num_confidence_levels;
+ rc = msm_cpe_lsm_get_conf_levels(session,
+ det_params.conf_level);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: %s get_conf_levels fail, err = %d\n",
+ __func__, "SNDRV_LSM_SET_PARAMS",
+ rc);
+ break;
+ }
+
+ rc = lsm_ops->lsm_set_data(cpe->core_handle, session,
+ det_params.detect_mode,
+ det_params.detect_failure);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: lsm_set_data failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ kfree(session->conf_levels);
+ session->conf_levels = NULL;
+
+ break;
+
+ case SNDRV_LSM_OUT_FORMAT_CFG: {
+ struct snd_lsm_output_format_cfg u_fmt_cfg;
+
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: Invalid argument to ioctl %s\n",
+ __func__, "SNDRV_LSM_OUT_FORMAT_CFG");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&u_fmt_cfg, arg,
+ sizeof(u_fmt_cfg))) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed for out_fmt_cfg\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (msm_cpe_lsm_validate_out_format(substream,
+ &u_fmt_cfg))
+ return -EINVAL;
+
+ session->out_fmt_cfg.format = u_fmt_cfg.format;
+ session->out_fmt_cfg.pack_mode = u_fmt_cfg.packing;
+ session->out_fmt_cfg.data_path_events =
+ u_fmt_cfg.events;
+ session->out_fmt_cfg.transfer_mode = u_fmt_cfg.mode;
+
+ rc = lsm_ops->lsm_set_fmt_cfg(cpe->core_handle,
+ session);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: lsm_set_fmt_cfg failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+ break;
+
+ default:
+ dev_dbg(rtd->dev,
+ "%s: Default snd_lib_ioctl cmd 0x%x\n",
+ __func__, cmd);
+ rc = snd_pcm_lib_ioctl(substream, cmd, arg);
+ }
+
+ return rc;
+}
+
+static int msm_cpe_lsm_lab_start(struct snd_pcm_substream *substream,
+ struct snd_lsm_event_status *event_status)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct cpe_lsm_lab *lab_d = NULL;
+ struct cpe_hw_params *hw_params;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ struct wcd_cpe_afe_ops *afe_ops;
+ struct wcd_cpe_afe_port_cfg *out_port;
+ int rc;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: invalid substream (%pK)\n",
+ __func__, substream);
+ return -EINVAL;
+ }
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+ lab_d = &lsm_d->lab;
+ afe_ops = &cpe->afe_ops;
+ hw_params = &lsm_d->hw_params;
+
+ if (!session->started) {
+ dev_dbg(rtd->dev,
+ "%s: Session is stopped, cannot start LAB\n",
+ __func__);
+ return 0;
+ }
+
+ reinit_completion(&lab_d->thread_complete);
+
+ if (session->lab_enable &&
+ event_status->status ==
+ LSM_VOICE_WAKEUP_STATUS_DETECTED) {
+ out_port = &session->afe_out_port_cfg;
+ out_port->port_id = session->afe_out_port_id;
+ out_port->bit_width = hw_params->sample_size;
+ out_port->num_channels = hw_params->channels;
+ out_port->sample_rate = hw_params->sample_rate;
+ dev_dbg(rtd->dev, "%s: port_id= %u, bit_width= %u, rate= %u\n",
+ __func__, out_port->port_id, out_port->bit_width,
+ out_port->sample_rate);
+
+ rc = afe_ops->afe_port_cmd_cfg(cpe->core_handle,
+ out_port);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: Failed afe generic config v2, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ atomic_set(&lab_d->abort_read, 0);
+ dev_dbg(rtd->dev,
+ "%s: KW detected, scheduling LAB thread\n",
+ __func__);
+
+ /*
+ * Even though thread might be only scheduled and
+ * not currently running, mark the internal driver
+ * status to running so driver can cancel this thread
+ * if it needs to before the thread gets chance to run.
+ */
+ lab_d->thread_status = MSM_LSM_LAB_THREAD_RUNNING;
+ session->lsm_lab_thread = kthread_run(
+ msm_cpe_lab_thread,
+ lsm_d,
+ "lab_thread");
+ }
+
+ return 0;
+}
+
+static bool msm_cpe_lsm_is_valid_stream(struct snd_pcm_substream *substream,
+ const char *func)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: invalid substream (%pK)\n",
+ func, substream);
+ return false;
+ }
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ func);
+ return false;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ func);
+ return false;
+ }
+
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ if (!lsm_ops) {
+ dev_err(rtd->dev,
+ "%s: Invalid lsm_ops\n", func);
+ return false;
+ }
+
+ return true;
+}
+
+static int msm_cpe_lsm_set_epd(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ struct snd_lsm_ep_det_thres epd_thres;
+ int rc;
+
+ if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
+ return -EINVAL;
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ if (p_info->param_size != sizeof(epd_thres)) {
+ dev_err(rtd->dev,
+ "%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(&epd_thres, p_info->param_data,
+ p_info->param_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed, size = %d\n",
+ __func__, p_info->param_size);
+ rc = -EFAULT;
+ goto done;
+ }
+
+ rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
+ session, p_info, &epd_thres,
+ LSM_ENDPOINT_DETECT_THRESHOLD);
+ if (unlikely(rc))
+ dev_err(rtd->dev,
+ "%s: set_one_param(epd_threshold) failed, rc %d\n",
+ __func__, rc);
+done:
+ return rc;
+}
+
+static int msm_cpe_lsm_set_mode(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ struct snd_lsm_detect_mode det_mode;
+ int rc;
+
+ if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
+ return -EINVAL;
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ if (p_info->param_size != sizeof(det_mode)) {
+ dev_err(rtd->dev,
+ "%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(&det_mode, p_info->param_data,
+ p_info->param_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed, size = %d\n",
+ __func__, p_info->param_size);
+ rc = -EFAULT;
+ goto done;
+ }
+
+ rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
+ session, p_info, &det_mode,
+ LSM_OPERATION_MODE);
+ if (unlikely(rc))
+ dev_err(rtd->dev,
+ "%s: set_one_param(epd_threshold) failed, rc %d\n",
+ __func__, rc);
+done:
+ return rc;
+}
+
+static int msm_cpe_lsm_set_gain(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ struct snd_lsm_gain gain;
+ int rc;
+
+ if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
+ return -EINVAL;
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ if (p_info->param_size != sizeof(gain)) {
+ dev_err(rtd->dev,
+ "%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(&gain, p_info->param_data,
+ p_info->param_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed, size = %d\n",
+ __func__, p_info->param_size);
+ rc = -EFAULT;
+ goto done;
+ }
+
+ rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
+ session, p_info, &gain,
+ LSM_GAIN);
+ if (unlikely(rc))
+ dev_err(rtd->dev,
+ "%s: set_one_param(epd_threshold) failed, rc %d\n",
+ __func__, rc);
+done:
+ return rc;
+
+}
+
+static int msm_cpe_lsm_set_conf(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ int rc;
+
+ if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
+ return -EINVAL;
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ session->num_confidence_levels =
+ p_info->param_size;
+ rc = msm_cpe_lsm_get_conf_levels(session,
+ p_info->param_data);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: get_conf_levels failed, err = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
+ session, p_info, NULL,
+ LSM_MIN_CONFIDENCE_LEVELS);
+ if (unlikely(rc))
+ dev_err(rtd->dev,
+ "%s: set_one_param(conf_levels) failed, rc %d\n",
+ __func__, rc);
+done:
+ return rc;
+}
+
+static int msm_cpe_lsm_reg_model(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ int rc;
+ size_t offset;
+ u8 *snd_model_ptr;
+
+ if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
+ return -EINVAL;
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ lsm_ops->lsm_get_snd_model_offset(cpe->core_handle,
+ session, &offset);
+ session->snd_model_size = p_info->param_size + offset;
+
+ session->snd_model_data = vzalloc(session->snd_model_size);
+ if (!session->snd_model_data)
+ return -ENOMEM;
+
+ snd_model_ptr = ((u8 *) session->snd_model_data) + offset;
+
+ if (copy_from_user(snd_model_ptr,
+ p_info->param_data, p_info->param_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user for snd_model failed\n",
+ __func__);
+ rc = -EFAULT;
+ goto free_snd_model_data;
+ }
+
+ rc = lsm_ops->lsm_shmem_alloc(cpe->core_handle, session,
+ session->snd_model_size);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: shared memory allocation failed, err = %d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ goto free_snd_model_data;
+ }
+
+ rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
+ session, p_info, NULL,
+ LSM_REG_SND_MODEL);
+ if (unlikely(rc)) {
+ dev_err(rtd->dev,
+ "%s: set_one_param(snd_model) failed, rc %d\n",
+ __func__, rc);
+ goto dealloc_shmem;
+ }
+ return 0;
+
+dealloc_shmem:
+ lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
+
+free_snd_model_data:
+ vfree(session->snd_model_data);
+ return rc;
+}
+
+static int msm_cpe_lsm_dereg_model(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ int rc;
+
+ if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
+ return -EINVAL;
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
+ session, p_info, NULL,
+ LSM_DEREG_SND_MODEL);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: dereg_snd_model failed\n",
+ __func__);
+ return lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
+}
+
+static int msm_cpe_lsm_set_custom(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+ u8 *data;
+ int rc;
+
+ if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
+ return -EINVAL;
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ if (p_info->param_size > MSM_CPE_MAX_CUSTOM_PARAM_SIZE) {
+ dev_err(rtd->dev,
+ "%s: invalid size %d, max allowed %d\n",
+ __func__, p_info->param_size,
+ MSM_CPE_MAX_CUSTOM_PARAM_SIZE);
+ return -EINVAL;
+ }
+
+ data = kzalloc(p_info->param_size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (copy_from_user(data, p_info->param_data,
+ p_info->param_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed for custom params, size = %d\n",
+ __func__, p_info->param_size);
+ rc = -EFAULT;
+ goto err_ret;
+ }
+
+ rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
+ session, p_info, data,
+ LSM_CUSTOM_PARAMS);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: custom_params failed, err = %d\n",
+ __func__, rc);
+err_ret:
+ kfree(data);
+ return rc;
+}
+
+static int msm_cpe_lsm_process_params(struct snd_pcm_substream *substream,
+ struct snd_lsm_module_params *p_data,
+ void *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct lsm_params_info *p_info;
+ int i;
+ int rc = 0;
+
+ p_info = (struct lsm_params_info *) params;
+
+ for (i = 0; i < p_data->num_params; i++) {
+ dev_dbg(rtd->dev,
+ "%s: param (%d), module_id = 0x%x, param_id = 0x%x, param_size = 0x%x, param_type = 0x%x\n",
+ __func__, i, p_info->module_id,
+ p_info->param_id, p_info->param_size,
+ p_info->param_type);
+
+ switch (p_info->param_type) {
+ case LSM_ENDPOINT_DETECT_THRESHOLD:
+ rc = msm_cpe_lsm_set_epd(substream, p_info);
+ break;
+ case LSM_OPERATION_MODE:
+ rc = msm_cpe_lsm_set_mode(substream, p_info);
+ break;
+ case LSM_GAIN:
+ rc = msm_cpe_lsm_set_gain(substream, p_info);
+ break;
+ case LSM_MIN_CONFIDENCE_LEVELS:
+ rc = msm_cpe_lsm_set_conf(substream, p_info);
+ break;
+ case LSM_REG_SND_MODEL:
+ rc = msm_cpe_lsm_reg_model(substream, p_info);
+ break;
+ case LSM_DEREG_SND_MODEL:
+ rc = msm_cpe_lsm_dereg_model(substream, p_info);
+ break;
+ case LSM_CUSTOM_PARAMS:
+ rc = msm_cpe_lsm_set_custom(substream, p_info);
+ break;
+ default:
+ dev_err(rtd->dev,
+ "%s: Invalid param_type %d\n",
+ __func__, p_info->param_type);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ pr_err("%s: set_param fail for param_type %d\n",
+ __func__, p_info->param_type);
+ return rc;
+ }
+
+ p_info++;
+ }
+
+ return rc;
+}
+
+static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ int err = 0;
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: invalid substream (%pK)\n",
+ __func__, substream);
+ return -EINVAL;
+ }
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ MSM_CPE_LSM_GRAB_LOCK(&lsm_d->lsm_api_lock,
+ "lsm_api_lock");
+
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ switch (cmd) {
+ case SNDRV_LSM_REG_SND_MODEL_V2: {
+ struct snd_lsm_sound_model_v2 snd_model;
+
+ if (session->is_topology_used) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if using topology\n",
+ __func__, "LSM_REG_SND_MODEL_V2");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&snd_model, (void *)arg,
+ sizeof(struct snd_lsm_sound_model_v2))) {
+ dev_err(rtd->dev,
+ "%s: copy from user failed, size %zd\n",
+ __func__,
+ sizeof(struct snd_lsm_sound_model_v2));
+ err = -EFAULT;
+ goto done;
+ }
+
+ err = msm_cpe_lsm_ioctl_shared(substream, cmd,
+ &snd_model);
+ }
+ break;
+ case SNDRV_LSM_EVENT_STATUS: {
+ struct snd_lsm_event_status u_event_status;
+ struct snd_lsm_event_status *event_status = NULL;
+ int u_pld_size = 0;
+
+ if (copy_from_user(&u_event_status, (void *)arg,
+ sizeof(struct snd_lsm_event_status))) {
+ dev_err(rtd->dev,
+ "%s: event status copy from user failed, size %zd\n",
+ __func__,
+ sizeof(struct snd_lsm_event_status));
+ err = -EFAULT;
+ goto done;
+ }
+
+ if (u_event_status.payload_size >
+ LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
+ dev_err(rtd->dev,
+ "%s: payload_size %d is invalid, max allowed = %d\n",
+ __func__, u_event_status.payload_size,
+ LISTEN_MAX_STATUS_PAYLOAD_SIZE);
+ err = -EINVAL;
+ goto done;
+ }
+
+ u_pld_size = sizeof(struct snd_lsm_event_status) +
+ u_event_status.payload_size;
+
+ event_status = kzalloc(u_pld_size, GFP_KERNEL);
+ if (!event_status) {
+ err = -ENOMEM;
+ goto done;
+ } else {
+ event_status->payload_size =
+ u_event_status.payload_size;
+ err = msm_cpe_lsm_ioctl_shared(substream,
+ cmd, event_status);
+ }
+
+ if (!err && copy_to_user(arg, event_status, u_pld_size)) {
+ dev_err(rtd->dev,
+ "%s: copy to user failed\n",
+ __func__);
+ kfree(event_status);
+ err = -EFAULT;
+ goto done;
+ }
+
+ msm_cpe_lsm_lab_start(substream, event_status);
+ msm_cpe_process_event_status_done(lsm_d);
+ kfree(event_status);
+ }
+ break;
+ case SNDRV_LSM_SET_PARAMS: {
+ struct snd_lsm_detection_params det_params;
+
+ if (session->is_topology_used) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if using topology\n",
+ __func__, "SNDRV_LSM_SET_PARAMS");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&det_params, (void *) arg,
+ sizeof(det_params))) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %zd\n",
+ __func__, "SNDRV_LSM_SET_PARAMS",
+ sizeof(det_params));
+ err = -EFAULT;
+ goto done;
+ }
+
+ err = msm_cpe_lsm_ioctl_shared(substream, cmd,
+ &det_params);
+ }
+ break;
+
+ case SNDRV_LSM_SET_MODULE_PARAMS: {
+ struct snd_lsm_module_params p_data;
+ size_t p_size;
+ u8 *params;
+
+ if (!session->is_topology_used) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if not using topology\n",
+ __func__, "SET_MODULE_PARAMS");
+ return -EINVAL;
+ }
+
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: %s: No Param data to set\n",
+ __func__, "SET_MODULE_PARAMS");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&p_data, arg,
+ sizeof(p_data))) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %zd\n",
+ __func__, "p_data", sizeof(p_data));
+ return -EFAULT;
+ }
+
+ if (p_data.num_params > LSM_PARAMS_MAX) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid num_params %d\n",
+ __func__, "SET_MODULE_PARAMS",
+ p_data.num_params);
+ return -EINVAL;
+ }
+
+ p_size = p_data.num_params *
+ sizeof(struct lsm_params_info);
+
+ if (p_data.data_size != p_size) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid size %zd\n",
+ __func__, "SET_MODULE_PARAMS", p_size);
+
+ return -EFAULT;
+ }
+
+ params = kzalloc(p_size, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ if (copy_from_user(params, p_data.params,
+ p_data.data_size)) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %d\n",
+ __func__, "params", p_data.data_size);
+ kfree(params);
+ return -EFAULT;
+ }
+
+ err = msm_cpe_lsm_process_params(substream, &p_data, params);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: %s: Failed to set params, err = %d\n",
+ __func__, "SET_MODULE_PARAMS", err);
+ kfree(params);
+ break;
+ }
+ default:
+ err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg);
+ break;
+ }
+
+done:
+ MSM_CPE_LSM_REL_LOCK(&lsm_d->lsm_api_lock,
+ "lsm_api_lock");
+ return err;
+}
+
+#ifdef CONFIG_COMPAT
+struct snd_lsm_event_status32 {
+ u16 status;
+ u16 payload_size;
+ u8 payload[0];
+};
+
+struct snd_lsm_sound_model_v2_32 {
+ compat_uptr_t data;
+ compat_uptr_t confidence_level;
+ u32 data_size;
+ enum lsm_detection_mode detection_mode;
+ u8 num_confidence_levels;
+ bool detect_failure;
+};
+
+struct snd_lsm_detection_params_32 {
+ compat_uptr_t conf_level;
+ enum lsm_detection_mode detect_mode;
+ u8 num_confidence_levels;
+ bool detect_failure;
+};
+
+struct lsm_params_info_32 {
+ u32 module_id;
+ u32 param_id;
+ u32 param_size;
+ compat_uptr_t param_data;
+ enum LSM_PARAM_TYPE param_type;
+};
+
+struct snd_lsm_module_params_32 {
+ compat_uptr_t params;
+ u32 num_params;
+ u32 data_size;
+};
+
+enum {
+ SNDRV_LSM_EVENT_STATUS32 =
+ _IOW('U', 0x02, struct snd_lsm_event_status32),
+ SNDRV_LSM_REG_SND_MODEL_V2_32 =
+ _IOW('U', 0x07, struct snd_lsm_sound_model_v2_32),
+ SNDRV_LSM_SET_PARAMS32 =
+ _IOW('U', 0x0A, struct snd_lsm_detection_params_32),
+ SNDRV_LSM_SET_MODULE_PARAMS_32 =
+ _IOW('U', 0x0B, struct snd_lsm_module_params_32),
+};
+
+static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ int err = 0;
+ struct snd_soc_pcm_runtime *rtd;
+ struct cpe_priv *cpe = NULL;
+ struct cpe_lsm_data *lsm_d = NULL;
+ struct cpe_lsm_session *session = NULL;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: invalid substream (%pK)\n",
+ __func__, substream);
+ return -EINVAL;
+ }
+
+ rtd = substream->private_data;
+ lsm_d = cpe_get_lsm_data(substream);
+ cpe = cpe_get_private_data(substream);
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ MSM_CPE_LSM_GRAB_LOCK(&lsm_d->lsm_api_lock,
+ "lsm_api_lock");
+
+ session = lsm_d->lsm_session;
+ lsm_ops = &cpe->lsm_ops;
+
+ switch (cmd) {
+ case SNDRV_LSM_REG_SND_MODEL_V2_32: {
+ struct snd_lsm_sound_model_v2 snd_model;
+ struct snd_lsm_sound_model_v2_32 snd_model32;
+
+ if (session->is_topology_used) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if using topology\n",
+ __func__, "LSM_REG_SND_MODEL_V2_32");
+ return -EINVAL;
+ }
+
+ dev_dbg(rtd->dev,
+ "%s: ioctl %s\n", __func__,
+ "SNDRV_LSM_REG_SND_MODEL_V2_32");
+
+ if (copy_from_user(&snd_model32, (void *)arg,
+ sizeof(snd_model32))) {
+ dev_err(rtd->dev,
+ "%s: copy from user failed, size %zd\n",
+ __func__,
+ sizeof(snd_model32));
+ err = -EFAULT;
+ goto done;
+ }
+
+ snd_model.data = compat_ptr(snd_model32.data);
+ snd_model.confidence_level =
+ compat_ptr(snd_model32.confidence_level);
+ snd_model.data_size = snd_model32.data_size;
+ snd_model.detect_failure = snd_model32.detect_failure;
+ snd_model.num_confidence_levels =
+ snd_model32.num_confidence_levels;
+ snd_model.detection_mode = snd_model32.detection_mode;
+
+ cmd = SNDRV_LSM_REG_SND_MODEL_V2;
+ err = msm_cpe_lsm_ioctl_shared(substream, cmd, &snd_model);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: %s failed, error = %d\n",
+ __func__,
+ "SNDRV_LSM_REG_SND_MODEL_V2_32",
+ err);
+ }
+ break;
+ case SNDRV_LSM_EVENT_STATUS32: {
+ struct snd_lsm_event_status *event_status = NULL;
+ struct snd_lsm_event_status u_event_status32;
+ struct snd_lsm_event_status *udata_32 = NULL;
+ int u_pld_size = 0;
+
+ dev_dbg(rtd->dev,
+ "%s: ioctl %s\n", __func__,
+ "SNDRV_LSM_EVENT_STATUS32");
+
+ if (copy_from_user(&u_event_status32, (void *)arg,
+ sizeof(struct snd_lsm_event_status))) {
+ dev_err(rtd->dev,
+ "%s: event status copy from user failed, size %zd\n",
+ __func__,
+ sizeof(struct snd_lsm_event_status));
+ err = -EFAULT;
+ goto done;
+ }
+
+ if (u_event_status32.payload_size >
+ LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
+ dev_err(rtd->dev,
+ "%s: payload_size %d is invalid, max allowed = %d\n",
+ __func__, u_event_status32.payload_size,
+ LISTEN_MAX_STATUS_PAYLOAD_SIZE);
+ err = -EINVAL;
+ goto done;
+ }
+
+ u_pld_size = sizeof(struct snd_lsm_event_status) +
+ u_event_status32.payload_size;
+ event_status = kzalloc(u_pld_size, GFP_KERNEL);
+ if (!event_status) {
+ dev_err(rtd->dev,
+ "%s: No memory for event status\n",
+ __func__);
+ err = -ENOMEM;
+ goto done;
+ } else {
+ event_status->payload_size =
+ u_event_status32.payload_size;
+ cmd = SNDRV_LSM_EVENT_STATUS;
+ err = msm_cpe_lsm_ioctl_shared(substream,
+ cmd, event_status);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: %s failed, error = %d\n",
+ __func__,
+ "SNDRV_LSM_EVENT_STATUS32",
+ err);
+ }
+
+ if (!err) {
+ udata_32 = kzalloc(u_pld_size, GFP_KERNEL);
+ if (!udata_32) {
+ dev_err(rtd->dev,
+ "%s: nomem for udata\n",
+ __func__);
+ err = -EFAULT;
+ } else {
+ udata_32->status = event_status->status;
+ udata_32->payload_size =
+ event_status->payload_size;
+ memcpy(udata_32->payload,
+ event_status->payload,
+ u_pld_size);
+ }
+ }
+
+ if (!err && copy_to_user(arg, udata_32,
+ u_pld_size)) {
+ dev_err(rtd->dev,
+ "%s: copy to user failed\n",
+ __func__);
+ kfree(event_status);
+ kfree(udata_32);
+ err = -EFAULT;
+ goto done;
+ }
+
+ msm_cpe_lsm_lab_start(substream, event_status);
+ msm_cpe_process_event_status_done(lsm_d);
+ kfree(event_status);
+ kfree(udata_32);
+ }
+ break;
+ case SNDRV_LSM_SET_PARAMS32: {
+ struct snd_lsm_detection_params_32 det_params32;
+ struct snd_lsm_detection_params det_params;
+
+ if (session->is_topology_used) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if using topology\n",
+ __func__, "SNDRV_LSM_SET_PARAMS32");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&det_params32, arg,
+ sizeof(det_params32))) {
+ err = -EFAULT;
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %zd\n",
+ __func__, "SNDRV_LSM_SET_PARAMS_32",
+ sizeof(det_params32));
+ } else {
+ det_params.conf_level =
+ compat_ptr(det_params32.conf_level);
+ det_params.detect_mode =
+ det_params32.detect_mode;
+ det_params.num_confidence_levels =
+ det_params32.num_confidence_levels;
+ det_params.detect_failure =
+ det_params32.detect_failure;
+ cmd = SNDRV_LSM_SET_PARAMS;
+ err = msm_cpe_lsm_ioctl_shared(substream, cmd,
+ &det_params);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: ioctl %s failed\n", __func__,
+ "SNDRV_LSM_SET_PARAMS");
+ }
+
+ break;
+ }
+
+ case SNDRV_LSM_SET_MODULE_PARAMS_32: {
+ struct snd_lsm_module_params_32 p_data_32;
+ struct snd_lsm_module_params p_data;
+ u8 *params, *params32;
+ size_t p_size;
+ struct lsm_params_info_32 *p_info_32;
+ struct lsm_params_info *p_info;
+ int i;
+
+ if (!session->is_topology_used) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if not using topology\n",
+ __func__, "SET_MODULE_PARAMS_32");
+ return -EINVAL;
+ }
+
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: %s: No Param data to set\n",
+ __func__, "SET_MODULE_PARAMS_32");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&p_data_32, arg,
+ sizeof(p_data_32))) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %zd\n",
+ __func__, "SET_MODULE_PARAMS_32",
+ sizeof(p_data_32));
+ return -EFAULT;
+ }
+
+ p_data.params = compat_ptr(p_data_32.params);
+ p_data.num_params = p_data_32.num_params;
+ p_data.data_size = p_data_32.data_size;
+
+ if (p_data.num_params > LSM_PARAMS_MAX) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid num_params %d\n",
+ __func__, "SET_MODULE_PARAMS_32",
+ p_data.num_params);
+ return -EINVAL;
+ }
+
+ if (p_data.data_size !=
+ (p_data.num_params * sizeof(struct lsm_params_info_32))) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid size %d\n",
+ __func__, "SET_MODULE_PARAMS_32",
+ p_data.data_size);
+ return -EINVAL;
+ }
+
+ p_size = sizeof(struct lsm_params_info_32) *
+ p_data.num_params;
+
+ params32 = kzalloc(p_size, GFP_KERNEL);
+ if (!params32)
+ return -ENOMEM;
+
+ p_size = sizeof(struct lsm_params_info) * p_data.num_params;
+ params = kzalloc(p_size, GFP_KERNEL);
+ if (!params) {
+ kfree(params32);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(params32, p_data.params,
+ p_data.data_size)) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %d\n",
+ __func__, "params32", p_data.data_size);
+ kfree(params32);
+ kfree(params);
+ return -EFAULT;
+ }
+
+ p_info_32 = (struct lsm_params_info_32 *) params32;
+ p_info = (struct lsm_params_info *) params;
+ for (i = 0; i < p_data.num_params; i++) {
+ p_info->module_id = p_info_32->module_id;
+ p_info->param_id = p_info_32->param_id;
+ p_info->param_size = p_info_32->param_size;
+ p_info->param_data = compat_ptr(p_info_32->param_data);
+ p_info->param_type = p_info_32->param_type;
+
+ p_info_32++;
+ p_info++;
+ }
+
+ err = msm_cpe_lsm_process_params(substream,
+ &p_data, params);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: Failed to process params, err = %d\n",
+ __func__, err);
+ kfree(params);
+ kfree(params32);
+ break;
+ }
+ default:
+ err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg);
+ break;
+ }
+done:
+ MSM_CPE_LSM_REL_LOCK(&lsm_d->lsm_api_lock,
+ "lsm_api_lock");
+ return err;
+}
+
+#else
+#define msm_cpe_lsm_ioctl_compat NULL
+#endif
+
+/*
+ * msm_cpe_lsm_prepare: prepare call from ASoC core for this platform
+ * @substream: ASoC substream for which the operation is invoked
+ *
+ * start the AFE port on CPE associated for this listen session
+ */
+static int msm_cpe_lsm_prepare(struct snd_pcm_substream *substream)
+{
+ int rc = 0;
+ struct cpe_priv *cpe = cpe_get_private_data(substream);
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct wcd_cpe_afe_ops *afe_ops;
+ struct wcd_cpe_afe_port_cfg *afe_cfg;
+ struct cpe_lsm_session *lsm_session;
+ struct cpe_lsm_lab *lab_d = &lsm_d->lab;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_hw_params lsm_param;
+ struct wcd_cpe_lsm_ops *lsm_ops;
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
+ runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
+ pr_err("%s: XRUN ignore for now\n", __func__);
+ return 0;
+ }
+
+ lsm_session = lsm_d->lsm_session;
+ lab_d->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+
+ dev_dbg(rtd->dev,
+ "%s: pcm_size 0x%x", __func__, lab_d->pcm_size);
+
+ if (lsm_d->cpe_prepared) {
+ dev_dbg(rtd->dev, "%s: CPE is alredy prepared\n",
+ __func__);
+ return 0;
+ }
+
+ lsm_ops = &cpe->lsm_ops;
+ afe_ops = &cpe->afe_ops;
+ afe_cfg = &(lsm_d->lsm_session->afe_port_cfg);
+
+ switch (cpe->input_port_id) {
+ case AFE_PORT_ID_3:
+ afe_cfg->port_id = AFE_PORT_ID_3;
+ afe_cfg->bit_width = 16;
+ afe_cfg->num_channels = 1;
+ afe_cfg->sample_rate = SAMPLE_RATE_48KHZ;
+ rc = afe_ops->afe_port_cmd_cfg(cpe->core_handle, afe_cfg);
+ break;
+ case AFE_PORT_ID_1:
+ default:
+ afe_cfg->port_id = AFE_PORT_ID_1;
+ afe_cfg->bit_width = 16;
+ afe_cfg->num_channels = 1;
+ afe_cfg->sample_rate = SAMPLE_RATE_16KHZ;
+ rc = afe_ops->afe_set_params(cpe->core_handle,
+ afe_cfg, cpe->afe_mad_ctl);
+ break;
+ }
+
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: cpe afe params failed for port = %d, err = %d\n",
+ __func__, afe_cfg->port_id, rc);
+ return rc;
+ }
+ lsm_param.sample_rate = afe_cfg->sample_rate;
+ lsm_param.num_chs = afe_cfg->num_channels;
+ lsm_param.bit_width = afe_cfg->bit_width;
+ rc = lsm_ops->lsm_set_media_fmt_params(cpe->core_handle, lsm_session,
+ &lsm_param);
+ if (rc)
+ dev_dbg(rtd->dev,
+ "%s: failed to set lsm media fmt params, err = %d\n",
+ __func__, rc);
+
+ /* Send connect to port (input) */
+ rc = lsm_ops->lsm_set_port(cpe->core_handle, lsm_session,
+ &cpe->input_port_id);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: Failed to set connect input port, err=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (cpe->input_port_id != 3) {
+ rc = lsm_ops->lsm_get_afe_out_port_id(cpe->core_handle,
+ lsm_session);
+ if (rc != 0) {
+ dev_err(rtd->dev,
+ "%s: failed to get port id, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ /* Send connect to port (output) */
+ rc = lsm_ops->lsm_set_port(cpe->core_handle, lsm_session,
+ &lsm_session->afe_out_port_id);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: Failed to set connect output port, err=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+ rc = msm_cpe_afe_port_cntl(substream,
+ cpe->core_handle,
+ afe_ops, afe_cfg,
+ AFE_CMD_PORT_START);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: cpe_afe_port start failed, err = %d\n",
+ __func__, rc);
+ else
+ lsm_d->cpe_prepared = true;
+
+ return rc;
+}
+
+/*
+ * msm_cpe_lsm_trigger: trigger call from ASoC core for this platform
+ * @substream: ASoC substream for which the operation is invoked
+ * @cmd: the trigger command from framework
+ *
+ * suspend/resume the AFE port on CPE associated with listen session
+ */
+static int msm_cpe_lsm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_priv *cpe = cpe_get_private_data(substream);
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct wcd_cpe_afe_ops *afe_ops;
+ struct wcd_cpe_afe_port_cfg *afe_cfg;
+ int afe_cmd = AFE_CMD_INVALID;
+ int rc = 0;
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid private data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid session data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ afe_ops = &cpe->afe_ops;
+ afe_cfg = &(lsm_d->lsm_session->afe_port_cfg);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ afe_cmd = AFE_CMD_PORT_SUSPEND;
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ afe_cmd = AFE_CMD_PORT_RESUME;
+ break;
+
+ default:
+ afe_cmd = AFE_CMD_INVALID;
+ dev_dbg(rtd->dev,
+ "%s: unhandled trigger cmd %d\n",
+ __func__, cmd);
+ break;
+ }
+
+ if (afe_cmd != AFE_CMD_INVALID)
+ rc = msm_cpe_afe_port_cntl(substream,
+ cpe->core_handle,
+ afe_ops, afe_cfg,
+ afe_cmd);
+
+ return rc;
+}
+
+static int msm_cpe_lsm_hwparams(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct cpe_priv *cpe = cpe_get_private_data(substream);
+ struct cpe_lsm_session *session = NULL;
+ struct cpe_hw_params *hw_params = NULL;
+
+ if (!cpe || !cpe->core_handle) {
+ dev_err(rtd->dev,
+ "%s: Invalid %s\n",
+ __func__,
+ (!cpe) ? "cpe" : "core");
+ return -EINVAL;
+ }
+
+ if (!lsm_d || !lsm_d->lsm_session) {
+ dev_err(rtd->dev,
+ "%s: Invalid %s\n",
+ __func__,
+ (!lsm_d) ? "priv_data" : "session");
+ return -EINVAL;
+ }
+
+ session = lsm_d->lsm_session;
+ hw_params = &lsm_d->hw_params;
+ hw_params->buf_sz = (params_buffer_bytes(params)
+ / params_periods(params));
+ hw_params->period_count = params_periods(params);
+ hw_params->channels = params_channels(params);
+ hw_params->sample_rate = params_rate(params);
+
+ if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
+ hw_params->sample_size = 16;
+ else if (params_format(params) ==
+ SNDRV_PCM_FORMAT_S24_LE)
+ hw_params->sample_size = 24;
+ else if (params_format(params) ==
+ SNDRV_PCM_FORMAT_S32_LE)
+ hw_params->sample_size = 32;
+ else {
+ dev_err(rtd->dev,
+ "%s: Invalid Format 0x%x\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ dev_dbg(rtd->dev,
+ "%s: Format %d buffer size(bytes) %d period count %d\n"
+ " Channel %d period in bytes 0x%x Period Size 0x%x rate = %d\n",
+ __func__, params_format(params), params_buffer_bytes(params),
+ params_periods(params), params_channels(params),
+ params_period_bytes(params), params_period_size(params),
+ params_rate(params));
+
+ return 0;
+}
+
+static snd_pcm_uframes_t msm_cpe_lsm_pointer(
+ struct snd_pcm_substream *substream)
+{
+
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct cpe_lsm_session *session;
+ struct cpe_lsm_lab *lab_d = &lsm_d->lab;
+
+ session = lsm_d->lsm_session;
+ if (lab_d->dma_write >= lab_d->pcm_size)
+ lab_d->dma_write = 0;
+ dev_dbg(rtd->dev,
+ "%s:pcm_dma_pos = %d\n",
+ __func__, lab_d->dma_write);
+
+ return bytes_to_frames(runtime, (lab_d->dma_write));
+}
+
+static int msm_cpe_lsm_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct cpe_lsm_session *session;
+ struct cpe_lsm_lab *lab_d = &lsm_d->lab;
+ char *pcm_buf;
+ int fbytes = 0;
+ int rc = 0;
+
+ fbytes = frames_to_bytes(runtime, frames);
+ if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
+ runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
+ pr_err("%s: XRUN ignore for now\n", __func__);
+ return 0;
+ }
+ session = lsm_d->lsm_session;
+
+ /* Check if buffer reading is already in error state */
+ if (lab_d->thread_status == MSM_LSM_LAB_THREAD_ERROR) {
+ dev_err(rtd->dev,
+ "%s: Bufferring is in error state\n",
+ __func__);
+ /*
+ * Advance the period so there is no wait in case
+ * read is invoked even after error is propogated
+ */
+ atomic_inc(&lab_d->in_count);
+ lab_d->dma_write += snd_pcm_lib_period_bytes(substream);
+ snd_pcm_period_elapsed(substream);
+ return -ENETRESET;
+ } else if (lab_d->thread_status == MSM_LSM_LAB_THREAD_STOP) {
+ dev_err(rtd->dev,
+ "%s: Buferring is in stopped\n",
+ __func__);
+ return -EIO;
+ }
+
+ rc = wait_event_timeout(lab_d->period_wait,
+ (atomic_read(&lab_d->in_count) ||
+ atomic_read(&lab_d->abort_read)),
+ (2 * HZ));
+ if (atomic_read(&lab_d->abort_read)) {
+ pr_debug("%s: LSM LAB Abort read\n", __func__);
+ return -EIO;
+ }
+ if (lab_d->thread_status != MSM_LSM_LAB_THREAD_RUNNING) {
+ pr_err("%s: Lab stopped\n", __func__);
+ return -EIO;
+ }
+ if (!rc) {
+ pr_err("%s:LAB err wait_event_timeout\n", __func__);
+ rc = -EAGAIN;
+ goto fail;
+ }
+ if (lab_d->buf_idx >= (lsm_d->hw_params.period_count))
+ lab_d->buf_idx = 0;
+ pcm_buf = (lab_d->pcm_buf[lab_d->buf_idx].mem);
+ pr_debug("%s: Buf IDX = 0x%x pcm_buf %pK\n",
+ __func__, lab_d->buf_idx, pcm_buf);
+ if (pcm_buf) {
+ if (copy_to_user(buf, pcm_buf, fbytes)) {
+ pr_err("Failed to copy buf to user\n");
+ rc = -EFAULT;
+ goto fail;
+ }
+ }
+ lab_d->buf_idx++;
+ atomic_dec(&lab_d->in_count);
+ return 0;
+fail:
+ return rc;
+}
+
+/*
+ * msm_asoc_cpe_lsm_probe: ASoC framework for lsm platform driver
+ * @platform: platform registered with ASoC core
+ *
+ * Allocate the private data for this platform and obtain the ops for
+ * lsm and afe modules from underlying driver. Also find the codec
+ * for this platform as specified by machine driver for ASoC framework.
+ */
+static int msm_asoc_cpe_lsm_probe(struct snd_soc_platform *platform)
+{
+ struct snd_soc_card *card;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *codec;
+ struct cpe_priv *cpe_priv;
+ const struct snd_kcontrol_new *kcontrol;
+ bool found_runtime = false;
+ const char *cpe_dev_id = "qcom,msm-cpe-lsm-id";
+ u32 port_id = 0;
+ int ret = 0;
+ int i;
+
+ if (!platform || !platform->component.card) {
+ pr_err("%s: Invalid platform or card\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ card = platform->component.card;
+
+ /* Match platform to codec */
+ for (i = 0; i < card->num_links; i++) {
+ rtd = &card->rtd[i];
+ if (!rtd->platform)
+ continue;
+ if (!strcmp(rtd->platform->component.name,
+ platform->component.name)) {
+ found_runtime = true;
+ break;
+ }
+ }
+
+ if (!found_runtime) {
+ dev_err(platform->dev,
+ "%s: Failed to find runtime for platform\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(platform->dev->of_node, cpe_dev_id,
+ &port_id);
+ if (ret) {
+ dev_dbg(platform->dev,
+ "%s: missing 0x%x in dt node\n", __func__, port_id);
+ port_id = 1;
+ }
+
+ codec = rtd->codec;
+
+ cpe_priv = kzalloc(sizeof(struct cpe_priv),
+ GFP_KERNEL);
+ if (!cpe_priv)
+ return -ENOMEM;
+
+ cpe_priv->codec = codec;
+ cpe_priv->input_port_id = port_id;
+ wcd_cpe_get_lsm_ops(&cpe_priv->lsm_ops);
+ wcd_cpe_get_afe_ops(&cpe_priv->afe_ops);
+
+ snd_soc_platform_set_drvdata(platform, cpe_priv);
+ kcontrol = &msm_cpe_kcontrols[0];
+ snd_ctl_add(card->snd_card, snd_ctl_new1(kcontrol, cpe_priv));
+ return 0;
+}
+
+static struct snd_pcm_ops msm_cpe_lsm_ops = {
+ .open = msm_cpe_lsm_open,
+ .close = msm_cpe_lsm_close,
+ .ioctl = msm_cpe_lsm_ioctl,
+ .prepare = msm_cpe_lsm_prepare,
+ .trigger = msm_cpe_lsm_trigger,
+ .pointer = msm_cpe_lsm_pointer,
+ .copy = msm_cpe_lsm_copy,
+ .hw_params = msm_cpe_lsm_hwparams,
+ .compat_ioctl = msm_cpe_lsm_ioctl_compat,
+};
+
+static struct snd_soc_platform_driver msm_soc_cpe_platform = {
+ .ops = &msm_cpe_lsm_ops,
+ .probe = msm_asoc_cpe_lsm_probe,
+};
+
+/*
+ * msm_cpe_lsm_probe: platform driver probe
+ * @pdev: platform device
+ *
+ * Register the ASoC platform driver with ASoC core
+ */
+static int msm_cpe_lsm_probe(struct platform_device *pdev)
+{
+
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_cpe_platform);
+}
+
+/*
+ * msm_cpe_lsm_remove: platform driver remove
+ * @pdev: platform device
+ *
+ * Deregister the ASoC platform driver
+ */
+static int msm_cpe_lsm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_cpe_lsm_dt_match[] = {
+ {.compatible = "qcom,msm-cpe-lsm" },
+ { }
+};
+
+static struct platform_driver msm_cpe_lsm_driver = {
+ .driver = {
+ .name = "msm-cpe-lsm",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(msm_cpe_lsm_dt_match),
+ },
+ .probe = msm_cpe_lsm_probe,
+ .remove = msm_cpe_lsm_remove,
+};
+module_platform_driver(msm_cpe_lsm_driver);
+
+MODULE_DESCRIPTION("CPE LSM platform driver");
+MODULE_DEVICE_TABLE(of, msm_cpe_lsm_dt_match);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
new file mode 100644
index 0000000..081f8b4
--- /dev/null
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -0,0 +1,2555 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+static struct snd_soc_dai_ops msm_fe_dai_ops = {};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+ 88200, 96000, 176400, 192000, 352800, 384000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static int multimedia_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ return 0;
+}
+
+static int fe_dai_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_dapm_route intercon;
+ struct snd_soc_dapm_context *dapm;
+
+ if (!dai || !dai->driver) {
+ pr_err("%s invalid params\n", __func__);
+ return -EINVAL;
+ }
+ dapm = snd_soc_component_get_dapm(dai->component);
+ memset(&intercon, 0, sizeof(intercon));
+ if (dai->driver->playback.stream_name &&
+ dai->driver->playback.aif_name) {
+ dev_dbg(dai->dev, "%s add route for widget %s",
+ __func__, dai->driver->playback.stream_name);
+ intercon.source = dai->driver->playback.stream_name;
+ intercon.sink = dai->driver->playback.aif_name;
+ dev_dbg(dai->dev, "%s src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ snd_soc_dapm_ignore_suspend(dapm, intercon.source);
+ }
+ if (dai->driver->capture.stream_name &&
+ dai->driver->capture.aif_name) {
+ dev_dbg(dai->dev, "%s add route for widget %s",
+ __func__, dai->driver->capture.stream_name);
+ intercon.sink = dai->driver->capture.stream_name;
+ intercon.source = dai->driver->capture.aif_name;
+ dev_dbg(dai->dev, "%s src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ snd_soc_dapm_ignore_suspend(dapm, intercon.sink);
+ }
+ return 0;
+}
+
+static struct snd_soc_dai_ops msm_fe_Multimedia_dai_ops = {
+ .startup = multimedia_startup,
+};
+
+static const struct snd_soc_component_driver msm_fe_dai_component = {
+ .name = "msm-dai-fe",
+};
+
+static struct snd_soc_dai_driver msm_fe_dais[] = {
+ {
+ .playback = {
+ .stream_name = "MultiMedia1 Playback",
+ .aif_name = "MM_DL1",
+ .rates = (SNDRV_PCM_RATE_8000_384000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia1 Capture",
+ .aif_name = "MM_UL1",
+ .rates = (SNDRV_PCM_RATE_8000_384000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia1",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia2 Playback",
+ .aif_name = "MM_DL2",
+ .rates = (SNDRV_PCM_RATE_8000_384000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia2 Capture",
+ .aif_name = "MM_UL2",
+ .rates = (SNDRV_PCM_RATE_8000_384000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia2",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "CS-VOICE Playback",
+ .aif_name = "CS-VOICE_DL1",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "CS-VOICE Capture",
+ .aif_name = "CS-VOICE_UL1",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "CS-VOICE",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "VoIP Playback",
+ .aif_name = "VOIP_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_SPECIAL,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VoIP Capture",
+ .aif_name = "VOIP_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_SPECIAL,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VoIP",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia3 Playback",
+ .aif_name = "MM_DL3",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 6,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia3 Capture",
+ .aif_name = "MM_UL3",
+ .rates = (SNDRV_PCM_RATE_8000_384000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia3",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia4 Playback",
+ .aif_name = "MM_DL4",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia4",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia5 Playback",
+ .aif_name = "MM_DL5",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia5 Capture",
+ .aif_name = "MM_UL5",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia5",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia6 Playback",
+ .aif_name = "MM_DL6",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia6 Capture",
+ .aif_name = "MM_UL6",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia6",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia7 Playback",
+ .aif_name = "MM_DL7",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia7",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia8 Playback",
+ .aif_name = "MM_DL8",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia8 Capture",
+ .aif_name = "MM_UL8",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia8",
+ .probe = fe_dai_probe,
+ },
+ /* FE DAIs created for hostless operation purpose */
+ {
+ .playback = {
+ .stream_name = "SLIMBUS0_HOSTLESS Playback",
+ .aif_name = "SLIM0_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "SLIMBUS0_HOSTLESS Capture",
+ .aif_name = "SLIM0_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SLIMBUS0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "SLIMBUS1_HOSTLESS Playback",
+ .aif_name = "SLIM1_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "SLIMBUS1_HOSTLESS Capture",
+ .aif_name = "SLIM1_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SLIMBUS1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "SLIMBUS3_HOSTLESS Playback",
+ .aif_name = "SLIM3_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "SLIMBUS3_HOSTLESS Capture",
+ .aif_name = "SLIM3_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SLIMBUS3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "SLIMBUS4_HOSTLESS Playback",
+ .aif_name = "SLIM4_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "SLIMBUS4_HOSTLESS Capture",
+ .aif_name = "SLIM4_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SLIMBUS4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "SLIMBUS6_HOSTLESS Playback",
+ .aif_name = "SLIM6_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SLIMBUS6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "SLIMBUS8_HOSTLESS Playback",
+ .aif_name = "SLIM8_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "SLIMBUS8_HOSTLESS Capture",
+ .aif_name = "SLIM8_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SLIMBUS8_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "INT_FM_HOSTLESS Playback",
+ .aif_name = "INTFM_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT_FM_HOSTLESS Capture",
+ .aif_name = "INTFM_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT_FM_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "INT_HFP_BT Hostless Playback",
+ .aif_name = "INTHFP_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .capture = {
+ .stream_name = "INT_HFP_BT Hostless Capture",
+ .aif_name = "INTHFP_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT_HFP_BT_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "AFE Playback",
+ .aif_name = "PCM_RX",
+ .rates = (SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "AFE Capture",
+ .aif_name = "PCM_TX",
+ .rates = (SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "AFE-PROXY",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "HDMI_HOSTLESS Playback",
+ .aif_name = "HDMI_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "HDMI_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "AUXPCM_HOSTLESS Playback",
+ .aif_name = "AUXPCM_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .capture = {
+ .stream_name = "AUXPCM_HOSTLESS Capture",
+ .aif_name = "AUXPCM_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "AUXPCM_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "VOICE_STUB Playback",
+ .aif_name = "VOICE_STUB_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VOICE_STUB Capture",
+ .aif_name = "VOICE_STUB_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VOICE_STUB",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "VoLTE Playback",
+ .aif_name = "VoLTE_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VoLTE Capture",
+ .aif_name = "VoLTE_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VoLTE",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MI2S_RX_HOSTLESS Playback",
+ .aif_name = "MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "MI2S_TX_HOSTLESS Capture",
+ .aif_name = "MI2S_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "MI2S_TX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "SEC_I2S_RX_HOSTLESS Playback",
+ .aif_name = "SEC_I2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_I2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary MI2S_TX Hostless Capture",
+ .aif_name = "PRI_MI2S_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_MI2S_TX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary MI2S_RX Hostless Playback",
+ .aif_name = "PRI_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_MI2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary MI2S_TX Hostless Capture",
+ .aif_name = "SEC_MI2S_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_MI2S_TX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary MI2S_RX Hostless Playback",
+ .aif_name = "SEC_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_MI2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary MI2S_TX Hostless Capture",
+ .aif_name = "TERT_MI2S_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_MI2S_TX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary MI2S_RX Hostless Playback",
+ .aif_name = "TERT_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_MI2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary MI2S_TX Hostless Capture",
+ .aif_name = "QUAT_MI2S_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_MI2S_TX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary MI2S_RX Hostless Playback",
+ .aif_name = "QUAT_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_MI2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "INT0 MI2S_RX Hostless Playback",
+ .aif_name = "INT0_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT0_MI2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "INT4 MI2S_RX Hostless Playback",
+ .aif_name = "INT4_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT4_MI2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ /* TDM Hostless */
+ {
+ .capture = {
+ .stream_name = "Primary TDM0 Hostless Capture",
+ .aif_name = "PRI_TDM_TX_0_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_TX_0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM0 Hostless Playback",
+ .aif_name = "PRI_TDM_RX_0_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_RX_0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM1 Hostless Capture",
+ .aif_name = "PRI_TDM_TX_1_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_TX_1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM1 Hostless Playback",
+ .aif_name = "PRI_TDM_RX_1_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_RX_1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM2 Hostless Capture",
+ .aif_name = "PRI_TDM_TX_2_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_TX_2_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM2 Hostless Playback",
+ .aif_name = "PRI_TDM_RX_2_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_RX_2_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM3 Hostless Capture",
+ .aif_name = "PRI_TDM_TX_3_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_TX_3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM3 Hostless Playback",
+ .aif_name = "PRI_TDM_RX_3_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_RX_3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM4 Hostless Capture",
+ .aif_name = "PRI_TDM_TX_4_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_TX_4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM4 Hostless Playback",
+ .aif_name = "PRI_TDM_RX_4_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_RX_4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM5 Hostless Capture",
+ .aif_name = "PRI_TDM_TX_5_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_TX_5_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM5 Hostless Playback",
+ .aif_name = "PRI_TDM_RX_5_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_RX_5_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM6 Hostless Capture",
+ .aif_name = "PRI_TDM_TX_6_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_TX_6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM6 Hostless Playback",
+ .aif_name = "PRI_TDM_RX_6_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_RX_6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM7 Hostless Capture",
+ .aif_name = "PRI_TDM_TX_7_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_TX_7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM7 Hostless Playback",
+ .aif_name = "PRI_TDM_RX_7_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_TDM_RX_7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM0 Hostless Capture",
+ .aif_name = "SEC_TDM_TX_0_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_TX_0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM0 Hostless Playback",
+ .aif_name = "SEC_TDM_RX_0_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_RX_0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM1 Hostless Capture",
+ .aif_name = "SEC_TDM_TX_1_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_TX_1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM1 Hostless Playback",
+ .aif_name = "SEC_TDM_RX_1_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_RX_1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM2 Hostless Capture",
+ .aif_name = "SEC_TDM_TX_2_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_TX_2_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM2 Hostless Playback",
+ .aif_name = "SEC_TDM_RX_2_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_RX_2_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM3 Hostless Capture",
+ .aif_name = "SEC_TDM_TX_3_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_TX_3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM3 Hostless Playback",
+ .aif_name = "SEC_TDM_RX_3_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_RX_3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM4 Hostless Capture",
+ .aif_name = "SEC_TDM_TX_4_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_TX_4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM4 Hostless Playback",
+ .aif_name = "SEC_TDM_RX_4_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_RX_4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM5 Hostless Capture",
+ .aif_name = "SEC_TDM_TX_5_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_TX_5_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM5 Hostless Playback",
+ .aif_name = "SEC_TDM_RX_5_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_RX_5_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM6 Hostless Capture",
+ .aif_name = "SEC_TDM_TX_6_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_TX_6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM6 Hostless Playback",
+ .aif_name = "SEC_TDM_RX_6_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_RX_6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM7 Hostless Capture",
+ .aif_name = "SEC_TDM_TX_7_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_TX_7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM7 Hostless Playback",
+ .aif_name = "SEC_TDM_RX_7_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_TDM_RX_7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM0 Hostless Capture",
+ .aif_name = "TERT_TDM_TX_0_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_TX_0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM0 Hostless Playback",
+ .aif_name = "TERT_TDM_RX_0_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_RX_0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM1 Hostless Capture",
+ .aif_name = "TERT_TDM_TX_1_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_TX_1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM1 Hostless Playback",
+ .aif_name = "TERT_TDM_RX_1_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_RX_1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM2 Hostless Capture",
+ .aif_name = "TERT_TDM_TX_2_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_TX_2_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM2 Hostless Playback",
+ .aif_name = "TERT_TDM_RX_2_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_RX_2_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM3 Hostless Capture",
+ .aif_name = "TERT_TDM_TX_3_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_TX_3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM3 Hostless Playback",
+ .aif_name = "TERT_TDM_RX_3_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_RX_3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM4 Hostless Capture",
+ .aif_name = "TERT_TDM_TX_4_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_TX_4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM4 Hostless Playback",
+ .aif_name = "TERT_TDM_RX_4_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_RX_4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM5 Hostless Capture",
+ .aif_name = "TERT_TDM_TX_5_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_TX_5_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM5 Hostless Playback",
+ .aif_name = "TERT_TDM_RX_5_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_RX_5_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM6 Hostless Capture",
+ .aif_name = "TERT_TDM_TX_6_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_TX_6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM6 Hostless Playback",
+ .aif_name = "TERT_TDM_RX_6_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_RX_6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM7 Hostless Capture",
+ .aif_name = "TERT_TDM_TX_7_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_TX_7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM7 Hostless Playback",
+ .aif_name = "TERT_TDM_RX_7_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "TERT_TDM_RX_7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM0 Hostless Capture",
+ .aif_name = "QUAT_TDM_TX_0_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_TX_0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM0 Hostless Playback",
+ .aif_name = "QUAT_TDM_RX_0_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_RX_0_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM1 Hostless Capture",
+ .aif_name = "QUAT_TDM_TX_1_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_TX_1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM1 Hostless Playback",
+ .aif_name = "QUAT_TDM_RX_1_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_RX_1_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM2 Hostless Capture",
+ .aif_name = "QUAT_TDM_TX_2_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_TX_2_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM2 Hostless Playback",
+ .aif_name = "QUAT_TDM_RX_2_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_RX_2_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM3 Hostless Capture",
+ .aif_name = "QUAT_TDM_TX_3_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_TX_3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM3 Hostless Playback",
+ .aif_name = "QUAT_TDM_RX_3_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_RX_3_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM4 Hostless Capture",
+ .aif_name = "QUAT_TDM_TX_4_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_TX_4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM4 Hostless Playback",
+ .aif_name = "QUAT_TDM_RX_4_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_RX_4_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM5 Hostless Capture",
+ .aif_name = "QUAT_TDM_TX_5_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_TX_5_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM5 Hostless Playback",
+ .aif_name = "QUAT_TDM_RX_5_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_RX_5_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM6 Hostless Capture",
+ .aif_name = "QUAT_TDM_TX_6_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_TX_6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM6 Hostless Playback",
+ .aif_name = "QUAT_TDM_RX_6_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_RX_6_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM7 Hostless Capture",
+ .aif_name = "QUAT_TDM_TX_7_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_TX_7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM7 Hostless Playback",
+ .aif_name = "QUAT_TDM_RX_7_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QUAT_TDM_RX_7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Voice2 Playback",
+ .aif_name = "VOICE2_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "Voice2 Capture",
+ .aif_name = "VOICE2_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "Voice2",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "Pseudo Playback",
+ .aif_name = "MM_DL9",
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "Pseudo Capture",
+ .aif_name = "MM_UL9",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "Pseudo",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "DTMF_RX_HOSTLESS Playback",
+ .aif_name = "DTMF_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "DTMF_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "CPE Listen Audio capture",
+ .aif_name = "CPE_LSM_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "CPE_LSM_NOHOST",
+ },
+ {
+ .playback = {
+ .stream_name = "VOLTE_STUB Playback",
+ .aif_name = "VOLTE_STUB_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VOLTE_STUB Capture",
+ .aif_name = "VOLTE_STUB_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VOLTE_STUB",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "VOICE2_STUB Playback",
+ .aif_name = "VOICE2_STUB_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VOICE2_STUB Capture",
+ .aif_name = "VOICE2_STUB_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VOICE2_STUB",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia9 Playback",
+ .aif_name = "MM_DL9",
+ .rates = (SNDRV_PCM_RATE_8000_384000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia9 Capture",
+ .aif_name = "MM_UL9",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia9",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "QCHAT Playback",
+ .aif_name = "QCHAT_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "QCHAT Capture",
+ .aif_name = "QCHAT_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QCHAT",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 1 Audio Service Capture",
+ .aif_name = "LSM1_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM1",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 2 Audio Service Capture",
+ .aif_name = "LSM2_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM2",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 3 Audio Service Capture",
+ .aif_name = "LSM3_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM3",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 4 Audio Service Capture",
+ .aif_name = "LSM4_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM4",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 5 Audio Service Capture",
+ .aif_name = "LSM5_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM5",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 6 Audio Service Capture",
+ .aif_name = "LSM6_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM6",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 7 Audio Service Capture",
+ .aif_name = "LSM7_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM7",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 8 Audio Service Capture",
+ .aif_name = "LSM8_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM8",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "VoWLAN Playback",
+ .aif_name = "VoWLAN_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VoWLAN Capture",
+ .aif_name = "VoWLAN_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VoWLAN",
+ .probe = fe_dai_probe,
+ },
+ /* FE DAIs created for multiple instances of offload playback */
+ {
+ .playback = {
+ .stream_name = "MultiMedia10 Playback",
+ .aif_name = "MM_DL10",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia10",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia11 Playback",
+ .aif_name = "MM_DL11",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia11",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia12 Playback",
+ .aif_name = "MM_DL12",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia12",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia13 Playback",
+ .aif_name = "MM_DL13",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia13",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia14 Playback",
+ .aif_name = "MM_DL14",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia14",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia15 Playback",
+ .aif_name = "MM_DL15",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia15",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia16 Playback",
+ .aif_name = "MM_DL16",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia16",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "VoiceMMode1 Playback",
+ .aif_name = "VOICEMMODE1_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VoiceMMode1 Capture",
+ .aif_name = "VOICEMMODE1_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VoiceMMode1",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "VoiceMMode2 Playback",
+ .aif_name = "VOICEMMODE2_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VoiceMMode2 Capture",
+ .aif_name = "VOICEMMODE2_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VoiceMMode2",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "MultiMedia17 Capture",
+ .aif_name = "MM_UL17",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia17",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "MultiMedia18 Capture",
+ .aif_name = "MM_UL18",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia18",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "MultiMedia19 Capture",
+ .aif_name = "MM_UL19",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia19",
+ .probe = fe_dai_probe,
+ },
+};
+
+static int msm_fe_dai_dev_probe(struct platform_device *pdev)
+{
+
+ dev_dbg(&pdev->dev, "%s: dev name %s\n", __func__,
+ dev_name(&pdev->dev));
+ return snd_soc_register_component(&pdev->dev, &msm_fe_dai_component,
+ msm_fe_dais, ARRAY_SIZE(msm_fe_dais));
+}
+
+static int msm_fe_dai_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_dai_fe_dt_match[] = {
+ {.compatible = "qcom,msm-dai-fe"},
+ {}
+};
+
+static struct platform_driver msm_fe_dai_driver = {
+ .probe = msm_fe_dai_dev_probe,
+ .remove = msm_fe_dai_dev_remove,
+ .driver = {
+ .name = "msm-dai-fe",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_fe_dt_match,
+ },
+};
+
+static int __init msm_fe_dai_init(void)
+{
+ return platform_driver_register(&msm_fe_dai_driver);
+}
+module_init(msm_fe_dai_init);
+
+static void __exit msm_fe_dai_exit(void)
+{
+ platform_driver_unregister(&msm_fe_dai_driver);
+}
+module_exit(msm_fe_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Frontend DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-hostless.c b/sound/soc/msm/msm-pcm-hostless.c
new file mode 100644
index 0000000..5793243
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-hostless.c
@@ -0,0 +1,82 @@
+/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+
+
+static int msm_pcm_hostless_prepare(struct snd_pcm_substream *substream)
+{
+ if (!substream) {
+ pr_err("%s: invalid params\n", __func__);
+ return -EINVAL;
+ }
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
+ return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_hostless_ops = {
+ .prepare = msm_pcm_hostless_prepare
+};
+
+static struct snd_soc_platform_driver msm_soc_hostless_platform = {
+ .ops = &msm_pcm_hostless_ops,
+};
+
+static int msm_pcm_hostless_probe(struct platform_device *pdev)
+{
+
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_hostless_platform);
+}
+
+static int msm_pcm_hostless_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_pcm_hostless_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-hostless"},
+ {}
+};
+
+static struct platform_driver msm_pcm_hostless_driver = {
+ .driver = {
+ .name = "msm-pcm-hostless",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_hostless_dt_match,
+ },
+ .probe = msm_pcm_hostless_probe,
+ .remove = msm_pcm_hostless_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_hostless_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_hostless_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Hostless platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c
new file mode 100644
index 0000000..077005a
--- /dev/null
+++ b/sound/soc/msm/msm8996.c
@@ -0,0 +1,4003 @@
+/*
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6core.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <device_event.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "../codecs/wcd9xxx-common.h"
+#include "../codecs/wcd9330.h"
+#include "../codecs/wcd9335.h"
+#include "../codecs/wsa881x.h"
+
+#define DRV_NAME "msm8996-asoc-snd"
+
+#define SAMPLING_RATE_8KHZ 8000
+#define SAMPLING_RATE_16KHZ 16000
+#define SAMPLING_RATE_32KHZ 32000
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_192KHZ 192000
+#define SAMPLING_RATE_44P1KHZ 44100
+
+#define MSM8996_SPK_ON 1
+#define MSM8996_HIFI_ON 1
+
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define CODEC_EXT_CLK_RATE 9600000
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+#define DEV_NAME_STR_LEN 32
+
+#define WSA8810_NAME_1 "wsa881x.20170211"
+#define WSA8810_NAME_2 "wsa881x.20170212"
+
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+static int slim0_tx_sample_rate = SAMPLING_RATE_48KHZ;
+static int slim1_tx_sample_rate = SAMPLING_RATE_48KHZ;
+static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int slim1_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
+static int slim5_rx_sample_rate = SAMPLING_RATE_48KHZ;
+static int slim5_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int slim6_rx_sample_rate = SAMPLING_RATE_48KHZ;
+static int slim6_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+
+static struct platform_device *spdev;
+static int ext_us_amp_gpio = -1;
+static int msm8996_spk_control = 1;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+static int msm_slim_1_tx_ch = 1;
+static int msm_slim_5_rx_ch = 1;
+static int msm_slim_6_rx_ch = 1;
+static int msm_hifi_control;
+static int msm_vi_feed_tx_ch = 2;
+
+static int msm_hdmi_rx_ch = 2;
+static int msm_proxy_rx_ch = 2;
+static int hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ;
+static int msm_tert_mi2s_tx_ch = 2;
+
+static bool codec_reg_done;
+
+static const char *const hifi_function[] = {"Off", "On"};
+static const char *const pin_states[] = {"Disable", "active"};
+static const char *const spk_function[] = {"Off", "On"};
+static const char *const slim0_rx_ch_text[] = {"One", "Two"};
+static const char *const slim5_rx_ch_text[] = {"One", "Two"};
+static const char *const slim6_rx_ch_text[] = {"One", "Two"};
+static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static const char *const vi_feed_ch_text[] = {"One", "Two"};
+static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
+static char const *slim5_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
+static char const *slim6_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192", "KHZ_44P1", "KHZ_8",
+ "KHZ_16", "KHZ_32"};
+static char const *slim5_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192", "KHZ_44P1"};
+static char const *slim6_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192", "KHZ_44P1"};
+static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
+
+static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
+
+static const char *const auxpcm_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm8996_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
+static struct afe_clk_set mi2s_tx_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+};
+
+struct msm8996_wsa881x_dev_info {
+ struct device_node *of_node;
+ u32 index;
+};
+
+static struct snd_soc_aux_dev *msm8996_aux_dev;
+static struct snd_soc_codec_conf *msm8996_codec_conf;
+
+struct msm8996_asoc_mach_data {
+ u32 mclk_freq;
+ int us_euro_gpio;
+ int hph_en1_gpio;
+ int hph_en0_gpio;
+ struct snd_info_entry *codec_root;
+};
+
+struct msm8996_asoc_wcd93xx_codec {
+ void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
+ enum afe_config_type config_type);
+ void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
+};
+
+static struct msm8996_asoc_wcd93xx_codec msm8996_codec_fn;
+
+struct msm8996_liquid_dock_dev {
+ int dock_plug_gpio;
+ int dock_plug_irq;
+ int dock_plug_det;
+ struct work_struct irq_work;
+ struct switch_dev audio_sdev;
+};
+static struct msm8996_liquid_dock_dev *msm8996_liquid_dock_dev;
+
+static void *adsp_state_notifier;
+static void *def_tasha_mbhc_cal(void);
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm);
+static int msm8996_wsa881x_init(struct snd_soc_component *component);
+
+/*
+ * Need to report LINEIN
+ * if R/L channel impedance is larger than 5K ohm
+ */
+static struct wcd_mbhc_config wcd_mbhc_cfg = {
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .detect_extn_cable = true,
+ .mono_stero_detection = false,
+ .swap_gnd_mic = NULL,
+ .hs_ext_micbias = true,
+ .key_code[0] = KEY_MEDIA,
+ .key_code[1] = KEY_VOICECOMMAND,
+ .key_code[2] = KEY_VOLUMEUP,
+ .key_code[3] = KEY_VOLUMEDOWN,
+ .key_code[4] = 0,
+ .key_code[5] = 0,
+ .key_code[6] = 0,
+ .key_code[7] = 0,
+ .linein_th = 5000,
+ .moisture_en = true,
+ .mbhc_micbias = MIC_BIAS_2,
+ .anc_micbias = MIC_BIAS_2,
+ .enable_anc_mic_detect = false,
+};
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
+ int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static void msm8996_liquid_docking_irq_work(struct work_struct *work)
+{
+ struct msm8996_liquid_dock_dev *dock_dev =
+ container_of(work, struct msm8996_liquid_dock_dev,
+ irq_work);
+
+ dock_dev->dock_plug_det =
+ gpio_get_value(dock_dev->dock_plug_gpio);
+
+ switch_set_state(&dock_dev->audio_sdev, dock_dev->dock_plug_det);
+ /* notify to audio daemon */
+ sysfs_notify(&dock_dev->audio_sdev.dev->kobj, NULL, "state");
+}
+
+static irqreturn_t msm8996_liquid_docking_irq_handler(int irq, void *dev)
+{
+ struct msm8996_liquid_dock_dev *dock_dev = dev;
+
+ /* switch speakers should not run in interrupt context */
+ schedule_work(&dock_dev->irq_work);
+ return IRQ_HANDLED;
+}
+
+static int msm8996_liquid_init_docking(void)
+{
+ int ret = 0;
+ int dock_plug_gpio = 0;
+
+ /* plug in docking speaker+plug in device OR unplug one of them */
+ u32 dock_plug_irq_flags = IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_SHARED;
+
+ dock_plug_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,dock-plug-det-irq", 0);
+
+ if (dock_plug_gpio >= 0) {
+ msm8996_liquid_dock_dev =
+ kzalloc(sizeof(*msm8996_liquid_dock_dev), GFP_KERNEL);
+ if (!msm8996_liquid_dock_dev) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ msm8996_liquid_dock_dev->dock_plug_gpio = dock_plug_gpio;
+
+ ret = gpio_request(msm8996_liquid_dock_dev->dock_plug_gpio,
+ "dock-plug-det-irq");
+ if (ret) {
+ pr_err("%s:failed request msm8996_liquid_dock_plug_gpio err = %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto fail_dock_gpio;
+ }
+
+ msm8996_liquid_dock_dev->dock_plug_det =
+ gpio_get_value(
+ msm8996_liquid_dock_dev->dock_plug_gpio);
+ msm8996_liquid_dock_dev->dock_plug_irq =
+ gpio_to_irq(
+ msm8996_liquid_dock_dev->dock_plug_gpio);
+
+ ret = request_irq(msm8996_liquid_dock_dev->dock_plug_irq,
+ msm8996_liquid_docking_irq_handler,
+ dock_plug_irq_flags,
+ "liquid_dock_plug_irq",
+ msm8996_liquid_dock_dev);
+ if (ret < 0) {
+ pr_err("%s: Request Irq Failed err = %d\n",
+ __func__, ret);
+ goto fail_dock_gpio;
+ }
+
+ msm8996_liquid_dock_dev->audio_sdev.name =
+ QC_AUDIO_EXTERNAL_SPK_1_EVENT;
+
+ if (switch_dev_register(
+ &msm8996_liquid_dock_dev->audio_sdev) < 0) {
+ pr_err("%s: dock device register in switch diretory failed\n",
+ __func__);
+ goto fail_switch_dev;
+ }
+
+ INIT_WORK(
+ &msm8996_liquid_dock_dev->irq_work,
+ msm8996_liquid_docking_irq_work);
+ }
+ return 0;
+
+fail_switch_dev:
+ free_irq(msm8996_liquid_dock_dev->dock_plug_irq,
+ msm8996_liquid_dock_dev);
+fail_dock_gpio:
+ gpio_free(msm8996_liquid_dock_dev->dock_plug_gpio);
+exit:
+ kfree(msm8996_liquid_dock_dev);
+ msm8996_liquid_dock_dev = NULL;
+ return ret;
+}
+
+static void msm8996_ext_control(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+ pr_debug("%s: msm8996_spk_control = %d", __func__,
+ msm8996_spk_control);
+ if (msm8996_spk_control == MSM8996_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
+ }
+ snd_soc_dapm_sync(dapm);
+}
+
+static int msm8996_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm8996_spk_control = %d\n",
+ __func__, msm8996_spk_control);
+ ucontrol->value.integer.value[0] = msm8996_spk_control;
+ return 0;
+}
+
+static int msm8996_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+ if (msm8996_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm8996_spk_control = ucontrol->value.integer.value[0];
+ msm8996_ext_control(codec);
+ return 1;
+}
+
+static int msm8996_hifi_ctrl(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct snd_soc_card *card = codec->component.card;
+ struct msm8996_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+
+ pr_debug("%s: msm_hifi_control = %d", __func__,
+ msm_hifi_control);
+ if (pdata->hph_en1_gpio < 0) {
+ pr_err("%s: hph_en1_gpio is invalid\n", __func__);
+ return -EINVAL;
+ }
+ if (msm_hifi_control == MSM8996_HIFI_ON) {
+ gpio_direction_output(pdata->hph_en1_gpio, 1);
+ /* 5msec delay needed as per HW requirement */
+ usleep_range(5000, 5010);
+ } else {
+ gpio_direction_output(pdata->hph_en1_gpio, 0);
+ }
+ snd_soc_dapm_sync(dapm);
+ return 0;
+}
+
+static int msm8996_hifi_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_hifi_control = %d\n",
+ __func__, msm_hifi_control);
+ ucontrol->value.integer.value[0] = msm_hifi_control;
+ return 0;
+}
+
+static int msm8996_hifi_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+ pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ msm_hifi_control = ucontrol->value.integer.value[0];
+ msm8996_hifi_ctrl(codec);
+ return 1;
+}
+
+static int msm8996_ext_us_amp_init(void)
+{
+ int ret = 0;
+
+ ext_us_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-ult-spk-amp-gpio", 0);
+ if (ext_us_amp_gpio >= 0) {
+ ret = gpio_request(ext_us_amp_gpio, "ext_us_amp_gpio");
+ if (ret) {
+ pr_err("%s: ext_us_amp_gpio request failed, ret:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ gpio_direction_output(ext_us_amp_gpio, 0);
+ }
+ return ret;
+}
+
+static void msm8996_ext_us_amp_enable(u32 on)
+{
+ if (on)
+ gpio_direction_output(ext_us_amp_gpio, 1);
+ else
+ gpio_direction_output(ext_us_amp_gpio, 0);
+
+ pr_debug("%s: US Emitter GPIO enable:%s\n", __func__,
+ on ? "Enable" : "Disable");
+}
+
+static int msm_ext_ultrasound_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ pr_debug("%s()\n", __func__);
+ if (strcmp(w->name, "ultrasound amp")) {
+ if (!gpio_is_valid(ext_us_amp_gpio)) {
+ pr_err("%s: ext_us_amp_gpio isn't configured\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ msm8996_ext_us_amp_enable(1);
+ else
+ msm8996_ext_us_amp_enable(0);
+ } else {
+ pr_err("%s() Invalid Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ if (!strcmp(dev_name(codec->dev), "tasha_codec")) {
+ ret = tasha_cdc_mclk_enable(codec, enable, dapm);
+ } else {
+ dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int msm8996_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_clk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_clk(codec, 0, true);
+ }
+ return 0;
+}
+
+static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ if (!strcmp(dev_name(codec->dev), "tasha_codec"))
+ ret = tasha_cdc_mclk_tx_enable(codec, enable, dapm);
+ else {
+ dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int msm8996_mclk_tx_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 0, true);
+ }
+ return 0;
+}
+
+static int msm_hifi_ctrl_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct snd_soc_card *card = codec->component.card;
+ struct msm8996_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int ret = 0;
+
+ pr_debug("%s: msm_hifi_control = %d", __func__,
+ msm_hifi_control);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (msm_hifi_control == MSM8996_HIFI_ON) {
+ if (pdata->hph_en0_gpio < 0) {
+ pr_err("%s: hph_en0_gpio is invalid\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ gpio_direction_output(pdata->hph_en0_gpio, 1);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if (msm_hifi_control == MSM8996_HIFI_ON) {
+ if (pdata->hph_en0_gpio < 0) {
+ pr_err("%s: hph_en0_gpio is invalid\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ gpio_direction_output(pdata->hph_en0_gpio, 0);
+ }
+ break;
+ }
+err:
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget msm8996_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ msm8996_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("MCLK TX", SND_SOC_NOPM, 0, 0,
+ msm8996_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
+ SND_SOC_DAPM_SPK("ultrasound amp", msm_ext_ultrasound_event),
+ SND_SOC_DAPM_SPK("hifi amp", msm_hifi_ctrl_event),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic7", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic8", NULL),
+
+ SND_SOC_DAPM_MIC("Digital Mic0", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static struct snd_soc_dapm_route wcd9335_audio_paths[] = {
+ {"MIC BIAS1", NULL, "MCLK TX"},
+ {"MIC BIAS2", NULL, "MCLK TX"},
+ {"MIC BIAS3", NULL, "MCLK TX"},
+ {"MIC BIAS4", NULL, "MCLK TX"},
+};
+
+static int slim5_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim5_rx_sample_rate) {
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim5_rx_sample_rate = %d\n", __func__,
+ slim5_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim5_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ slim5_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 2:
+ slim5_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim5_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim5_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: slim5_rx_sample_rate = %d\n", __func__,
+ slim5_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim6_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim6_rx_sample_rate) {
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim6_rx_sample_rate = %d\n", __func__,
+ slim6_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim6_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ slim6_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 2:
+ slim6_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim6_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim6_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: ucontrol value = %ld, slim6_rx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ slim6_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_tx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (slim0_tx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: slim0_tx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, slim0_tx_bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int slim0_tx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ default:
+ pr_err("%s: invalid value %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ rc = -EINVAL;
+ break;
+ }
+
+ pr_debug("%s: ucontrol value = %ld, slim0_tx_bit_format = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ slim0_tx_bit_format);
+
+ return rc;
+}
+
+static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim0_rx_sample_rate) {
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 6;
+ break;
+
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 5;
+ break;
+
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 4;
+ break;
+
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 6:
+ slim0_rx_sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 5:
+ slim0_rx_sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 4:
+ slim0_rx_sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 3:
+ slim0_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 2:
+ slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim0_tx_sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim0_tx_sample_rate = %d\n", __func__,
+ slim0_tx_sample_rate);
+ return 0;
+}
+
+static int slim0_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim0_tx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim0_tx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ slim0_tx_sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ default:
+ rc = -EINVAL;
+ pr_err("%s: invalid sample rate being passed\n", __func__);
+ break;
+ }
+
+ pr_debug("%s: slim0_tx_sample_rate = %d\n", __func__,
+ slim0_tx_sample_rate);
+ return rc;
+}
+
+static int slim5_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (slim5_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: slim5_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, slim5_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int slim5_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ slim5_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return 0;
+}
+
+static int slim6_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (slim6_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: slim6_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, slim6_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int slim6_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ slim6_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return 0;
+}
+
+static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (slim0_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, slim0_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return 0;
+}
+
+static int msm_slim_5_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_5_rx_ch = %d\n", __func__,
+ msm_slim_5_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_5_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_5_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_5_rx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_slim_5_rx_ch = %d\n", __func__,
+ msm_slim_5_rx_ch);
+ return 1;
+}
+
+static int msm_slim_6_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_6_rx_ch = %d\n", __func__,
+ msm_slim_6_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_6_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_6_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_6_rx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_slim_6_rx_ch = %d\n", __func__,
+ msm_slim_6_rx_ch);
+ return 1;
+}
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+ msm_slim_0_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+ msm_slim_0_rx_ch);
+ return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+ msm_slim_0_tx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__, msm_slim_0_tx_ch);
+ return 1;
+}
+
+static int msm_slim_1_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__,
+ msm_slim_1_tx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_1_tx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_1_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_1_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__, msm_slim_1_tx_ch);
+ return 1;
+}
+
+static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
+ pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
+ return 1;
+}
+
+static int hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (hdmi_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
+ msm_hdmi_rx_ch);
+ ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+ if (msm_hdmi_rx_ch > 8) {
+ pr_err("%s: channels %d exceeded 8.Limiting to max chs-8\n",
+ __func__, msm_hdmi_rx_ch);
+ msm_hdmi_rx_ch = 8;
+ }
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, msm_hdmi_rx_ch);
+
+ return 1;
+}
+
+static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (hdmi_rx_sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
+ hdmi_rx_sample_rate);
+
+ return 0;
+}
+
+static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ hdmi_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ hdmi_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
+ hdmi_rx_sample_rate);
+
+ return 0;
+}
+
+static int msm8996_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm8996_auxpcm_rate;
+ return 0;
+}
+
+static int msm8996_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ msm8996_auxpcm_rate = SAMPLING_RATE_16KHZ;
+ break;
+ default:
+ msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ return 0;
+}
+
+static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, msm_proxy_rx_ch);
+ ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1;
+ return 0;
+}
+
+static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, msm_proxy_rx_ch);
+ return 1;
+}
+
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm8996_auxpcm_rate;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
+
+static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
+
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ channels->min = channels->max = msm_proxy_rx_ch;
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ return 0;
+}
+
+static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ return 0;
+}
+
+static int msm8996_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+ channels->min, channels->max);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ hdmi_rx_bit_format);
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ rate->min = rate->max = hdmi_rx_sample_rate;
+ channels->min = channels->max = msm_hdmi_rx_ch;
+
+ return 0;
+}
+
+static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s: channel:%d\n", __func__, msm_tert_mi2s_tx_ch);
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ channels->min = channels->max = msm_tert_mi2s_tx_ch;
+ return 0;
+}
+
+static int msm8996_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ pr_debug("%s: substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ mi2s_tx_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX,
+ &mi2s_tx_clk);
+ if (ret < 0) {
+ pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret);
+ goto err;
+ }
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("%s: set fmt cpu dai failed, err:%d\n", __func__, ret);
+err:
+ return ret;
+}
+
+static void msm8996_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ pr_debug("%s: substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ mi2s_tx_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX,
+ &mi2s_tx_clk);
+ if (ret < 0)
+ pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret);
+}
+
+static struct snd_soc_ops msm8996_mi2s_be_ops = {
+ .startup = msm8996_mi2s_snd_startup,
+ .shutdown = msm8996_mi2s_snd_shutdown,
+};
+
+static int msm_slim_5_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim5_rx_bit_format);
+ rate->min = rate->max = slim5_rx_sample_rate;
+ channels->min = channels->max = msm_slim_5_rx_ch;
+
+ pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+ __func__, params_format(params), params_rate(params),
+ msm_slim_5_rx_ch);
+
+ return 0;
+}
+
+static int msm_slim_6_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim6_rx_bit_format);
+ rate->min = rate->max = slim6_rx_sample_rate;
+ channels->min = channels->max = msm_slim_6_rx_ch;
+
+ pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+ __func__, params_format(params), params_rate(params),
+ msm_slim_6_rx_ch);
+
+ return 0;
+}
+
+static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim0_rx_bit_format);
+ rate->min = rate->max = slim0_rx_sample_rate;
+ channels->min = channels->max = msm_slim_0_rx_ch;
+
+ pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+ __func__, params_format(params), params_rate(params),
+ msm_slim_0_rx_ch);
+
+ return 0;
+}
+
+static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, slim0_tx_bit_format);
+ rate->min = rate->max = slim0_tx_sample_rate;
+ channels->min = channels->max = msm_slim_0_tx_ch;
+
+ return 0;
+}
+
+static int msm_slim_1_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, slim1_tx_bit_format);
+ rate->min = rate->max = slim1_tx_sample_rate;
+ channels->min = channels->max = msm_slim_1_tx_ch;
+
+ return 0;
+}
+
+static int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FORMAT_S32_LE);
+
+ rate->min = rate->max = SAMPLING_RATE_8KHZ;
+ channels->min = channels->max = msm_vi_feed_tx_ch;
+ pr_debug("%s: msm_vi_feed_tx_ch: %d\n", __func__, msm_vi_feed_tx_ch);
+
+ return 0;
+}
+
+static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ int rc = 0;
+ void *config = NULL;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s: enter\n", __func__);
+ rate->min = rate->max = SAMPLING_RATE_16KHZ;
+ channels->min = channels->max = 1;
+
+ config = msm8996_codec_fn.get_afe_config_fn(codec,
+ AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ if (config) {
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+ SLIMBUS_5_TX);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ }
+ }
+
+ return rc;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ pr_debug("%s:\n", __func__);
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ return 0;
+}
+
+static const struct soc_enum msm_snd_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+ SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(8, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_bit_format_text),
+ rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim0_rx_sample_rate_text),
+ slim0_rx_sample_rate_text),
+ SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(3, hdmi_rx_sample_rate_text),
+ SOC_ENUM_SINGLE_EXT(4, slim5_rx_sample_rate_text),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim5_rx_bit_format_text),
+ slim5_rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(2, slim5_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, hifi_function),
+ SOC_ENUM_SINGLE_EXT(2, vi_feed_ch_text),
+ SOC_ENUM_SINGLE_EXT(4, slim6_rx_sample_rate_text),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim6_rx_bit_format_text),
+ slim6_rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(2, slim6_rx_ch_text),
+};
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8996_get_spk,
+ msm8996_set_spk),
+ SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
+ msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_5_RX Channels", msm_snd_enum[10],
+ msm_slim_5_rx_ch_get, msm_slim_5_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_6_RX Channels", msm_snd_enum[15],
+ msm_slim_6_rx_ch_get, msm_slim_6_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
+ msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_1_TX Channels", msm_snd_enum[2],
+ msm_slim_1_tx_ch_get, msm_slim_1_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", msm8996_auxpcm_enum[0],
+ msm8996_auxpcm_rate_get,
+ msm8996_auxpcm_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
+ msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
+ slim0_rx_bit_format_get, slim0_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_5_RX Format", msm_snd_enum[9],
+ slim5_rx_bit_format_get, slim5_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_6_RX Format", msm_snd_enum[14],
+ slim6_rx_bit_format_get, slim6_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
+ slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_5_RX SampleRate", msm_snd_enum[8],
+ slim5_rx_sample_rate_get, slim5_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_6_RX SampleRate", msm_snd_enum[13],
+ slim6_rx_sample_rate_get, slim6_rx_sample_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
+ hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
+ SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
+ msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
+ SOC_ENUM_EXT("HDMI_RX SampleRate", msm_snd_enum[7],
+ hdmi_rx_sample_rate_get, hdmi_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_0_TX SampleRate", msm_snd_enum[5],
+ slim0_tx_sample_rate_get, slim0_tx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_0_TX Format", msm_snd_enum[4],
+ slim0_tx_bit_format_get, slim0_tx_bit_format_put),
+ SOC_ENUM_EXT("HiFi Function", msm_snd_enum[11], msm8996_hifi_get,
+ msm8996_hifi_put),
+ SOC_ENUM_EXT("VI_FEED_TX Channels", msm_snd_enum[12],
+ msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+};
+
+static bool msm8996_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm8996_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+ return true;
+}
+
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+ int rc;
+ void *config_data = NULL;
+
+ pr_debug("%s: enter\n", __func__);
+
+ if (!msm8996_codec_fn.get_afe_config_fn) {
+ dev_err(codec->dev, "%s: codec get afe config not init'ed\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ config_data = msm8996_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTERS_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm8996_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTER_PAGE_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
+ 0);
+ if (rc)
+ pr_err("%s: Failed to set cdc register page config\n",
+ __func__);
+ }
+
+ config_data = msm8996_codec_fn.get_afe_config_fn(codec,
+ AFE_SLIMBUS_SLAVE_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave config %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+ afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+ afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+}
+
+static int msm8996_adsp_state_callback(struct notifier_block *nb,
+ unsigned long value, void *priv)
+{
+ if (value == SUBSYS_BEFORE_SHUTDOWN) {
+ pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
+ __func__);
+ msm_afe_clear_config();
+ } else if (value == SUBSYS_AFTER_POWERUP) {
+ pr_debug("%s: ADSP is up\n", __func__);
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+ .notifier_call = msm8996_adsp_state_callback,
+ .priority = -INT_MAX,
+};
+
+static int msm8996_wcd93xx_codec_up(struct snd_soc_codec *codec)
+{
+ int err;
+ unsigned long timeout;
+ int adsp_ready = 0;
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+ do {
+ if (!q6core_is_adsp_ready()) {
+ pr_err_ratelimited("%s: ADSP Audio isn't ready\n",
+ __func__);
+ /*
+ * ADSP will be coming up after subsystem restart and
+ * it might not be fully up when the control reaches
+ * here. So, wait for 50msec before checking ADSP state
+ */
+ msleep(50);
+ } else {
+ pr_debug("%s: ADSP Audio is ready\n", __func__);
+ adsp_ready = 1;
+ break;
+ }
+ } while (time_after(timeout, jiffies));
+
+ if (!adsp_ready) {
+ pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ err = msm_afe_set_config(codec);
+ if (err)
+ pr_err("%s: Failed to set AFE config. err %d\n",
+ __func__, err);
+ return err;
+}
+
+static int msm8996_tasha_codec_event_cb(struct snd_soc_codec *codec,
+ enum wcd9335_codec_event codec_event)
+{
+ switch (codec_event) {
+ case WCD9335_CODEC_EVENT_CODEC_UP:
+ return msm8996_wcd93xx_codec_up(codec);
+ default:
+ pr_err("%s: UnSupported codec event %d\n",
+ __func__, codec_event);
+ return -EINVAL;
+ }
+}
+
+static int msm8996_config_hph_en0_gpio(struct snd_soc_codec *codec, bool high)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm8996_asoc_mach_data *pdata;
+ int val;
+
+ if (!card)
+ return 0;
+
+ pdata = snd_soc_card_get_drvdata(card);
+ if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio))
+ return 0;
+
+ val = gpio_get_value_cansleep(pdata->hph_en0_gpio);
+ if ((!!val) == high)
+ return 0;
+
+ gpio_direction_output(pdata->hph_en0_gpio, (int)high);
+
+ return 1;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err;
+ void *config_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux;
+ void *mbhc_calibration;
+ struct snd_card *card;
+ struct snd_info_entry *entry;
+ struct msm8996_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(rtd->card);
+
+ /* Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+ pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ rtd->pmdown_time = 0;
+
+ err = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (err < 0) {
+ pr_err("%s: add_codec_controls failed, err %d\n",
+ __func__, err);
+ return err;
+ }
+
+ err = msm8996_liquid_init_docking();
+ if (err) {
+ pr_err("%s: 8996 init Docking stat IRQ failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ err = msm8996_ext_us_amp_init();
+ if (err) {
+ pr_err("%s: 8996 US Emitter GPIO init failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ snd_soc_dapm_new_controls(dapm, msm8996_dapm_widgets,
+ ARRAY_SIZE(msm8996_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, wcd9335_audio_paths,
+ ARRAY_SIZE(wcd9335_audio_paths));
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_1 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_3 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_2 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_4 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "ultrasound amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic7");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic8");
+ snd_soc_dapm_ignore_suspend(dapm, "MADINPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC6");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC0");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
+ snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+
+ snd_soc_dapm_sync(dapm);
+
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+ msm8996_codec_fn.get_afe_config_fn = tasha_get_afe_config;
+ msm8996_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit;
+
+ err = msm_afe_set_config(codec);
+ if (err) {
+ pr_err("%s: Failed to set AFE config %d\n", __func__, err);
+ goto out;
+ }
+
+ config_data = msm8996_codec_fn.get_afe_config_fn(codec,
+ AFE_AANC_VERSION);
+ if (config_data) {
+ err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, err);
+ goto out;
+ }
+ }
+ config_data = msm8996_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, err);
+ goto out;
+ }
+ }
+ config_data = msm8996_codec_fn.get_afe_config_fn(codec,
+ AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, err);
+ goto out;
+ }
+ }
+ /* Start mbhc */
+ tasha_mbhc_zdet_gpio_ctrl(msm8996_config_hph_en0_gpio, rtd->codec);
+ mbhc_calibration = def_tasha_mbhc_cal();
+ if (mbhc_calibration) {
+ wcd_mbhc_cfg.calibration = mbhc_calibration;
+ err = tasha_mbhc_hs_detect(codec, &wcd_mbhc_cfg);
+ if (err) {
+ pr_err("%s: mbhc hs detect failed, err:%d\n",
+ __func__, err);
+ goto out;
+ }
+ } else {
+ pr_err("%s: mbhc_cfg calibration is NULL\n", __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+ adsp_state_notifier = subsys_notif_register_notifier("adsp",
+ &adsp_state_notifier_block);
+ if (!adsp_state_notifier) {
+ pr_err("%s: Failed to register adsp state notifier\n",
+ __func__);
+ err = -EFAULT;
+ msm8996_codec_fn.mbhc_hs_detect_exit(codec);
+ goto out;
+ }
+
+ tasha_event_register(msm8996_tasha_codec_event_cb, rtd->codec);
+
+ /*
+ * Send speaker configuration only for WSA8810.
+ * Defalut configuration is for WSA8815.
+ */
+ if (rtd_aux && rtd_aux->component)
+ if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
+ !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
+ tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+ tasha_set_spkr_gain_offset(rtd->codec,
+ RX_GAIN_OFFSET_M1P5_DB);
+ }
+ codec_reg_done = true;
+
+ card = rtd->card->snd_card;
+ entry = snd_info_create_subdir(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ err = 0;
+ goto out;
+ }
+ pdata->codec_root = entry;
+ tasha_codec_info_create_codec_entry(pdata->codec_root, codec);
+
+ return 0;
+out:
+ return err;
+}
+
+static void *def_tasha_mbhc_cal(void)
+{
+ void *tasha_wcd_cal;
+ struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_high;
+
+ tasha_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
+ if (!tasha_wcd_cal)
+ return NULL;
+
+#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tasha_wcd_cal)->X) = (Y))
+ S(v_hs_max, 1500);
+#undef S
+#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal)->X) = (Y))
+ S(num_btn, WCD_MBHC_DEF_BUTTONS);
+#undef S
+
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal);
+ btn_high = ((void *)&btn_cfg->_v_btn_low) +
+ (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+ btn_high[0] = 75;
+ btn_high[1] = 150;
+ btn_high[2] = 237;
+ btn_high[3] = 500;
+ btn_high[4] = 500;
+ btn_high[5] = 500;
+ btn_high[6] = 500;
+ btn_high[7] = 500;
+
+ return tasha_wcd_cal;
+}
+
+static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ int ret = 0;
+ u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ u32 user_set_tx_ch = 0;
+ u32 rx_ch_count;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_5_RX) {
+ pr_debug("%s: rx_5_ch=%d\n", __func__,
+ msm_slim_5_rx_ch);
+ rx_ch_count = msm_slim_5_rx_ch;
+ } else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_6_RX) {
+ pr_debug("%s: rx_6_ch=%d\n", __func__,
+ msm_slim_6_rx_ch);
+ rx_ch_count = msm_slim_6_rx_ch;
+ } else {
+ pr_debug("%s: rx_0_ch=%d\n", __func__,
+ msm_slim_0_rx_ch);
+ rx_ch_count = msm_slim_0_rx_ch;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ rx_ch_count, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+
+ pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+ codec_dai->name, codec_dai->id, user_set_tx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ /* For <codec>_tx1 case */
+ if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_0_TX)
+ user_set_tx_ch = msm_slim_0_tx_ch;
+ /* For <codec>_tx3 case */
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_1_TX)
+ user_set_tx_ch = msm_slim_1_tx_ch;
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_3_TX)
+ /* DAI 5 is used for external EC reference from codec.
+ * Since Rx is fed as reference for EC, the config of
+ * this DAI is based on that of the Rx path.
+ */
+ user_set_tx_ch = msm_slim_0_rx_ch;
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_4_TX)
+ user_set_tx_ch = msm_vi_feed_tx_ch;
+ else
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), be_id (%d)\n",
+ __func__, msm_slim_0_tx_ch, user_set_tx_ch,
+ tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ int ret = 0;
+ u32 tx_ch[SLIM_MAX_TX_PORTS];
+ u32 tx_ch_cnt = 0;
+ u32 user_set_tx_ch = 0;
+
+ if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("%s: Invalid stream type %d\n",
+ __func__, substream->stream);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pr_debug("%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, NULL, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0, 0);
+ if (ret < 0)
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+end:
+ return ret;
+}
+
+static struct snd_soc_ops msm8996_be_ops = {
+ .hw_params = msm_snd_hw_params,
+};
+
+static struct snd_soc_ops msm8996_cpe_ops = {
+ .hw_params = msm_snd_cpe_hw_params,
+};
+
+static int msm8996_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ num_rx_ch = params_channels(params);
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ num_tx_ch = params_channels(params);
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static struct snd_soc_ops msm8996_slimbus_2_be_ops = {
+ .hw_params = msm8996_slimbus_2_hw_params,
+};
+
+static int msm8996_get_ll_qos_val(struct snd_pcm_runtime *runtime)
+{
+ int usecs;
+
+ /* take 10% of period time as the deadline */
+ usecs = (100000 / runtime->rate) * runtime->period_size;
+ usecs += ((100000 % runtime->rate) * runtime->period_size) /
+ runtime->rate;
+
+ return usecs;
+}
+
+static int msm8996_mm5_prepare(struct snd_pcm_substream *substream)
+{
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
+ pm_qos_add_request(&substream->latency_pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ msm8996_get_ll_qos_val(substream->runtime));
+ return 0;
+}
+
+static struct snd_soc_ops msm8996_mm5_ops = {
+ .prepare = msm8996_mm5_prepare,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm8996_common_dai_links[] = {
+ /* FrontEnd DAI Links */
+ {
+ .name = "MSM8996 Media1",
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {
+ .name = "MSM8996 Media2",
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {
+ .name = "VoiceMMode1",
+ .stream_name = "VoiceMMode1",
+ .cpu_dai_name = "VoiceMMode1",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE1,
+ },
+ {
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {
+ .name = "MSM8996 ULL",
+ .stream_name = "MultiMedia3",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-dsp.2",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "Tertiary MI2S TX_Hostless",
+ .stream_name = "Tertiary MI2S_TX Hostless Capture",
+ .cpu_dai_name = "TERT_MI2S_TX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "MSM8996 Compress1",
+ .stream_name = "Compress1",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
+ {
+ .name = "MSM8996 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ .ops = &msm8996_mm5_ops,
+ },
+ {
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ /* Multiple Tunnel instances */
+ {
+ .name = "MSM8996 Compress2",
+ .stream_name = "Compress2",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {
+ .name = "MSM8996 Compress3",
+ .stream_name = "Compress3",
+ .cpu_dai_name = "MultiMedia10",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+ },
+ {
+ .name = "MSM8996 ULL NOIRQ",
+ .stream_name = "MM_NOIRQ",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-pcm-dsp-noirq",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
+ {
+ .name = "QCHAT",
+ .stream_name = "QCHAT",
+ .cpu_dai_name = "QCHAT",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_QCHAT,
+ },
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "VoiceMMode2",
+ .stream_name = "VoiceMMode2",
+ .cpu_dai_name = "VoiceMMode2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE2,
+ },
+ {
+ .name = "INT_HFP_BT Hostless",
+ .stream_name = "INT_HFP_BT Hostless",
+ .cpu_dai_name = "INT_HFP_BT_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM8996 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+ /* LSM FE */
+ {
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM6,
+ },
+ {
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {
+ .name = "MSM8996 Media9",
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
+ {
+ .name = "VoWLAN",
+ .stream_name = "VoWLAN",
+ .cpu_dai_name = "VoWLAN",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOWLAN,
+ },
+ {
+ .name = "MSM8996 Compress4",
+ .stream_name = "Compress4",
+ .cpu_dai_name = "MultiMedia11",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA11,
+ },
+ {
+ .name = "MSM8996 Compress5",
+ .stream_name = "Compress5",
+ .cpu_dai_name = "MultiMedia12",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA12,
+ },
+ {
+ .name = "MSM8996 Compress6",
+ .stream_name = "Compress6",
+ .cpu_dai_name = "MultiMedia13",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA13,
+ },
+ {
+ .name = "MSM8996 Compress7",
+ .stream_name = "Compress7",
+ .cpu_dai_name = "MultiMedia14",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+ },
+ {
+ .name = "MSM8996 Compress8",
+ .stream_name = "Compress8",
+ .cpu_dai_name = "MultiMedia15",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15,
+ },
+ {
+ .name = "MSM8996 Compress9",
+ .stream_name = "Compress9",
+ .cpu_dai_name = "MultiMedia16",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA16,
+ },
+ {
+ .name = "Circuit-Switch Voice",
+ .stream_name = "CS-Voice",
+ .cpu_dai_name = "CS-VOICE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_CS_VOICE,
+ },
+ {
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICE2,
+ },
+};
+
+static struct snd_soc_dai_link msm8996_tasha_fe_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm8996_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm8996_slimbus_2_be_ops,
+ },
+ /* CPE LSM direct dai-link */
+ {
+ .name = "CPE Listen service",
+ .stream_name = "CPE Listen Audio Service",
+ .cpu_dai_name = "msm-dai-slim",
+ .platform_name = "msm-cpe-lsm",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "tasha_mad1",
+ .codec_name = "tasha_codec",
+ .ops = &msm8996_cpe_ops,
+ },
+ /* slimbus rx 6 hostless */
+ {
+ .name = "SLIMBUS_6 Hostless Playback",
+ .stream_name = "SLIMBUS_6 Hostless",
+ .cpu_dai_name = "SLIMBUS6_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* CPE LSM EC PP direct dai-link */
+ {
+ .name = "CPE Listen service ECPP",
+ .stream_name = "CPE Listen Audio Service ECPP",
+ .cpu_dai_name = "CPE_LSM_NOHOST",
+ .platform_name = "msm-cpe-lsm.3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "tasha_cpe",
+ .codec_name = "tasha_codec",
+ },
+};
+
+static struct snd_soc_dai_link msm8996_common_be_dai_links[] = {
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Primary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_TX,
+ .stream_name = "Tertiary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ .be_hw_params_fixup = msm_tx_be_hw_params_fixup,
+ .ops = &msm8996_mi2s_be_ops,
+ .ignore_suspend = 1,
+ }
+};
+
+static struct snd_soc_dai_link msm8996_tasha_be_dai_links[] = {
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm8996_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm8996_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx3",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_slim_1_tx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_5_RX,
+ .stream_name = "Slimbus5 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16394",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ .be_hw_params_fixup = msm_slim_5_rx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mad1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_6_RX,
+ .stream_name = "Slimbus6 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16396",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx4",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ .be_hw_params_fixup = msm_slim_6_rx_be_hw_params_fixup,
+ .ops = &msm8996_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm8996_hdmi_dai_link[] = {
+ /* HDMI BACK END DAI Link */
+ {
+ .name = LPASS_BE_HDMI,
+ .stream_name = "HDMI Playback",
+ .cpu_dai_name = "msm-dai-q6-hdmi.8",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-hdmi-audio-codec-rx",
+ .codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_HDMI_RX,
+ .be_hw_params_fixup = msm8996_hdmi_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm8996_tasha_dai_links[
+ ARRAY_SIZE(msm8996_common_dai_links) +
+ ARRAY_SIZE(msm8996_tasha_fe_dai_links) +
+ ARRAY_SIZE(msm8996_common_be_dai_links) +
+ ARRAY_SIZE(msm8996_tasha_be_dai_links) +
+ ARRAY_SIZE(msm8996_hdmi_dai_link)];
+
+static int msm8996_wsa881x_init(struct snd_soc_component *component)
+{
+ u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106};
+ u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107};
+ unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
+ unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+ struct msm8996_asoc_mach_data *pdata;
+ struct snd_soc_dapm_context *dapm;
+
+ if (!codec) {
+ pr_err("%s codec is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dapm = snd_soc_codec_get_dapm(codec);
+
+ if (!strcmp(component->name_prefix, "SpkrLeft")) {
+ dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n",
+ __func__, codec->component.name);
+ wsa881x_set_channel_map(codec, &spkleft_ports[0],
+ WSA881X_MAX_SWR_PORTS, &ch_mask[0],
+ &ch_rate[0]);
+ if (dapm->component) {
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
+ }
+ } else if (!strcmp(component->name_prefix, "SpkrRight")) {
+ dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n",
+ __func__, codec->component.name);
+ wsa881x_set_channel_map(codec, &spkright_ports[0],
+ WSA881X_MAX_SWR_PORTS, &ch_mask[0],
+ &ch_rate[0]);
+ if (dapm->component) {
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
+ }
+ } else {
+ dev_err(codec->dev, "%s: wrong codec name %s\n", __func__,
+ codec->component.name);
+ return -EINVAL;
+ }
+ pdata = snd_soc_card_get_drvdata(component->card);
+ if (pdata && pdata->codec_root)
+ wsa881x_codec_info_create_codec_entry(pdata->codec_root,
+ codec);
+
+ return 0;
+}
+
+struct snd_soc_card snd_soc_card_tasha_msm8996 = {
+ .name = "msm8996-tasha-snd-card",
+};
+
+static int msm8996_populate_dai_link_component_of_node(
+ struct snd_soc_card *card)
+{
+ int i, index, ret = 0;
+ struct device *cdev = card->dev;
+ struct snd_soc_dai_link *dai_link = card->dai_link;
+ struct device_node *np;
+
+ if (!cdev) {
+ pr_err("%s: Sound card device memory NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < card->num_links; i++) {
+ if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
+ continue;
+
+ /* populate platform_of_node for snd card dai links */
+ if (dai_link[i].platform_name &&
+ !dai_link[i].platform_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-platform-names",
+ dai_link[i].platform_name);
+ if (index < 0) {
+ pr_err("%s: No match found for platform name: %s\n",
+ __func__, dai_link[i].platform_name);
+ ret = index;
+ goto err;
+ }
+ np = of_parse_phandle(cdev->of_node, "asoc-platform",
+ index);
+ if (!np) {
+ pr_err("%s: retrieving phandle for platform %s, index %d failed\n",
+ __func__, dai_link[i].platform_name,
+ index);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].platform_of_node = np;
+ dai_link[i].platform_name = NULL;
+ }
+
+ /* populate cpu_of_node for snd card dai links */
+ if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-cpu-names",
+ dai_link[i].cpu_dai_name);
+ if (index >= 0) {
+ np = of_parse_phandle(cdev->of_node, "asoc-cpu",
+ index);
+ if (!np) {
+ pr_err("%s: retrieving phandle for cpu dai %s failed\n",
+ __func__,
+ dai_link[i].cpu_dai_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].cpu_of_node = np;
+ dai_link[i].cpu_dai_name = NULL;
+ }
+ }
+
+ /* populate codec_of_node for snd card dai links */
+ if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-codec-names",
+ dai_link[i].codec_name);
+ if (index < 0)
+ continue;
+ np = of_parse_phandle(cdev->of_node, "asoc-codec",
+ index);
+ if (!np) {
+ pr_err("%s: retrieving phandle for codec %s failed\n",
+ __func__, dai_link[i].codec_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].codec_of_node = np;
+ dai_link[i].codec_name = NULL;
+ }
+ }
+
+err:
+ return ret;
+}
+
+static int msm8996_prepare_us_euro(struct snd_soc_card *card)
+{
+ struct msm8996_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (pdata->us_euro_gpio >= 0) {
+ dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__,
+ pdata->us_euro_gpio);
+ ret = gpio_request(pdata->us_euro_gpio, "TASHA_CODEC_US_EURO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request codec US/EURO gpio %d error %d\n",
+ __func__, pdata->us_euro_gpio, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int msm8996_prepare_hifi(struct snd_soc_card *card)
+{
+ struct msm8996_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (gpio_is_valid(pdata->hph_en1_gpio)) {
+ dev_dbg(card->dev, "%s: hph_en1_gpio request %d\n", __func__,
+ pdata->hph_en1_gpio);
+ ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: hph_en1_gpio request failed, ret:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+ if (gpio_is_valid(pdata->hph_en0_gpio)) {
+ dev_dbg(card->dev, "%s: hph_en0_gpio request %d\n", __func__,
+ pdata->hph_en0_gpio);
+ ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: hph_en0_gpio request failed, ret:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static const struct of_device_id msm8996_asoc_machine_of_match[] = {
+ { .compatible = "qcom,msm8996-asoc-snd-tasha",
+ .data = "tasha_codec"},
+ {},
+};
+
+static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
+{
+ struct snd_soc_card *card = NULL;
+ struct snd_soc_dai_link *dailink;
+ int len_1, len_2, len_3, len_4;
+ const struct of_device_id *match;
+
+ match = of_match_node(msm8996_asoc_machine_of_match, dev->of_node);
+ if (!match) {
+ dev_err(dev, "%s: No DT match found for sound card\n",
+ __func__);
+ return NULL;
+ }
+
+ if (!strcmp(match->data, "tasha_codec")) {
+ card = &snd_soc_card_tasha_msm8996;
+ len_1 = ARRAY_SIZE(msm8996_common_dai_links);
+ len_2 = len_1 + ARRAY_SIZE(msm8996_tasha_fe_dai_links);
+ len_3 = len_2 + ARRAY_SIZE(msm8996_common_be_dai_links);
+
+ memcpy(msm8996_tasha_dai_links,
+ msm8996_common_dai_links,
+ sizeof(msm8996_common_dai_links));
+ memcpy(msm8996_tasha_dai_links + len_1,
+ msm8996_tasha_fe_dai_links,
+ sizeof(msm8996_tasha_fe_dai_links));
+ memcpy(msm8996_tasha_dai_links + len_2,
+ msm8996_common_be_dai_links,
+ sizeof(msm8996_common_be_dai_links));
+ memcpy(msm8996_tasha_dai_links + len_3,
+ msm8996_tasha_be_dai_links,
+ sizeof(msm8996_tasha_be_dai_links));
+
+ dailink = msm8996_tasha_dai_links;
+ len_4 = len_3 + ARRAY_SIZE(msm8996_tasha_be_dai_links);
+ }
+
+ if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) {
+ dev_dbg(dev, "%s(): hdmi audio support present\n",
+ __func__);
+ memcpy(dailink + len_4, msm8996_hdmi_dai_link,
+ sizeof(msm8996_hdmi_dai_link));
+ len_4 += ARRAY_SIZE(msm8996_hdmi_dai_link);
+ } else {
+ dev_dbg(dev, "%s(): No hdmi audio support\n", __func__);
+ }
+
+ if (card) {
+ card->dai_link = dailink;
+ card->num_links = len_4;
+ }
+
+ return card;
+}
+
+static int msm8996_init_wsa_dev(struct platform_device *pdev,
+ struct snd_soc_card *card)
+{
+ struct device_node *wsa_of_node;
+ u32 wsa_max_devs;
+ u32 wsa_dev_cnt;
+ char *dev_name_str = NULL;
+ struct msm8996_wsa881x_dev_info *wsa881x_dev_info;
+ const char *wsa_auxdev_name_prefix[1];
+ int found = 0;
+ int i;
+ int ret;
+
+ /* Get maximum WSA device count for this platform */
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,wsa-max-devs", &wsa_max_devs);
+ if (ret) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa-max-devs property missing in DT %s, ret = %d\n",
+ __func__, pdev->dev.of_node->full_name, ret);
+ return 0;
+ }
+ if (wsa_max_devs == 0) {
+ dev_warn(&pdev->dev,
+ "%s: Max WSA devices is 0 for this target?\n",
+ __func__);
+ return 0;
+ }
+
+ /* Get count of WSA device phandles for this platform */
+ wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
+ "qcom,wsa-devs", NULL);
+ if (wsa_dev_cnt == -ENOENT) {
+ dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
+ __func__);
+ return 0;
+ } else if (wsa_dev_cnt <= 0) {
+ dev_err(&pdev->dev,
+ "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
+ __func__, wsa_dev_cnt);
+ return -EINVAL;
+ }
+
+ /*
+ * Expect total phandles count to be NOT less than maximum possible
+ * WSA count. However, if it is less, then assign same value to
+ * max count as well.
+ */
+ if (wsa_dev_cnt < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
+ __func__, wsa_max_devs, wsa_dev_cnt);
+ wsa_max_devs = wsa_dev_cnt;
+ }
+
+ /* Make sure prefix string passed for each WSA device */
+ ret = of_property_count_strings(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix");
+ if (ret != wsa_dev_cnt) {
+ dev_err(&pdev->dev,
+ "%s: expecting %d wsa prefix. Defined only %d in DT\n",
+ __func__, wsa_dev_cnt, ret);
+ return -EINVAL;
+ }
+
+ /*
+ * Alloc mem to store phandle and index info of WSA device, if already
+ * registered with ALSA core
+ */
+ wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
+ sizeof(struct msm8996_wsa881x_dev_info),
+ GFP_KERNEL);
+ if (!wsa881x_dev_info)
+ return -ENOMEM;
+
+ /*
+ * search and check whether all WSA devices are already
+ * registered with ALSA core or not. If found a node, store
+ * the node and the index in a local array of struct for later
+ * use.
+ */
+ for (i = 0; i < wsa_dev_cnt; i++) {
+ wsa_of_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,wsa-devs", i);
+ if (unlikely(!wsa_of_node)) {
+ /* we should not be here */
+ dev_err(&pdev->dev,
+ "%s: wsa dev node is not present\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (soc_find_component(wsa_of_node, NULL)) {
+ /* WSA device registered with ALSA core */
+ wsa881x_dev_info[found].of_node = wsa_of_node;
+ wsa881x_dev_info[found].index = i;
+ found++;
+ if (found == wsa_max_devs)
+ break;
+ }
+ }
+
+ if (found < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: failed to find %d components. Found only %d\n",
+ __func__, wsa_max_devs, found);
+ return -EPROBE_DEFER;
+ }
+ dev_info(&pdev->dev,
+ "%s: found %d wsa881x devices registered with ALSA core\n",
+ __func__, found);
+
+ card->num_aux_devs = wsa_max_devs;
+ card->num_configs = wsa_max_devs;
+
+ /* Alloc array of AUX devs struct */
+ msm8996_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_aux_dev),
+ GFP_KERNEL);
+ if (!msm8996_aux_dev)
+ return -ENOMEM;
+
+ /* Alloc array of codec conf struct */
+ msm8996_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_codec_conf),
+ GFP_KERNEL);
+ if (!msm8996_codec_conf)
+ return -ENOMEM;
+
+ for (i = 0; i < card->num_aux_devs; i++) {
+ dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
+ GFP_KERNEL);
+ if (!dev_name_str)
+ return -ENOMEM;
+
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix",
+ wsa881x_dev_info[i].index,
+ wsa_auxdev_name_prefix);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: failed to read wsa aux dev prefix, ret = %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
+ msm8996_aux_dev[i].name = dev_name_str;
+ msm8996_aux_dev[i].codec_name = NULL;
+ msm8996_aux_dev[i].codec_of_node =
+ wsa881x_dev_info[i].of_node;
+ msm8996_aux_dev[i].init = msm8996_wsa881x_init;
+ msm8996_codec_conf[i].dev_name = NULL;
+ msm8996_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0];
+ msm8996_codec_conf[i].of_node =
+ wsa881x_dev_info[i].of_node;
+ }
+ card->codec_conf = msm8996_codec_conf;
+ card->aux_dev = msm8996_aux_dev;
+
+ return 0;
+}
+
+static int msm8996_asoc_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct msm8996_asoc_mach_data *pdata;
+ const char *mbhc_audio_jack_type = NULL;
+ char *mclk_freq_prop_name;
+ const struct of_device_id *match;
+ int ret;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "No platform supplied from device tree\n");
+ return -EINVAL;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm8996_asoc_mach_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ card = populate_snd_card_dailinks(&pdev->dev);
+ if (!card) {
+ dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, pdata);
+
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret) {
+ dev_err(&pdev->dev, "parse card name failed, err:%d\n",
+ ret);
+ goto err;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "parse audio routing failed, err:%d\n",
+ ret);
+ goto err;
+ }
+
+ match = of_match_node(msm8996_asoc_machine_of_match,
+ pdev->dev.of_node);
+ if (!match) {
+ dev_err(&pdev->dev, "%s: no matched codec is found.\n",
+ __func__);
+ goto err;
+ }
+
+ mclk_freq_prop_name = "qcom,tasha-mclk-clk-freq";
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ mclk_freq_prop_name, &pdata->mclk_freq);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed, err%d\n",
+ mclk_freq_prop_name,
+ pdev->dev.of_node->full_name, ret);
+ goto err;
+ }
+
+ if (pdata->mclk_freq != CODEC_EXT_CLK_RATE) {
+ dev_err(&pdev->dev, "unsupported mclk freq %u\n",
+ pdata->mclk_freq);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ spdev = pdev;
+
+ ret = msm8996_populate_dai_link_component_of_node(card);
+ if (ret) {
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+
+ ret = msm8996_init_wsa_dev(pdev, card);
+ if (ret)
+ goto err;
+
+ pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,hph-en1-gpio", 0);
+ if (pdata->hph_en1_gpio < 0) {
+ dev_dbg(&pdev->dev, "%s: %s property not found %d\n",
+ __func__, "qcom,hph-en1-gpio", pdata->hph_en1_gpio);
+ }
+
+ pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,hph-en0-gpio", 0);
+ if (pdata->hph_en0_gpio < 0) {
+ dev_dbg(&pdev->dev, "%s: %s property not found %d\n",
+ __func__, "qcom,hph-en0-gpio", pdata->hph_en0_gpio);
+ }
+ ret = msm8996_prepare_hifi(card);
+ if (ret)
+ dev_dbg(&pdev->dev, "msm8996_prepare_hifi failed (%d)\n",
+ ret);
+
+ ret = snd_soc_register_card(card);
+ if (ret == -EPROBE_DEFER) {
+ if (codec_reg_done)
+ ret = -EINVAL;
+ goto err;
+ } else if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err;
+ }
+ dev_info(&pdev->dev, "Sound card %s registered\n", card->name);
+
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type);
+ if (ret) {
+ dev_dbg(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,mbhc-audio-jack-type",
+ pdev->dev.of_node->full_name);
+ dev_dbg(&pdev->dev, "Jack type properties set to default");
+ } else {
+ if (!strcmp(mbhc_audio_jack_type, "4-pole-jack"))
+ dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
+ else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack"))
+ dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
+ else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack"))
+ dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
+ else
+ dev_dbg(&pdev->dev, "Unknown value, set to default");
+ }
+ /*
+ * Parse US-Euro gpio info from DT. Report no error if us-euro
+ * entry is not found in DT file as some targets do not support
+ * US-Euro detection
+ */
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (pdata->us_euro_gpio < 0) {
+ dev_info(&pdev->dev, "property %s not detected in node %s",
+ "qcom,us-euro-gpios",
+ pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected %d",
+ "qcom,us-euro-gpios", pdata->us_euro_gpio);
+ wcd_mbhc_cfg.swap_gnd_mic = msm8996_swap_gnd_mic;
+ }
+
+ ret = msm8996_prepare_us_euro(card);
+ if (ret)
+ dev_info(&pdev->dev, "msm8996_prepare_us_euro failed (%d)\n",
+ ret);
+ return 0;
+err:
+ if (pdata->us_euro_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ pdata->us_euro_gpio = 0;
+ }
+ if (pdata->hph_en1_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free hph_en1_gpio %d\n",
+ __func__, pdata->hph_en1_gpio);
+ gpio_free(pdata->hph_en1_gpio);
+ pdata->hph_en1_gpio = 0;
+ }
+ if (pdata->hph_en0_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free hph_en0_gpio %d\n",
+ __func__, pdata->hph_en0_gpio);
+ gpio_free(pdata->hph_en0_gpio);
+ pdata->hph_en0_gpio = 0;
+ }
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+
+static int msm8996_asoc_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm8996_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+
+ if (gpio_is_valid(ext_us_amp_gpio))
+ gpio_free(ext_us_amp_gpio);
+
+ gpio_free(pdata->us_euro_gpio);
+ gpio_free(pdata->hph_en1_gpio);
+ gpio_free(pdata->hph_en0_gpio);
+
+ if (msm8996_liquid_dock_dev != NULL) {
+ switch_dev_unregister(&msm8996_liquid_dock_dev->audio_sdev);
+
+ if (msm8996_liquid_dock_dev->dock_plug_irq)
+ free_irq(msm8996_liquid_dock_dev->dock_plug_irq,
+ msm8996_liquid_dock_dev);
+
+ if (msm8996_liquid_dock_dev->dock_plug_gpio)
+ gpio_free(msm8996_liquid_dock_dev->dock_plug_gpio);
+
+ kfree(msm8996_liquid_dock_dev);
+ msm8996_liquid_dock_dev = NULL;
+ }
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static struct platform_driver msm8996_asoc_machine_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = msm8996_asoc_machine_of_match,
+ },
+ .probe = msm8996_asoc_machine_probe,
+ .remove = msm8996_asoc_machine_remove,
+};
+module_platform_driver(msm8996_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, msm8996_asoc_machine_of_match);
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
new file mode 100644
index 0000000..c96c5bc
--- /dev/null
+++ b/sound/soc/msm/msm8998.c
@@ -0,0 +1,6828 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <linux/of_device.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6core.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <device_event.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "../codecs/wcd9335.h"
+#include "../codecs/wcd934x/wcd934x.h"
+#include "../codecs/wcd934x/wcd934x-mbhc.h"
+#include "../codecs/wsa881x.h"
+
+#define DRV_NAME "msm8998-asoc-snd"
+
+#define __CHIPSET__ "MSM8998 "
+#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
+
+#define SAMPLING_RATE_8KHZ 8000
+#define SAMPLING_RATE_11P025KHZ 11025
+#define SAMPLING_RATE_16KHZ 16000
+#define SAMPLING_RATE_22P05KHZ 22050
+#define SAMPLING_RATE_32KHZ 32000
+#define SAMPLING_RATE_44P1KHZ 44100
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_88P2KHZ 88200
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_176P4KHZ 176400
+#define SAMPLING_RATE_192KHZ 192000
+#define SAMPLING_RATE_352P8KHZ 352800
+#define SAMPLING_RATE_384KHZ 384000
+
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define CODEC_EXT_CLK_RATE 9600000
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+#define DEV_NAME_STR_LEN 32
+
+#define WSA8810_NAME_1 "wsa881x.20170211"
+#define WSA8810_NAME_2 "wsa881x.20170212"
+
+#define WCN_CDC_SLIM_RX_CH_MAX 2
+#define WCN_CDC_SLIM_TX_CH_MAX 3
+
+#define TDM_CHANNEL_MAX 8
+#define TDM_SLOT_OFFSET_MAX 8
+
+#define MSM_HIFI_ON 1
+
+enum {
+ SLIM_RX_0 = 0,
+ SLIM_RX_1,
+ SLIM_RX_2,
+ SLIM_RX_3,
+ SLIM_RX_4,
+ SLIM_RX_5,
+ SLIM_RX_6,
+ SLIM_RX_7,
+ SLIM_RX_MAX,
+};
+
+enum {
+ SLIM_TX_0 = 0,
+ SLIM_TX_1,
+ SLIM_TX_2,
+ SLIM_TX_3,
+ SLIM_TX_4,
+ SLIM_TX_5,
+ SLIM_TX_6,
+ SLIM_TX_7,
+ SLIM_TX_8,
+ SLIM_TX_MAX,
+};
+
+enum {
+ PRIM_MI2S = 0,
+ SEC_MI2S,
+ TERT_MI2S,
+ QUAT_MI2S,
+ MI2S_MAX,
+};
+
+enum {
+ PRIM_AUX_PCM = 0,
+ SEC_AUX_PCM,
+ TERT_AUX_PCM,
+ QUAT_AUX_PCM,
+ AUX_PCM_MAX,
+};
+
+enum {
+ PCM_I2S_SEL_PRIM = 0,
+ PCM_I2S_SEL_SEC,
+ PCM_I2S_SEL_TERT,
+ PCM_I2S_SEL_QUAT,
+ PCM_I2S_SEL_MAX,
+};
+
+struct mi2s_aux_pcm_common_conf {
+ struct mutex lock;
+ void *pcm_i2s_sel_vt_addr;
+};
+
+struct mi2s_conf {
+ struct mutex lock;
+ u32 ref_cnt;
+ u32 msm_is_mi2s_master;
+};
+
+struct auxpcm_conf {
+ struct mutex lock;
+ u32 ref_cnt;
+};
+
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+enum {
+ HDMI_RX_IDX = 0,
+ DP_RX_IDX,
+ EXT_DISP_RX_IDX_MAX,
+};
+
+struct msm_wsa881x_dev_info {
+ struct device_node *of_node;
+ u32 index;
+};
+
+struct msm_asoc_mach_data {
+ u32 mclk_freq;
+ int us_euro_gpio; /* used by gpio driver API */
+ struct device_node *us_euro_gpio_p; /* used by pinctrl API */
+ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
+ struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
+ struct snd_info_entry *codec_root;
+};
+
+struct msm_asoc_wcd93xx_codec {
+ void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
+ enum afe_config_type config_type);
+ void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
+};
+
+enum {
+ TDM_0 = 0,
+ TDM_1,
+ TDM_2,
+ TDM_3,
+ TDM_4,
+ TDM_5,
+ TDM_6,
+ TDM_7,
+ TDM_PORT_MAX,
+};
+
+enum {
+ TDM_PRI = 0,
+ TDM_SEC,
+ TDM_TERT,
+ TDM_QUAT,
+ TDM_INTERFACE_MAX,
+};
+
+struct tdm_port {
+ u32 mode;
+ u32 channel;
+};
+
+/* TDM default config */
+static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* SEC TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* TERT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* QUAT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ }
+};
+
+/* TDM default config */
+static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* SEC TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* TERT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* QUAT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ }
+};
+
+/*TDM default offset currently only supporting TDM_RX_0 and TDM_TX_0 */
+static unsigned int tdm_slot_offset[TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
+ {0, 4, 8, 12, 16, 20, 24, 28},/* TX_0 | RX_0 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_1 | RX_1 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_2 | RX_2 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_3 | RX_3 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_4 | RX_4 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_5 | RX_5 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_6 | RX_6 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_7 | RX_7 */
+};
+
+/* Default configuration of slimbus channels */
+static struct dev_config slim_rx_cfg[] = {
+ [SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config slim_tx_cfg[] = {
+ [SLIM_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+
+/* Default configuration of external display BE */
+static struct dev_config ext_disp_rx_cfg[] = {
+ [HDMI_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [DP_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static struct dev_config usb_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
+static struct dev_config usb_tx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 1,
+};
+
+static struct dev_config proxy_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
+/* Default configuration of MI2S channels */
+static struct dev_config mi2s_rx_cfg[] = {
+ [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static struct dev_config mi2s_tx_cfg[] = {
+ [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config aux_pcm_rx_cfg[] = {
+ [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config aux_pcm_tx_cfg[] = {
+ [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static int msm_vi_feed_tx_ch = 2;
+static const char *const slim_rx_ch_text[] = {"One", "Two"};
+static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static const char *const vi_feed_ch_text[] = {"One", "Two"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+ "S32_LE"};
+static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96", "KHZ_176P4",
+ "KHZ_192", "KHZ_352P8", "KHZ_384"};
+static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_48"};
+static const char *const usb_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static char const *ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
+static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
+ "KHZ_16", "KHZ_22P05",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96", "KHZ_176P4",
+ "KHZ_192", "KHZ_352P8", "KHZ_384"};
+static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
+static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
+static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
+static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
+ "KHZ_44P1", "KHZ_48", "KHZ_96",
+ "KHZ_192", "KHZ_352P8", "KHZ_384"};
+static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
+static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_96", "KHZ_192"};
+static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static const char *const hifi_text[] = {"Off", "On"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_1_tx_chs, slim_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_format, ext_disp_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate,
+ ext_disp_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text);
+
+static struct platform_device *spdev;
+static int msm_hifi_control;
+
+static bool is_initial_boot;
+static bool codec_reg_done;
+static struct snd_soc_aux_dev *msm_aux_dev;
+static struct snd_soc_codec_conf *msm_codec_conf;
+static struct msm_asoc_wcd93xx_codec msm_codec_fn;
+
+static void *def_tasha_mbhc_cal(void);
+static void *def_tavil_mbhc_cal(void);
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm);
+static int msm_wsa881x_init(struct snd_soc_component *component);
+
+/*
+ * Need to report LINEIN
+ * if R/L channel impedance is larger than 5K ohm
+ */
+static struct wcd_mbhc_config wcd_mbhc_cfg = {
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .detect_extn_cable = true,
+ .mono_stero_detection = false,
+ .swap_gnd_mic = NULL,
+ .hs_ext_micbias = true,
+ .key_code[0] = KEY_MEDIA,
+ .key_code[1] = KEY_VOICECOMMAND,
+ .key_code[2] = KEY_VOLUMEUP,
+ .key_code[3] = KEY_VOLUMEDOWN,
+ .key_code[4] = 0,
+ .key_code[5] = 0,
+ .key_code[6] = 0,
+ .key_code[7] = 0,
+ .linein_th = 5000,
+ .moisture_en = true,
+};
+
+static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
+ {"MIC BIAS1", NULL, "MCLK TX"},
+ {"MIC BIAS2", NULL, "MCLK TX"},
+ {"MIC BIAS3", NULL, "MCLK TX"},
+ {"MIC BIAS4", NULL, "MCLK TX"},
+};
+
+static struct snd_soc_dapm_route wcd_audio_paths[] = {
+ {"MIC BIAS1", NULL, "MCLK"},
+ {"MIC BIAS2", NULL, "MCLK"},
+ {"MIC BIAS3", NULL, "MCLK"},
+ {"MIC BIAS4", NULL, "MCLK"},
+};
+
+static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ }
+};
+
+static struct mi2s_aux_pcm_common_conf mi2s_auxpcm_conf[PCM_I2S_SEL_MAX];
+static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
+static struct auxpcm_conf auxpcm_intf_conf[AUX_PCM_MAX];
+
+static int slim_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 10;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int slim_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 7:
+ sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 8:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 9:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 10:
+ sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int slim_get_bit_format_val(int bit_format)
+{
+ int val = 0;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ val = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ val = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static int slim_get_bit_format(int val)
+{
+ int bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+
+ switch (val) {
+ case 0:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 3:
+ bit_fmt = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return bit_fmt;
+}
+
+static int slim_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int port_id = 0;
+
+ if (strnstr(kcontrol->id.name, "SLIM_0_RX", sizeof("SLIM_0_RX")))
+ port_id = SLIM_RX_0;
+ else if (strnstr(kcontrol->id.name, "SLIM_2_RX", sizeof("SLIM_2_RX")))
+ port_id = SLIM_RX_2;
+ else if (strnstr(kcontrol->id.name, "SLIM_5_RX", sizeof("SLIM_5_RX")))
+ port_id = SLIM_RX_5;
+ else if (strnstr(kcontrol->id.name, "SLIM_6_RX", sizeof("SLIM_6_RX")))
+ port_id = SLIM_RX_6;
+ else if (strnstr(kcontrol->id.name, "SLIM_0_TX", sizeof("SLIM_0_TX")))
+ port_id = SLIM_TX_0;
+ else if (strnstr(kcontrol->id.name, "SLIM_1_TX", sizeof("SLIM_1_TX")))
+ port_id = SLIM_TX_1;
+ else {
+ pr_err("%s: unsupported channel: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return port_id;
+}
+
+static int slim_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_sample_rate_val(slim_rx_cfg[ch_num].sample_rate);
+
+ pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].sample_rate =
+ slim_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_sample_rate_val(slim_tx_cfg[ch_num].sample_rate);
+
+ pr_debug("%s: slim[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate = 0;
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ sample_rate = slim_get_sample_rate(ucontrol->value.enumerated.item[0]);
+ if (sample_rate == SAMPLING_RATE_44P1KHZ) {
+ pr_err("%s: Unsupported sample rate %d: for Tx path\n",
+ __func__, sample_rate);
+ return -EINVAL;
+ }
+ slim_tx_cfg[ch_num].sample_rate = sample_rate;
+
+ pr_debug("%s: slim[%d]_tx_sample_rate = %d, value = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_bit_format_val(slim_rx_cfg[ch_num].bit_format);
+
+ pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_rx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].bit_format =
+ slim_get_bit_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_rx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_bit_format_val(slim_tx_cfg[ch_num].bit_format);
+
+ pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_tx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_tx_cfg[ch_num].bit_format =
+ slim_get_bit_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_tx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_slim_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].channels);
+ ucontrol->value.enumerated.item[0] = slim_rx_cfg[ch_num].channels - 1;
+
+ return 0;
+}
+
+static int msm_slim_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].channels);
+
+ return 1;
+}
+
+static int msm_slim_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].channels);
+ ucontrol->value.enumerated.item[0] = slim_tx_cfg[ch_num].channels - 1;
+
+ return 0;
+}
+
+static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_tx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].channels);
+
+ return 1;
+}
+
+static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
+ pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
+ return 1;
+}
+
+static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * Slimbus_7_Rx/Tx sample rate values should always be in sync (same)
+ * when used for BT_SCO use case. Return either Rx or Tx sample rate
+ * value.
+ */
+ switch (slim_rx_cfg[SLIM_RX_7].sample_rate) {
+ case SAMPLING_RATE_48KHZ:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: sample rate = %d", __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 0:
+ default:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n",
+ __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate,
+ slim_tx_cfg[SLIM_TX_7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: usb_audio_rx_ch = %d\n", __func__,
+ usb_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = usb_rx_cfg.channels - 1;
+ return 0;
+}
+
+static int usb_audio_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ usb_rx_cfg.channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, usb_rx_cfg.channels);
+ return 1;
+}
+
+static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+
+ switch (usb_rx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 12;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 11;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 10;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: usb_audio_rx_sample_rate = %d\n", __func__,
+ usb_rx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 12:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 11:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 10:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 9:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 8:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 7:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 6:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, usb_audio_rx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ usb_rx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (usb_rx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+static int usb_audio_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: usb_audio_tx_ch = %d\n", __func__,
+ usb_tx_cfg.channels);
+ ucontrol->value.integer.value[0] = usb_tx_cfg.channels - 1;
+ return 0;
+}
+
+static int usb_audio_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ usb_tx_cfg.channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, usb_tx_cfg.channels);
+ return 1;
+}
+
+static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+
+ switch (usb_tx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 12;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 11;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 10;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ default:
+ sample_rate_val = 6;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: usb_audio_tx_sample_rate = %d\n", __func__,
+ usb_tx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 12:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 11:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 10:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 9:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 8:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 7:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 6:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, usb_audio_tx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ usb_tx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (usb_tx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_tx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_tx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx;
+
+ if (strnstr(kcontrol->id.name, "HDMI_RX", sizeof("HDMI_RX")))
+ idx = HDMI_RX_IDX;
+ else if (strnstr(kcontrol->id.name, "Display Port RX",
+ sizeof("Display Port RX")))
+ idx = DP_RX_IDX;
+ else {
+ pr_err("%s: unsupported BE: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int ext_disp_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ switch (ext_disp_rx_cfg[idx].bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n",
+ __func__, idx, ext_disp_rx_cfg[idx].bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int ext_disp_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n",
+ __func__, idx, ext_disp_rx_cfg[idx].bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int ext_disp_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.integer.value[0] =
+ ext_disp_rx_cfg[idx].channels - 2;
+
+ pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__,
+ idx, ext_disp_rx_cfg[idx].channels);
+
+ return 0;
+}
+
+static int ext_disp_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ext_disp_rx_cfg[idx].channels =
+ ucontrol->value.integer.value[0] + 2;
+
+ pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__,
+ idx, ext_disp_rx_cfg[idx].channels);
+ return 1;
+}
+
+static int ext_disp_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ switch (ext_disp_rx_cfg[idx].sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: ext_disp_rx[%d].sample_rate = %d\n", __func__,
+ idx, ext_disp_rx_cfg[idx].sample_rate);
+
+ return 0;
+}
+
+static int ext_disp_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, ext_disp_rx[%d].sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0], idx,
+ ext_disp_rx_cfg[idx].sample_rate);
+ return 0;
+}
+
+static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: proxy_rx channels = %d\n",
+ __func__, proxy_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = proxy_rx_cfg.channels - 2;
+
+ return 0;
+}
+
+static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ proxy_rx_cfg.channels = ucontrol->value.integer.value[0] + 2;
+ pr_debug("%s: proxy_rx channels = %d\n",
+ __func__, proxy_rx_cfg.channels);
+
+ return 1;
+}
+
+static int tdm_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 7:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 8:
+ sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int aux_pcm_get_sample_rate(int value)
+{
+ int sample_rate;
+
+ switch (value) {
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 0:
+ default:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int tdm_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 8;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int aux_pcm_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
+ struct tdm_port *port)
+{
+ if (port) {
+ if (strnstr(kcontrol->id.name, "PRI",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_PRI;
+ } else if (strnstr(kcontrol->id.name, "SEC",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_SEC;
+ } else if (strnstr(kcontrol->id.name, "TERT",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_TERT;
+ } else if (strnstr(kcontrol->id.name, "QUAT",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_QUAT;
+ } else {
+ pr_err("%s: unsupported mode in: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ if (strnstr(kcontrol->id.name, "RX_0",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_0",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_0;
+ } else if (strnstr(kcontrol->id.name, "RX_1",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_1",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_1;
+ } else if (strnstr(kcontrol->id.name, "RX_2",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_2",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_2;
+ } else if (strnstr(kcontrol->id.name, "RX_3",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_3",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_3;
+ } else if (strnstr(kcontrol->id.name, "RX_4",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_4",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_4;
+ } else if (strnstr(kcontrol->id.name, "RX_5",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_5",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_5;
+ } else if (strnstr(kcontrol->id.name, "RX_6",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_6",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_6;
+ } else if (strnstr(kcontrol->id.name, "RX_7",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_7",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_7;
+ } else {
+ pr_err("%s: unsupported channel in: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
+ tdm_rx_cfg[port.mode][port.channel].sample_rate);
+
+ pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].sample_rate =
+ tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
+ tdm_tx_cfg[port.mode][port.channel].sample_rate);
+
+ pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].sample_rate =
+ tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_get_format(int value)
+{
+ int format = 0;
+
+ switch (value) {
+ case 0:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return format;
+}
+
+static int tdm_get_format_val(int format)
+{
+ int value = 0;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ value = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ value = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ value = 2;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ return value;
+}
+
+static int tdm_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_format_val(
+ tdm_rx_cfg[port.mode][port.channel].bit_format);
+
+ pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].bit_format =
+ tdm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_format_val(
+ tdm_tx_cfg[port.mode][port.channel].bit_format);
+
+ pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].bit_format =
+ tdm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+
+ ucontrol->value.enumerated.item[0] =
+ tdm_rx_cfg[port.mode][port.channel].channels - 1;
+
+ pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].channels - 1,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].channels,
+ ucontrol->value.enumerated.item[0] + 1);
+ }
+ return ret;
+}
+
+static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] =
+ tdm_tx_cfg[port.mode][port.channel].channels - 1;
+
+ pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].channels - 1,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].channels,
+ ucontrol->value.enumerated.item[0] + 1);
+ }
+ return ret;
+}
+
+static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx;
+
+ if (strnstr(kcontrol->id.name, "PRIM_AUX_PCM",
+ sizeof("PRIM_AUX_PCM")))
+ idx = PRIM_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "SEC_AUX_PCM",
+ sizeof("SEC_AUX_PCM")))
+ idx = SEC_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "TERT_AUX_PCM",
+ sizeof("TERT_AUX_PCM")))
+ idx = TERT_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM",
+ sizeof("QUAT_AUX_PCM")))
+ idx = QUAT_AUX_PCM;
+ else {
+ pr_err("%s: unsupported port: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_rx_cfg[idx].sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(aux_pcm_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_tx_cfg[idx].sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(aux_pcm_tx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx;
+
+ if (strnstr(kcontrol->id.name, "PRIM_MI2S_RX",
+ sizeof("PRIM_MI2S_RX")))
+ idx = PRIM_MI2S;
+ else if (strnstr(kcontrol->id.name, "SEC_MI2S_RX",
+ sizeof("SEC_MI2S_RX")))
+ idx = SEC_MI2S;
+ else if (strnstr(kcontrol->id.name, "TERT_MI2S_RX",
+ sizeof("TERT_MI2S_RX")))
+ idx = TERT_MI2S;
+ else if (strnstr(kcontrol->id.name, "QUAT_MI2S_RX",
+ sizeof("QUAT_MI2S_RX")))
+ idx = QUAT_MI2S;
+ else if (strnstr(kcontrol->id.name, "PRIM_MI2S_TX",
+ sizeof("PRIM_MI2S_TX")))
+ idx = PRIM_MI2S;
+ else if (strnstr(kcontrol->id.name, "SEC_MI2S_TX",
+ sizeof("SEC_MI2S_TX")))
+ idx = SEC_MI2S;
+ else if (strnstr(kcontrol->id.name, "TERT_MI2S_TX",
+ sizeof("TERT_MI2S_TX")))
+ idx = TERT_MI2S;
+ else if (strnstr(kcontrol->id.name, "QUAT_MI2S_TX",
+ sizeof("QUAT_MI2S_TX")))
+ idx = QUAT_MI2S;
+ else {
+ pr_err("%s: unsupported channel: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int mi2s_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 6;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int mi2s_get_sample_rate(int value)
+{
+ int sample_rate;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(mi2s_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(mi2s_tx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = mi2s_rx_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].channels);
+
+ return 1;
+}
+
+static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = mi2s_tx_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].channels);
+
+ return 1;
+}
+
+static int msm_hifi_ctrl(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+
+ pr_debug("%s: msm_hifi_control = %d", __func__,
+ msm_hifi_control);
+
+ if (!pdata || !pdata->hph_en1_gpio_p) {
+ pr_err("%s: hph_en1_gpio is invalid\n", __func__);
+ return -EINVAL;
+ }
+ if (msm_hifi_control == MSM_HIFI_ON) {
+ msm_cdc_pinctrl_select_active_state(pdata->hph_en1_gpio_p);
+ /* 5msec delay needed as per HW requirement */
+ usleep_range(5000, 5010);
+ } else {
+ msm_cdc_pinctrl_select_sleep_state(pdata->hph_en1_gpio_p);
+ }
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+static int msm_hifi_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_hifi_control = %d\n",
+ __func__, msm_hifi_control);
+ ucontrol->value.integer.value[0] = msm_hifi_control;
+
+ return 0;
+}
+
+static int msm_hifi_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+ pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ msm_hifi_control = ucontrol->value.integer.value[0];
+ msm_hifi_ctrl(codec);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_2_RX Channels", slim_2_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", slim_0_tx_chs,
+ msm_slim_tx_ch_get, msm_slim_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_1_TX Channels", slim_1_tx_chs,
+ msm_slim_tx_ch_get, msm_slim_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_5_RX Channels", slim_5_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_6_RX Channels", slim_6_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs,
+ msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX Channels", usb_rx_chs,
+ usb_audio_rx_ch_get, usb_audio_rx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs,
+ usb_audio_tx_ch_get, usb_audio_tx_ch_put),
+ SOC_ENUM_EXT("HDMI_RX Channels", ext_disp_rx_chs,
+ ext_disp_rx_ch_get, ext_disp_rx_ch_put),
+ SOC_ENUM_EXT("Display Port RX Channels", ext_disp_rx_chs,
+ ext_disp_rx_ch_get, ext_disp_rx_ch_put),
+ SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
+ proxy_rx_ch_get, proxy_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_5_RX Format", slim_5_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_6_RX Format", slim_6_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format,
+ slim_tx_bit_format_get, slim_tx_bit_format_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format,
+ usb_audio_rx_format_get, usb_audio_rx_format_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format,
+ usb_audio_tx_format_get, usb_audio_tx_format_put),
+ SOC_ENUM_EXT("HDMI_RX Bit Format", ext_disp_rx_format,
+ ext_disp_rx_format_get, ext_disp_rx_format_put),
+ SOC_ENUM_EXT("Display Port RX Bit Format", ext_disp_rx_format,
+ ext_disp_rx_format_get, ext_disp_rx_format_put),
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_0_TX SampleRate", slim_0_tx_sample_rate,
+ slim_tx_sample_rate_get, slim_tx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_5_RX SampleRate", slim_5_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_6_RX SampleRate", slim_6_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("BT SampleRate", bt_sample_rate,
+ msm_bt_sample_rate_get,
+ msm_bt_sample_rate_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate,
+ usb_audio_rx_sample_rate_get,
+ usb_audio_rx_sample_rate_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate,
+ usb_audio_tx_sample_rate_get,
+ usb_audio_tx_sample_rate_put),
+ SOC_ENUM_EXT("HDMI_RX SampleRate", ext_disp_rx_sample_rate,
+ ext_disp_rx_sample_rate_get,
+ ext_disp_rx_sample_rate_put),
+ SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate,
+ ext_disp_rx_sample_rate_get,
+ ext_disp_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_RX SampleRate", sec_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_RX SampleRate", tert_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_RX SampleRate", quat_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_TX SampleRate", sec_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_TX SampleRate", tert_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_TX SampleRate", quat_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX SampleRate", prim_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX SampleRate", sec_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX SampleRate", tert_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX SampleRate", quat_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX SampleRate", prim_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", sec_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX SampleRate", tert_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX Channels", sec_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX Channels", sec_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX Channels", tert_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX Channels", tert_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX Channels", quat_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get,
+ msm_hifi_put),
+};
+
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ if (!strcmp(dev_name(codec->dev), "tasha_codec"))
+ ret = tasha_cdc_mclk_enable(codec, enable, dapm);
+ else if (!strcmp(dev_name(codec->dev), "tavil_codec"))
+ ret = tavil_cdc_mclk_enable(codec, enable);
+ else {
+ dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ if (!strcmp(dev_name(codec->dev), "tasha_codec"))
+ ret = tasha_cdc_mclk_tx_enable(codec, enable, dapm);
+ else {
+ dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int msm_mclk_tx_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 0, true);
+ }
+ return 0;
+}
+
+static int msm_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_clk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_clk(codec, 0, true);
+ }
+ return 0;
+}
+
+static int msm_hifi_ctrl_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+
+ pr_debug("%s: msm_hifi_control = %d", __func__, msm_hifi_control);
+
+ if (!pdata || !pdata->hph_en0_gpio_p) {
+ pr_err("%s: hph_en0_gpio is invalid\n", __func__);
+ return -EINVAL;
+ }
+
+ if (msm_hifi_control != MSM_HIFI_ON) {
+ pr_debug("%s: HiFi mixer control is not set\n",
+ __func__);
+ return 0;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msm_cdc_pinctrl_select_active_state(pdata->hph_en0_gpio_p);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ msm_cdc_pinctrl_select_sleep_state(pdata->hph_en0_gpio_p);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ msm_mclk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("MCLK TX", SND_SOC_NOPM, 0, 0,
+ msm_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
+ SND_SOC_DAPM_SPK("hifi amp", msm_hifi_ctrl_event),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic5", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+
+ SND_SOC_DAPM_MIC("Digital Mic0", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+};
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
+ int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static int msm_slim_get_ch_from_beid(int32_t be_id)
+{
+ int ch_id = 0;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_SLIMBUS_0_RX:
+ ch_id = SLIM_RX_0;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_1_RX:
+ ch_id = SLIM_RX_1;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_2_RX:
+ ch_id = SLIM_RX_2;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_3_RX:
+ ch_id = SLIM_RX_3;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_4_RX:
+ ch_id = SLIM_RX_4;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_6_RX:
+ ch_id = SLIM_RX_6;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_0_TX:
+ ch_id = SLIM_TX_0;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_3_TX:
+ ch_id = SLIM_TX_3;
+ break;
+ default:
+ ch_id = SLIM_RX_0;
+ break;
+ }
+
+ return ch_id;
+}
+
+static int msm_ext_disp_get_idx_from_beid(int32_t be_id)
+{
+ int idx;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_HDMI_RX:
+ idx = HDMI_RX_IDX;
+ break;
+ case MSM_BACKEND_DAI_DISPLAY_PORT_RX:
+ idx = DP_RX_IDX;
+ break;
+ default:
+ pr_err("%s: Incorrect ext_disp be_id %d\n", __func__, be_id);
+ idx = -EINVAL;
+ break;
+ }
+
+ return idx;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ int rc = 0;
+ int idx;
+ void *config = NULL;
+ struct snd_soc_codec *codec = NULL;
+
+ pr_debug("%s: format = %d, rate = %d\n",
+ __func__, params_format(params), params_rate(params));
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_SLIMBUS_0_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_1_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_2_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_3_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_4_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_6_RX:
+ idx = msm_slim_get_ch_from_beid(dai_link->be_id);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[idx].bit_format);
+ rate->min = rate->max = slim_rx_cfg[idx].sample_rate;
+ channels->min = channels->max = slim_rx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_0_TX:
+ case MSM_BACKEND_DAI_SLIMBUS_3_TX:
+ idx = msm_slim_get_ch_from_beid(dai_link->be_id);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_tx_cfg[idx].bit_format);
+ rate->min = rate->max = slim_tx_cfg[idx].sample_rate;
+ channels->min = channels->max = slim_tx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_1_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_tx_cfg[1].bit_format);
+ rate->min = rate->max = slim_tx_cfg[1].sample_rate;
+ channels->min = channels->max = slim_tx_cfg[1].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_4_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FORMAT_S32_LE);
+ rate->min = rate->max = SAMPLING_RATE_8KHZ;
+ channels->min = channels->max = msm_vi_feed_tx_ch;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_5_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[5].bit_format);
+ rate->min = rate->max = slim_rx_cfg[5].sample_rate;
+ channels->min = channels->max = slim_rx_cfg[5].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_5_TX:
+ codec = rtd->codec;
+ rate->min = rate->max = SAMPLING_RATE_16KHZ;
+ channels->min = channels->max = 1;
+
+ config = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ if (config) {
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG,
+ config, SLIMBUS_5_TX);
+ if (rc)
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ }
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[SLIM_RX_7].bit_format);
+ rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate;
+ channels->min = channels->max =
+ slim_rx_cfg[SLIM_RX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_8_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_8].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_8].channels;
+ break;
+
+ case MSM_BACKEND_DAI_USB_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ usb_rx_cfg.bit_format);
+ rate->min = rate->max = usb_rx_cfg.sample_rate;
+ channels->min = channels->max = usb_rx_cfg.channels;
+ break;
+
+ case MSM_BACKEND_DAI_USB_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ usb_tx_cfg.bit_format);
+ rate->min = rate->max = usb_tx_cfg.sample_rate;
+ channels->min = channels->max = usb_tx_cfg.channels;
+ break;
+
+ case MSM_BACKEND_DAI_HDMI_RX:
+ case MSM_BACKEND_DAI_DISPLAY_PORT_RX:
+ idx = msm_ext_disp_get_idx_from_beid(dai_link->be_id);
+ if (IS_ERR_VALUE(idx)) {
+ pr_err("%s: Incorrect ext disp idx %d\n",
+ __func__, idx);
+ rc = idx;
+ goto done;
+ }
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ ext_disp_rx_cfg[idx].bit_format);
+ rate->min = rate->max = ext_disp_rx_cfg[idx].sample_rate;
+ channels->min = channels->max = ext_disp_rx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_AFE_PCM_RX:
+ channels->min = channels->max = proxy_rx_cfg.channels;
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[SEC_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[SEC_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[SEC_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[SEC_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[TERT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[TERT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[TERT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[TERT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[PRIM_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[PRIM_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[SEC_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[SEC_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[TERT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[TERT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[QUAT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[QUAT_MI2S].channels;
+ break;
+
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+done:
+ return rc;
+}
+
+static bool msm_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int value = 0;
+
+ if (pdata->us_euro_gpio_p) {
+ value = msm_cdc_pinctrl_get_state(pdata->us_euro_gpio_p);
+ if (value)
+ msm_cdc_pinctrl_select_sleep_state(
+ pdata->us_euro_gpio_p);
+ else
+ msm_cdc_pinctrl_select_active_state(
+ pdata->us_euro_gpio_p);
+ } else if (pdata->us_euro_gpio >= 0) {
+ value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+ gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+ }
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ return true;
+}
+
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+ int ret = 0;
+ void *config_data = NULL;
+
+ if (!msm_codec_fn.get_afe_config_fn) {
+ dev_err(codec->dev, "%s: codec get afe config not init'ed\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTERS_CONFIG);
+ if (config_data) {
+ ret = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (ret) {
+ dev_err(codec->dev,
+ "%s: Failed to set codec registers config %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTER_PAGE_CONFIG);
+ if (config_data) {
+ ret = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
+ 0);
+ if (ret)
+ dev_err(codec->dev,
+ "%s: Failed to set cdc register page config\n",
+ __func__);
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_SLIMBUS_SLAVE_CONFIG);
+ if (config_data) {
+ ret = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (ret) {
+ dev_err(codec->dev,
+ "%s: Failed to set slimbus slave config %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+ afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+ afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+}
+
+static int msm_adsp_power_up_config(struct snd_soc_codec *codec)
+{
+ int ret = 0;
+ unsigned long timeout;
+ int adsp_ready = 0;
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+ do {
+ if (q6core_is_adsp_ready()) {
+ pr_debug("%s: ADSP Audio is ready\n", __func__);
+ adsp_ready = 1;
+ break;
+ }
+ /*
+ * ADSP will be coming up after subsystem restart and
+ * it might not be fully up when the control reaches
+ * here. So, wait for 50msec before checking ADSP state
+ */
+ msleep(50);
+ } while (time_after(timeout, jiffies));
+
+ if (!adsp_ready) {
+ pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+ ret = -ETIMEDOUT;
+ goto err_fail;
+ }
+
+ ret = msm_afe_set_config(codec);
+ if (ret)
+ pr_err("%s: Failed to set AFE config. err %d\n",
+ __func__, ret);
+
+ return 0;
+
+err_fail:
+ return ret;
+}
+
+static int msm8998_notifier_service_cb(struct notifier_block *this,
+ unsigned long opcode, void *ptr)
+{
+ int ret;
+ struct snd_soc_card *card = NULL;
+ const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *codec;
+
+ pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
+
+ switch (opcode) {
+ case AUDIO_NOTIFIER_SERVICE_DOWN:
+ /*
+ * Use flag to ignore initial boot notifications
+ * On initial boot msm_adsp_power_up_config is
+ * called on init. There is no need to clear
+ * and set the config again on initial boot.
+ */
+ if (is_initial_boot)
+ break;
+ msm_afe_clear_config();
+ break;
+ case AUDIO_NOTIFIER_SERVICE_UP:
+ if (is_initial_boot) {
+ is_initial_boot = false;
+ break;
+ }
+ if (!spdev)
+ return -EINVAL;
+
+ card = platform_get_drvdata(spdev);
+ rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+ if (!rtd) {
+ dev_err(card->dev,
+ "%s: snd_soc_get_pcm_runtime for %s failed!\n",
+ __func__, be_dl_name);
+ ret = -EINVAL;
+ goto done;
+ }
+ codec = rtd->codec;
+
+ ret = msm_adsp_power_up_config(codec);
+ if (ret < 0) {
+ dev_err(card->dev,
+ "%s: msm_adsp_power_up_config failed ret = %d!\n",
+ __func__, ret);
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+done:
+ return NOTIFY_OK;
+}
+
+static struct notifier_block service_nb = {
+ .notifier_call = msm8998_notifier_service_cb,
+ .priority = -INT_MAX,
+};
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ void *config_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux;
+ struct snd_card *card;
+ struct snd_info_entry *entry;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(rtd->card);
+
+ /* Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+ pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ rtd->pmdown_time = 0;
+
+ ret = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (ret < 0) {
+ pr_err("%s: add_codec_controls failed, err %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
+ ARRAY_SIZE(msm_dapm_widgets));
+
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec"))
+ snd_soc_dapm_add_routes(dapm, wcd_audio_paths_tasha,
+ ARRAY_SIZE(wcd_audio_paths_tasha));
+ else
+ snd_soc_dapm_add_routes(dapm, wcd_audio_paths,
+ ARRAY_SIZE(wcd_audio_paths));
+
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic5");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6");
+ snd_soc_dapm_ignore_suspend(dapm, "MADINPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT2");
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
+ snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+ }
+
+ snd_soc_dapm_sync(dapm);
+
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+ if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+ msm_codec_fn.get_afe_config_fn = tavil_get_afe_config;
+ } else {
+ msm_codec_fn.get_afe_config_fn = tasha_get_afe_config;
+ msm_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit;
+ }
+
+ ret = msm_adsp_power_up_config(codec);
+ if (ret) {
+ pr_err("%s: Failed to set AFE config %d\n", __func__, ret);
+ goto err_afe_cfg;
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_AANC_VERSION);
+ if (config_data) {
+ ret = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ ret = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ ret = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+ }
+
+ /*
+ * Send speaker configuration only for WSA8810.
+ * Defalut configuration is for WSA8815.
+ */
+ pr_debug("%s: Number of aux devices: %d\n",
+ __func__, rtd->card->num_aux_devs);
+ if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+ if (rtd->card->num_aux_devs && rtd_aux && rtd_aux->component)
+ if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
+ !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
+ tavil_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+ tavil_set_spkr_gain_offset(rtd->codec,
+ RX_GAIN_OFFSET_M1P5_DB);
+ }
+ card = rtd->card->snd_card;
+ entry = snd_info_create_subdir(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ pdata->codec_root = NULL;
+ goto done;
+ }
+ pdata->codec_root = entry;
+ tavil_codec_info_create_codec_entry(pdata->codec_root, codec);
+ } else {
+ if (rtd->card->num_aux_devs && rtd_aux && rtd_aux->component)
+ if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
+ !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
+ tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+ tasha_set_spkr_gain_offset(rtd->codec,
+ RX_GAIN_OFFSET_M1P5_DB);
+ }
+ card = rtd->card->snd_card;
+ entry = snd_info_create_subdir(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ ret = 0;
+ goto err_snd_module;
+ }
+ pdata->codec_root = entry;
+ tasha_codec_info_create_codec_entry(pdata->codec_root, codec);
+ }
+done:
+ codec_reg_done = true;
+ return 0;
+
+err_snd_module:
+err_afe_cfg:
+ return ret;
+}
+
+static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd)
+{
+ unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158};
+ unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+}
+
+static void *def_tasha_mbhc_cal(void)
+{
+ void *tasha_wcd_cal;
+ struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_high;
+
+ tasha_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
+ if (!tasha_wcd_cal)
+ return NULL;
+
+#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tasha_wcd_cal)->X) = (Y))
+ S(v_hs_max, 1600);
+#undef S
+#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal)->X) = (Y))
+ S(num_btn, WCD_MBHC_DEF_BUTTONS);
+#undef S
+
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal);
+ btn_high = ((void *)&btn_cfg->_v_btn_low) +
+ (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+ btn_high[0] = 75;
+ btn_high[1] = 150;
+ btn_high[2] = 237;
+ btn_high[3] = 500;
+ btn_high[4] = 500;
+ btn_high[5] = 500;
+ btn_high[6] = 500;
+ btn_high[7] = 500;
+
+ return tasha_wcd_cal;
+}
+
+static void *def_tavil_mbhc_cal(void)
+{
+ void *tavil_wcd_cal;
+ struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_high;
+
+ tavil_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
+ if (!tavil_wcd_cal)
+ return NULL;
+
+#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tavil_wcd_cal)->X) = (Y))
+ S(v_hs_max, 1600);
+#undef S
+#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal)->X) = (Y))
+ S(num_btn, WCD_MBHC_DEF_BUTTONS);
+#undef S
+
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal);
+ btn_high = ((void *)&btn_cfg->_v_btn_low) +
+ (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+ btn_high[0] = 75;
+ btn_high[1] = 150;
+ btn_high[2] = 237;
+ btn_high[3] = 500;
+ btn_high[4] = 500;
+ btn_high[5] = 500;
+ btn_high[6] = 500;
+ btn_high[7] = 500;
+
+ return tavil_wcd_cal;
+}
+
+static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ int ret = 0;
+ u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ u32 user_set_tx_ch = 0;
+ u32 rx_ch_count;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_5_RX) {
+ pr_debug("%s: rx_5_ch=%d\n", __func__,
+ slim_rx_cfg[5].channels);
+ rx_ch_count = slim_rx_cfg[5].channels;
+ } else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_2_RX) {
+ pr_debug("%s: rx_2_ch=%d\n", __func__,
+ slim_rx_cfg[2].channels);
+ rx_ch_count = slim_rx_cfg[2].channels;
+ } else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_6_RX) {
+ pr_debug("%s: rx_6_ch=%d\n", __func__,
+ slim_rx_cfg[6].channels);
+ rx_ch_count = slim_rx_cfg[6].channels;
+ } else {
+ pr_debug("%s: rx_0_ch=%d\n", __func__,
+ slim_rx_cfg[0].channels);
+ rx_ch_count = slim_rx_cfg[0].channels;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ rx_ch_count, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ } else {
+
+ pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+ codec_dai->name, codec_dai->id, user_set_tx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ /* For <codec>_tx1 case */
+ if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_0_TX)
+ user_set_tx_ch = slim_tx_cfg[0].channels;
+ /* For <codec>_tx3 case */
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_1_TX)
+ user_set_tx_ch = slim_tx_cfg[1].channels;
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_4_TX)
+ user_set_tx_ch = msm_vi_feed_tx_ch;
+ else
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), be_id (%d)\n",
+ __func__, slim_tx_cfg[0].channels, user_set_tx_ch,
+ tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0, 0);
+ if (ret < 0)
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ }
+
+err_ch_map:
+ return ret;
+}
+
+static int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ int ret = 0;
+ u32 tx_ch[SLIM_MAX_TX_PORTS];
+ u32 tx_ch_cnt = 0;
+ u32 user_set_tx_ch = 0;
+
+ if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("%s: Invalid stream type %d\n",
+ __func__, substream->stream);
+ ret = -EINVAL;
+ goto err_stream_type;
+ }
+
+ pr_debug("%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, NULL, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0, 0);
+ if (ret < 0)
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+err_ch_map:
+err_stream_type:
+ return ret;
+}
+
+static int msm_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ num_rx_ch = params_channels(params);
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ } else {
+ num_tx_ch = params_channels(params);
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ }
+
+err_ch_map:
+ return ret;
+}
+
+static int msm_wcn_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret;
+
+ dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret) {
+ dev_err(rtd->dev,
+ "%s: failed to get BTFM codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch);
+ if (ret)
+ dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+
+exit:
+ return ret;
+}
+
+static int msm_aux_pcm_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id - 1;
+ return ret = 0;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__, substream->name, substream->stream,
+ cpu_dai->name, cpu_dai->id);
+
+ if (index < PRIM_AUX_PCM || index > QUAT_AUX_PCM) {
+ ret = -EINVAL;
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, cpu_dai->id);
+ goto done;
+ }
+
+ mutex_lock(&auxpcm_intf_conf[index].lock);
+ if (++auxpcm_intf_conf[index].ref_cnt == 1) {
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(1,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_tert_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ }
+ if (IS_ERR_VALUE(ret))
+ auxpcm_intf_conf[index].ref_cnt--;
+
+ mutex_unlock(&auxpcm_intf_conf[index].lock);
+
+done:
+ return ret;
+}
+
+static void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int index = rtd->cpu_dai->id - 1;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__,
+ substream->name, substream->stream,
+ rtd->cpu_dai->name, rtd->cpu_dai->id);
+
+ if (index < PRIM_AUX_PCM || index > QUAT_AUX_PCM) {
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, rtd->cpu_dai->id);
+ return;
+ }
+
+ mutex_lock(&auxpcm_intf_conf[index].lock);
+ if (--auxpcm_intf_conf[index].ref_cnt == 0) {
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(0,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_tert_muxsel_virt_addr is NULL\n",
+ __func__);
+ auxpcm_intf_conf[index].ref_cnt++;
+ }
+ }
+ mutex_unlock(&auxpcm_intf_conf[index].lock);
+}
+
+static int msm_get_port_id(int be_id)
+{
+ int afe_port_id;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_PRI_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_PRI_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
+ default:
+ pr_err("%s: Invalid be_id: %d\n", __func__, be_id);
+ afe_port_id = -EINVAL;
+ }
+
+ return afe_port_id;
+}
+
+static u32 get_mi2s_bits_per_sample(u32 bit_format)
+{
+ u32 bit_per_sample;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_per_sample = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_per_sample = 16;
+ break;
+ }
+
+ return bit_per_sample;
+}
+
+static void update_mi2s_clk_val(int dai_id, int stream)
+{
+ u32 bit_per_sample;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(mi2s_rx_cfg[dai_id].bit_format);
+ mi2s_clk[dai_id].clk_freq_in_hz =
+ mi2s_rx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
+ } else {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(mi2s_tx_cfg[dai_id].bit_format);
+ mi2s_clk[dai_id].clk_freq_in_hz =
+ mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
+ }
+
+ if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
+ mi2s_clk[dai_id].clk_freq_in_hz = 0;
+}
+
+static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int port_id = 0;
+ int index = cpu_dai->id;
+
+ port_id = msm_get_port_id(rtd->dai_link->be_id);
+ if (IS_ERR_VALUE(port_id)) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto done;
+ }
+
+ if (enable) {
+ update_mi2s_clk_val(index, substream->stream);
+ dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+ mi2s_clk[index].clk_freq_in_hz);
+ }
+
+ mi2s_clk[index].enable = enable;
+ ret = afe_set_lpass_clock_v2(port_id,
+ &mi2s_clk[index]);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed for port 0x%x , err:%d\n",
+ __func__, port_id, ret);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id;
+ unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__, substream->name, substream->stream,
+ cpu_dai->name, cpu_dai->id);
+
+ if (index < PRIM_MI2S || index > QUAT_MI2S) {
+ ret = -EINVAL;
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, cpu_dai->id);
+ goto done;
+ }
+ /*
+ * Muxtex protection in case the same MI2S
+ * interface using for both TX and RX so
+ * that the same clock won't be enable twice.
+ */
+ mutex_lock(&mi2s_intf_conf[index].lock);
+ if (++mi2s_intf_conf[index].ref_cnt == 1) {
+ ret = msm_mi2s_set_sclk(substream, true);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed to enable MI2S clock, err:%d\n",
+ __func__, ret);
+ goto clean_up;
+ }
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(0,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_muxsel_virt_addr is NULL for dai %d\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto clk_off;
+ }
+ /* Check if msm needs to provide the clock to the interface */
+ if (!mi2s_intf_conf[index].msm_is_mi2s_master)
+ fmt = SND_SOC_DAIFMT_CBM_CFM;
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: set fmt cpu dai failed for MI2S (%d), err:%d\n",
+ __func__, index, ret);
+ goto clk_off;
+ }
+ }
+clk_off:
+ if (IS_ERR_VALUE(ret))
+ msm_mi2s_set_sclk(substream, false);
+clean_up:
+ if (IS_ERR_VALUE(ret))
+ mi2s_intf_conf[index].ref_cnt--;
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+done:
+ return ret;
+}
+
+static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int index = rtd->cpu_dai->id;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ if (index < PRIM_MI2S || index > QUAT_MI2S) {
+ pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index);
+ return;
+ }
+
+ mutex_lock(&mi2s_intf_conf[index].lock);
+ if (--mi2s_intf_conf[index].ref_cnt == 0) {
+ ret = msm_mi2s_set_sclk(substream, false);
+ if (ret < 0) {
+ pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
+ __func__, index, ret);
+ mi2s_intf_conf[index].ref_cnt++;
+ }
+ }
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+}
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .shutdown = msm_mi2s_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_aux_pcm_be_ops = {
+ .startup = msm_aux_pcm_snd_startup,
+ .shutdown = msm_aux_pcm_snd_shutdown,
+};
+
+static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width,
+ int slots)
+{
+ unsigned int slot_mask = 0;
+ int i, j;
+ unsigned int *slot_offset;
+
+ for (i = TDM_0; i < TDM_PORT_MAX; i++) {
+ slot_offset = tdm_slot_offset[i];
+
+ for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) {
+ if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ slot_mask |=
+ (1 << ((slot_offset[j] * 8) / slot_width));
+ else
+ break;
+ }
+ }
+
+ return slot_mask;
+}
+
+static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int channels, slot_width, slots;
+ unsigned int slot_mask;
+ unsigned int *slot_offset;
+ int offset_channels = 0;
+ int i;
+
+ pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+ channels = params_channels(params);
+ switch (channels) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /*
+ * up to 8 channels HW config should
+ * use 32 bit slot width for max support of
+ * stream bit width. (slot_width > bit_width)
+ */
+ slot_width = 32;
+ break;
+ default:
+ pr_err("%s: invalid param format 0x%x\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+ slots = 8;
+ slot_mask = tdm_param_set_slot_mask(cpu_dai->id,
+ slot_width,
+ slots);
+ if (!slot_mask) {
+ pr_err("%s: invalid slot_mask 0x%x\n",
+ __func__, slot_mask);
+ return -EINVAL;
+ }
+ break;
+ default:
+ pr_err("%s: invalid param channels %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ /* currently only supporting TDM_RX_0 and TDM_TX_0 */
+ switch (cpu_dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ slot_offset = tdm_slot_offset[TDM_0];
+ break;
+ default:
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ offset_channels++;
+ else
+ break;
+ }
+
+ if (offset_channels == 0) {
+ pr_err("%s: slot offset not supported, offset_channels %d\n",
+ __func__, offset_channels);
+ return -EINVAL;
+ }
+
+ if (channels > offset_channels) {
+ pr_err("%s: channels %d exceed offset_channels %d\n",
+ __func__, channels, offset_channels);
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ channels, slot_offset);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
+ slot_offset, 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static struct snd_soc_ops msm_be_ops = {
+ .hw_params = msm_snd_hw_params,
+};
+
+static struct snd_soc_ops msm_cpe_ops = {
+ .hw_params = msm_snd_cpe_hw_params,
+};
+
+static struct snd_soc_ops msm_slimbus_2_be_ops = {
+ .hw_params = msm_slimbus_2_hw_params,
+};
+
+static struct snd_soc_ops msm_wcn_ops = {
+ .hw_params = msm_wcn_hw_params,
+};
+
+static struct snd_soc_ops msm_tdm_be_ops = {
+ .hw_params = msm_tdm_snd_hw_params
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_common_dai_links[] = {
+ /* FrontEnd DAI Links */
+ {
+ .name = MSM_DAILINK_NAME(Media1),
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {
+ .name = MSM_DAILINK_NAME(Media2),
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {
+ .name = "VoiceMMode1",
+ .stream_name = "VoiceMMode1",
+ .cpu_dai_name = "VoiceMMode1",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE1,
+ },
+ {
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {
+ .name = MSM_DAILINK_NAME(ULL),
+ .stream_name = "MultiMedia3",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-dsp.2",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Compress1),
+ .stream_name = "Compress1",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = MSM_DAILINK_NAME(LowLatency),
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
+ {
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ /* Multiple Tunnel instances */
+ {
+ .name = MSM_DAILINK_NAME(Compress2),
+ .stream_name = "Compress2",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Compress3),
+ .stream_name = "Compress3",
+ .cpu_dai_name = "MultiMedia10",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+ },
+ {
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ),
+ .stream_name = "MM_NOIRQ",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-pcm-dsp-noirq",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "VoiceMMode2",
+ .stream_name = "VoiceMMode2",
+ .cpu_dai_name = "VoiceMMode2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE2,
+ },
+ /* LSM FE */
+ {
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM6,
+ },
+ {
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Media9),
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Compress4),
+ .stream_name = "Compress4",
+ .cpu_dai_name = "MultiMedia11",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA11,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Compress5),
+ .stream_name = "Compress5",
+ .cpu_dai_name = "MultiMedia12",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA12,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Compress6),
+ .stream_name = "Compress6",
+ .cpu_dai_name = "MultiMedia13",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA13,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Compress7),
+ .stream_name = "Compress7",
+ .cpu_dai_name = "MultiMedia14",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Compress8),
+ .stream_name = "Compress8",
+ .cpu_dai_name = "MultiMedia15",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Compress9),
+ .stream_name = "Compress9",
+ .cpu_dai_name = "MultiMedia16",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA16,
+ },
+ {
+ .name = "SLIMBUS_8 Hostless",
+ .stream_name = "SLIMBUS8_HOSTLESS Capture",
+ .cpu_dai_name = "SLIMBUS8_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+};
+
+static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_slimbus_2_be_ops,
+ },
+ /* CPE LSM direct dai-link */
+ {
+ .name = "CPE Listen service",
+ .stream_name = "CPE Listen Audio Service",
+ .cpu_dai_name = "msm-dai-slim",
+ .platform_name = "msm-cpe-lsm",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "tasha_mad1",
+ .codec_name = "tasha_codec",
+ .ops = &msm_cpe_ops,
+ },
+ {
+ .name = "SLIMBUS_6 Hostless Playback",
+ .stream_name = "SLIMBUS_6 Hostless",
+ .cpu_dai_name = "SLIMBUS6_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* CPE LSM EC PP direct dai-link */
+ {
+ .name = "CPE Listen service ECPP",
+ .stream_name = "CPE Listen Audio Service ECPP",
+ .cpu_dai_name = "CPE_LSM_NOHOST",
+ .platform_name = "msm-cpe-lsm.3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "tasha_cpe",
+ .codec_name = "tasha_codec",
+ },
+};
+
+static struct snd_soc_dai_link msm_tavil_fe_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_slimbus_2_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_common_be_dai_links[] = {
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_RX,
+ .stream_name = "USB Audio Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.28672",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_USB_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_TX,
+ .stream_name = "USB Audio Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.28673",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_USB_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_RX_0,
+ .stream_name = "Primary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36864",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_TX_0,
+ .stream_name = "Primary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36865",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_RX_0,
+ .stream_name = "Secondary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36880",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_TX_0,
+ .stream_name = "Secondary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36881",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_RX_0,
+ .stream_name = "Tertiary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36896",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_TX_0,
+ .stream_name = "Tertiary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36897",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_RX_0,
+ .stream_name = "Quaternary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36912",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_TX_0,
+ .stream_name = "Quaternary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36913",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_tasha_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx3",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_5_RX,
+ .stream_name = "Slimbus5 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16394",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mad1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_6_RX,
+ .stream_name = "Slimbus6 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16396",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx4",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_tavil_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx3",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_2_RX,
+ .stream_name = "Slimbus2 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx2",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_5_RX,
+ .stream_name = "Slimbus5 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16394",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_mad1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_6_RX,
+ .stream_name = "Slimbus6 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16396",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx4",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_7_RX,
+ .stream_name = "Slimbus7 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16398",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ /* BT codec driver determines capabilities based on
+ * dai name, bt codecdai name should always contains
+ * supported usecase information
+ */
+ .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_7_TX,
+ .stream_name = "Slimbus7 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16399",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_bt_sco_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_8_TX,
+ .stream_name = "Slimbus8 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16401",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_fm_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .init = &msm_wcn_init,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link ext_disp_be_dai_link[] = {
+ /* HDMI BACK END DAI Link */
+ {
+ .name = LPASS_BE_HDMI,
+ .stream_name = "HDMI Playback",
+ .cpu_dai_name = "msm-dai-q6-hdmi.8",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-ext-disp-audio-codec-rx",
+ .codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_HDMI_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ /* DISP PORT BACK END DAI Link */
+ {
+ .name = LPASS_BE_DISPLAY_PORT,
+ .stream_name = "Display Port Playback",
+ .cpu_dai_name = "msm-dai-q6-dp.24608",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-ext-disp-audio-codec-rx",
+ .codec_dai_name = "msm_dp_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
+ {
+ .name = LPASS_BE_PRI_MI2S_RX,
+ .stream_name = "Primary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_MI2S_TX,
+ .stream_name = "Primary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_RX,
+ .stream_name = "Secondary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_TX,
+ .stream_name = "Secondary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_RX,
+ .stream_name = "Tertiary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_TX,
+ .stream_name = "Tertiary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_RX,
+ .stream_name = "Quaternary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_TX,
+ .stream_name = "Quaternary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
+ /* Primary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Secondary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_SEC_AUXPCM_RX,
+ .stream_name = "Sec AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SEC_AUXPCM_TX,
+ .stream_name = "Sec AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Tertiary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_TERT_AUXPCM_RX,
+ .stream_name = "Tert AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_TERT_AUXPCM_TX,
+ .stream_name = "Tert AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Quaternary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_RX,
+ .stream_name = "Quat AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_TX,
+ .stream_name = "Quat AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_tasha_dai_links[
+ ARRAY_SIZE(msm_common_dai_links) +
+ ARRAY_SIZE(msm_tasha_fe_dai_links) +
+ ARRAY_SIZE(msm_common_be_dai_links) +
+ ARRAY_SIZE(msm_tasha_be_dai_links) +
+ ARRAY_SIZE(msm_wcn_be_dai_links) +
+ ARRAY_SIZE(ext_disp_be_dai_link) +
+ ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ ARRAY_SIZE(msm_auxpcm_be_dai_links)];
+
+static struct snd_soc_dai_link msm_tavil_dai_links[
+ ARRAY_SIZE(msm_common_dai_links) +
+ ARRAY_SIZE(msm_tavil_fe_dai_links) +
+ ARRAY_SIZE(msm_common_be_dai_links) +
+ ARRAY_SIZE(msm_tavil_be_dai_links) +
+ ARRAY_SIZE(msm_wcn_be_dai_links) +
+ ARRAY_SIZE(ext_disp_be_dai_link) +
+ ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ ARRAY_SIZE(msm_auxpcm_be_dai_links)];
+
+static int msm_snd_card_late_probe(struct snd_soc_card *card)
+{
+ const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
+ void *mbhc_calibration;
+
+ rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+ if (!rtd) {
+ dev_err(card->dev,
+ "%s: snd_soc_get_pcm_runtime for %s failed!\n",
+ __func__, be_dl_name);
+ ret = -EINVAL;
+ goto err_pcm_runtime;
+ }
+
+ mbhc_calibration = def_tasha_mbhc_cal();
+ if (!mbhc_calibration) {
+ ret = -ENOMEM;
+ goto err_mbhc_cal;
+ }
+ wcd_mbhc_cfg.calibration = mbhc_calibration;
+ ret = tasha_mbhc_hs_detect(rtd->codec, &wcd_mbhc_cfg);
+ if (ret) {
+ dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n",
+ __func__, ret);
+ goto err_hs_detect;
+ }
+ return 0;
+
+err_hs_detect:
+ kfree(mbhc_calibration);
+err_mbhc_cal:
+err_pcm_runtime:
+ return ret;
+}
+
+static int msm_snd_card_tavil_late_probe(struct snd_soc_card *card)
+{
+ const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
+ void *mbhc_calibration;
+
+ rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+ if (!rtd) {
+ dev_err(card->dev,
+ "%s: snd_soc_get_pcm_runtime for %s failed!\n",
+ __func__, be_dl_name);
+ ret = -EINVAL;
+ goto err_pcm_runtime;
+ }
+
+ mbhc_calibration = def_tavil_mbhc_cal();
+ if (!mbhc_calibration) {
+ ret = -ENOMEM;
+ goto err_mbhc_cal;
+ }
+ wcd_mbhc_cfg.calibration = mbhc_calibration;
+ ret = tavil_mbhc_hs_detect(rtd->codec, &wcd_mbhc_cfg);
+ if (ret) {
+ dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n",
+ __func__, ret);
+ goto err_hs_detect;
+ }
+ return 0;
+
+err_hs_detect:
+ kfree(mbhc_calibration);
+err_mbhc_cal:
+err_pcm_runtime:
+ return ret;
+}
+
+struct snd_soc_card snd_soc_card_tasha_msm = {
+ .name = "msm8998-tasha-snd-card",
+ .late_probe = msm_snd_card_late_probe,
+};
+
+struct snd_soc_card snd_soc_card_tavil_msm = {
+ .name = "msm8998-tavil-snd-card",
+ .late_probe = msm_snd_card_tavil_late_probe,
+};
+
+static int msm_populate_dai_link_component_of_node(
+ struct snd_soc_card *card)
+{
+ int i, index, ret = 0;
+ struct device *cdev = card->dev;
+ struct snd_soc_dai_link *dai_link = card->dai_link;
+ struct device_node *np;
+
+ if (!cdev) {
+ pr_err("%s: Sound card device memory NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < card->num_links; i++) {
+ if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
+ continue;
+
+ /* populate platform_of_node for snd card dai links */
+ if (dai_link[i].platform_name &&
+ !dai_link[i].platform_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-platform-names",
+ dai_link[i].platform_name);
+ if (index < 0) {
+ pr_err("%s: No match found for platform name: %s\n",
+ __func__, dai_link[i].platform_name);
+ ret = index;
+ goto err;
+ }
+ np = of_parse_phandle(cdev->of_node, "asoc-platform",
+ index);
+ if (!np) {
+ pr_err("%s: retrieving phandle for platform %s, index %d failed\n",
+ __func__, dai_link[i].platform_name,
+ index);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].platform_of_node = np;
+ dai_link[i].platform_name = NULL;
+ }
+
+ /* populate cpu_of_node for snd card dai links */
+ if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-cpu-names",
+ dai_link[i].cpu_dai_name);
+ if (index >= 0) {
+ np = of_parse_phandle(cdev->of_node, "asoc-cpu",
+ index);
+ if (!np) {
+ pr_err("%s: retrieving phandle for cpu dai %s failed\n",
+ __func__,
+ dai_link[i].cpu_dai_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].cpu_of_node = np;
+ dai_link[i].cpu_dai_name = NULL;
+ }
+ }
+
+ /* populate codec_of_node for snd card dai links */
+ if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-codec-names",
+ dai_link[i].codec_name);
+ if (index < 0)
+ continue;
+ np = of_parse_phandle(cdev->of_node, "asoc-codec",
+ index);
+ if (!np) {
+ pr_err("%s: retrieving phandle for codec %s failed\n",
+ __func__, dai_link[i].codec_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].codec_of_node = np;
+ dai_link[i].codec_name = NULL;
+ }
+ }
+
+err:
+ return ret;
+}
+
+static int msm_prepare_us_euro(struct snd_soc_card *card)
+{
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int ret = 0;
+
+ if (pdata->us_euro_gpio >= 0) {
+ dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__,
+ pdata->us_euro_gpio);
+ ret = gpio_request(pdata->us_euro_gpio, "TASHA_CODEC_US_EURO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request codec US/EURO gpio %d error %d\n",
+ __func__, pdata->us_euro_gpio, ret);
+ }
+ }
+
+ return ret;
+}
+
+static int msm_audrx_stub_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+ ret = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (ret < 0) {
+ dev_err(codec->dev, "%s: add_codec_controls failed, err%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
+ ARRAY_SIZE(msm_dapm_widgets));
+
+ return 0;
+}
+
+static int msm_snd_stub_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ int ret = 0;
+ unsigned int rx_ch[] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ slim_rx_cfg[0].channels,
+ rx_ch);
+ if (ret < 0)
+ pr_err("%s: RX failed to set cpu chan map error %d\n",
+ __func__, ret);
+ } else {
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ slim_tx_cfg[0].channels,
+ tx_ch, 0, 0);
+ if (ret < 0)
+ pr_err("%s: TX failed to set cpu chan map error %d\n",
+ __func__, ret);
+ }
+
+ return ret;
+}
+
+static struct snd_soc_ops msm_stub_be_ops = {
+ .hw_params = msm_snd_stub_hw_params,
+};
+
+static struct snd_soc_dai_link msm_stub_fe_dai_links[] = {
+
+ /* FrontEnd DAI Links */
+ {
+ .name = "MSMSTUB Media1",
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+};
+
+static struct snd_soc_dai_link msm_stub_be_dai_links[] = {
+
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_stub_init,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .ignore_suspend = 1,
+ .ops = &msm_stub_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_stub_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_stub_dai_links[
+ ARRAY_SIZE(msm_stub_fe_dai_links) +
+ ARRAY_SIZE(msm_stub_be_dai_links)];
+
+struct snd_soc_card snd_soc_card_stub_msm = {
+ .name = "msm8998-stub-snd-card",
+};
+
+static const struct of_device_id msm8998_asoc_machine_of_match[] = {
+ { .compatible = "qcom,msm8998-asoc-snd-tasha",
+ .data = "tasha_codec"},
+ { .compatible = "qcom,msm8998-asoc-snd-tavil",
+ .data = "tavil_codec"},
+ { .compatible = "qcom,msm8998-asoc-snd-stub",
+ .data = "stub_codec"},
+ {},
+};
+
+static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
+{
+ struct snd_soc_card *card = NULL;
+ struct snd_soc_dai_link *dailink;
+ int len_1, len_2, len_3;
+ int total_links;
+ const struct of_device_id *match;
+
+ match = of_match_node(msm8998_asoc_machine_of_match, dev->of_node);
+ if (!match) {
+ dev_err(dev, "%s: No DT match found for sound card\n",
+ __func__);
+ return NULL;
+ }
+
+ if (!strcmp(match->data, "tasha_codec")) {
+ card = &snd_soc_card_tasha_msm;
+ len_1 = ARRAY_SIZE(msm_common_dai_links);
+ len_2 = len_1 + ARRAY_SIZE(msm_tasha_fe_dai_links);
+ len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
+ total_links = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links);
+ memcpy(msm_tasha_dai_links,
+ msm_common_dai_links,
+ sizeof(msm_common_dai_links));
+ memcpy(msm_tasha_dai_links + len_1,
+ msm_tasha_fe_dai_links,
+ sizeof(msm_tasha_fe_dai_links));
+ memcpy(msm_tasha_dai_links + len_2,
+ msm_common_be_dai_links,
+ sizeof(msm_common_be_dai_links));
+ memcpy(msm_tasha_dai_links + len_3,
+ msm_tasha_be_dai_links,
+ sizeof(msm_tasha_be_dai_links));
+
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(msm_tasha_dai_links + total_links,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
+ total_links += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
+
+ if (of_property_read_bool(dev->of_node,
+ "qcom,ext-disp-audio-rx")) {
+ dev_dbg(dev, "%s(): External display audio support present\n",
+ __func__);
+ memcpy(msm_tasha_dai_links + total_links,
+ ext_disp_be_dai_link,
+ sizeof(ext_disp_be_dai_link));
+ total_links += ARRAY_SIZE(ext_disp_be_dai_link);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,mi2s-audio-intf")) {
+ memcpy(msm_tasha_dai_links + total_links,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ total_links += ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,auxpcm-audio-intf")) {
+ memcpy(msm_tasha_dai_links + total_links,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ total_links += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ dailink = msm_tasha_dai_links;
+ } else if (!strcmp(match->data, "tavil_codec")) {
+ card = &snd_soc_card_tavil_msm;
+ len_1 = ARRAY_SIZE(msm_common_dai_links);
+ len_2 = len_1 + ARRAY_SIZE(msm_tavil_fe_dai_links);
+ len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
+ total_links = len_3 + ARRAY_SIZE(msm_tavil_be_dai_links);
+ memcpy(msm_tavil_dai_links,
+ msm_common_dai_links,
+ sizeof(msm_common_dai_links));
+ memcpy(msm_tavil_dai_links + len_1,
+ msm_tavil_fe_dai_links,
+ sizeof(msm_tavil_fe_dai_links));
+ memcpy(msm_tavil_dai_links + len_2,
+ msm_common_be_dai_links,
+ sizeof(msm_common_be_dai_links));
+ memcpy(msm_tavil_dai_links + len_3,
+ msm_tavil_be_dai_links,
+ sizeof(msm_tavil_be_dai_links));
+
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(msm_tavil_dai_links + total_links,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
+ total_links += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
+
+ if (of_property_read_bool(dev->of_node,
+ "qcom,ext-disp-audio-rx")) {
+ dev_dbg(dev, "%s(): ext disp audio support present\n",
+ __func__);
+ memcpy(msm_tavil_dai_links + total_links,
+ ext_disp_be_dai_link,
+ sizeof(ext_disp_be_dai_link));
+ total_links += ARRAY_SIZE(ext_disp_be_dai_link);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,mi2s-audio-intf")) {
+ memcpy(msm_tavil_dai_links + total_links,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ total_links += ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,auxpcm-audio-intf")) {
+ memcpy(msm_tavil_dai_links + total_links,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ total_links += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ dailink = msm_tavil_dai_links;
+ } else if (!strcmp(match->data, "stub_codec")) {
+ card = &snd_soc_card_stub_msm;
+ len_1 = ARRAY_SIZE(msm_stub_fe_dai_links);
+ len_2 = len_1 + ARRAY_SIZE(msm_stub_be_dai_links);
+
+ memcpy(msm_stub_dai_links,
+ msm_stub_fe_dai_links,
+ sizeof(msm_stub_fe_dai_links));
+ memcpy(msm_stub_dai_links + len_1,
+ msm_stub_be_dai_links,
+ sizeof(msm_stub_be_dai_links));
+
+ dailink = msm_stub_dai_links;
+ total_links = len_2;
+ }
+
+ if (card) {
+ card->dai_link = dailink;
+ card->num_links = total_links;
+ }
+
+ return card;
+}
+
+static int msm_wsa881x_init(struct snd_soc_component *component)
+{
+ u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106};
+ u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107};
+ unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
+ unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+ struct msm_asoc_mach_data *pdata;
+ struct snd_soc_dapm_context *dapm;
+ int ret = 0;
+
+ if (!codec) {
+ pr_err("%s codec is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dapm = snd_soc_codec_get_dapm(codec);
+
+ if (!strcmp(component->name_prefix, "SpkrLeft")) {
+ dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n",
+ __func__, codec->component.name);
+ wsa881x_set_channel_map(codec, &spkleft_ports[0],
+ WSA881X_MAX_SWR_PORTS, &ch_mask[0],
+ &ch_rate[0]);
+ if (dapm->component) {
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
+ }
+ } else if (!strcmp(component->name_prefix, "SpkrRight")) {
+ dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n",
+ __func__, codec->component.name);
+ wsa881x_set_channel_map(codec, &spkright_ports[0],
+ WSA881X_MAX_SWR_PORTS, &ch_mask[0],
+ &ch_rate[0]);
+ if (dapm->component) {
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
+ }
+ } else {
+ dev_err(codec->dev, "%s: wrong codec name %s\n", __func__,
+ codec->component.name);
+ ret = -EINVAL;
+ goto err_codec;
+ }
+ pdata = snd_soc_card_get_drvdata(component->card);
+ if (pdata && pdata->codec_root)
+ wsa881x_codec_info_create_codec_entry(pdata->codec_root,
+ codec);
+
+err_codec:
+ return ret;
+}
+
+static int msm_init_wsa_dev(struct platform_device *pdev,
+ struct snd_soc_card *card)
+{
+ struct device_node *wsa_of_node;
+ u32 wsa_max_devs;
+ u32 wsa_dev_cnt;
+ int i;
+ struct msm_wsa881x_dev_info *wsa881x_dev_info;
+ const char *wsa_auxdev_name_prefix[1];
+ char *dev_name_str = NULL;
+ int found = 0;
+ int ret = 0;
+
+ /* Get maximum WSA device count for this platform */
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,wsa-max-devs", &wsa_max_devs);
+ if (ret) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa-max-devs property missing in DT %s, ret = %d\n",
+ __func__, pdev->dev.of_node->full_name, ret);
+ goto err_dt;
+ }
+ if (wsa_max_devs == 0) {
+ dev_warn(&pdev->dev,
+ "%s: Max WSA devices is 0 for this target?\n",
+ __func__);
+ goto err_dt;
+ }
+
+ /* Get count of WSA device phandles for this platform */
+ wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
+ "qcom,wsa-devs", NULL);
+ if (wsa_dev_cnt == -ENOENT) {
+ dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
+ __func__);
+ goto err_dt;
+ } else if (wsa_dev_cnt <= 0) {
+ dev_err(&pdev->dev,
+ "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
+ __func__, wsa_dev_cnt);
+ ret = -EINVAL;
+ goto err_dt;
+ }
+
+ /*
+ * Expect total phandles count to be NOT less than maximum possible
+ * WSA count. However, if it is less, then assign same value to
+ * max count as well.
+ */
+ if (wsa_dev_cnt < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
+ __func__, wsa_max_devs, wsa_dev_cnt);
+ wsa_max_devs = wsa_dev_cnt;
+ }
+
+ /* Make sure prefix string passed for each WSA device */
+ ret = of_property_count_strings(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix");
+ if (ret != wsa_dev_cnt) {
+ dev_err(&pdev->dev,
+ "%s: expecting %d wsa prefix. Defined only %d in DT\n",
+ __func__, wsa_dev_cnt, ret);
+ ret = -EINVAL;
+ goto err_dt;
+ }
+
+ /*
+ * Alloc mem to store phandle and index info of WSA device, if already
+ * registered with ALSA core
+ */
+ wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
+ sizeof(struct msm_wsa881x_dev_info),
+ GFP_KERNEL);
+ if (!wsa881x_dev_info) {
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ /*
+ * search and check whether all WSA devices are already
+ * registered with ALSA core or not. If found a node, store
+ * the node and the index in a local array of struct for later
+ * use.
+ */
+ for (i = 0; i < wsa_dev_cnt; i++) {
+ wsa_of_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,wsa-devs", i);
+ if (unlikely(!wsa_of_node)) {
+ /* we should not be here */
+ dev_err(&pdev->dev,
+ "%s: wsa dev node is not present\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_dev_node;
+ }
+ if (soc_find_component(wsa_of_node, NULL)) {
+ /* WSA device registered with ALSA core */
+ wsa881x_dev_info[found].of_node = wsa_of_node;
+ wsa881x_dev_info[found].index = i;
+ found++;
+ if (found == wsa_max_devs)
+ break;
+ }
+ }
+
+ if (found < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: failed to find %d components. Found only %d\n",
+ __func__, wsa_max_devs, found);
+ return -EPROBE_DEFER;
+ }
+ dev_info(&pdev->dev,
+ "%s: found %d wsa881x devices registered with ALSA core\n",
+ __func__, found);
+
+ card->num_aux_devs = wsa_max_devs;
+ card->num_configs = wsa_max_devs;
+
+ /* Alloc array of AUX devs struct */
+ msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_aux_dev),
+ GFP_KERNEL);
+ if (!msm_aux_dev) {
+ ret = -ENOMEM;
+ goto err_auxdev_mem;
+ }
+
+ /* Alloc array of codec conf struct */
+ msm_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_codec_conf),
+ GFP_KERNEL);
+ if (!msm_codec_conf) {
+ ret = -ENOMEM;
+ goto err_codec_conf;
+ }
+
+ for (i = 0; i < card->num_aux_devs; i++) {
+ dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
+ GFP_KERNEL);
+ if (!dev_name_str) {
+ ret = -ENOMEM;
+ goto err_dev_str;
+ }
+
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix",
+ wsa881x_dev_info[i].index,
+ wsa_auxdev_name_prefix);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: failed to read wsa aux dev prefix, ret = %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto err_dt_prop;
+ }
+
+ snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
+ msm_aux_dev[i].name = dev_name_str;
+ msm_aux_dev[i].codec_name = NULL;
+ msm_aux_dev[i].codec_of_node =
+ wsa881x_dev_info[i].of_node;
+ msm_aux_dev[i].init = msm_wsa881x_init;
+ msm_codec_conf[i].dev_name = NULL;
+ msm_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0];
+ msm_codec_conf[i].of_node =
+ wsa881x_dev_info[i].of_node;
+ }
+ card->codec_conf = msm_codec_conf;
+ card->aux_dev = msm_aux_dev;
+
+ return 0;
+
+err_dt_prop:
+ devm_kfree(&pdev->dev, dev_name_str);
+err_dev_str:
+ devm_kfree(&pdev->dev, msm_codec_conf);
+err_codec_conf:
+ devm_kfree(&pdev->dev, msm_aux_dev);
+err_auxdev_mem:
+err_dev_node:
+ devm_kfree(&pdev->dev, wsa881x_dev_info);
+err_mem:
+err_dt:
+ return ret;
+}
+
+static void i2s_auxpcm_init(struct platform_device *pdev)
+{
+ struct resource *muxsel;
+ int count;
+ u32 mi2s_master_slave[MI2S_MAX];
+ int ret;
+ char *str[PCM_I2S_SEL_MAX] = {
+ "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel"
+ };
+
+ for (count = 0; count < MI2S_MAX; count++) {
+ mutex_init(&mi2s_intf_conf[count].lock);
+ mi2s_intf_conf[count].ref_cnt = 0;
+ }
+
+ for (count = 0; count < AUX_PCM_MAX; count++) {
+ mutex_init(&auxpcm_intf_conf[count].lock);
+ auxpcm_intf_conf[count].ref_cnt = 0;
+ }
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++) {
+ mutex_init(&mi2s_auxpcm_conf[count].lock);
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr = NULL;
+ }
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++) {
+ muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ str[count]);
+ if (muxsel) {
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr
+ = ioremap(muxsel->start, resource_size(muxsel));
+ }
+ }
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-mi2s-master",
+ mi2s_master_slave, MI2S_MAX);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n",
+ __func__);
+ } else {
+ for (count = 0; count < MI2S_MAX; count++) {
+ mi2s_intf_conf[count].msm_is_mi2s_master =
+ mi2s_master_slave[count];
+ }
+ }
+}
+
+static void i2s_auxpcm_deinit(void)
+{
+ int count;
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++)
+ if (mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr !=
+ NULL)
+ iounmap(
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr);
+}
+
+static int msm_asoc_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct msm_asoc_mach_data *pdata;
+ const char *mbhc_audio_jack_type = NULL;
+ char *mclk_freq_prop_name;
+ const struct of_device_id *match;
+ int ret;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "No platform supplied from device tree\n");
+ return -EINVAL;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_asoc_mach_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ card = populate_snd_card_dailinks(&pdev->dev);
+ if (!card) {
+ dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, pdata);
+
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret) {
+ dev_err(&pdev->dev, "parse card name failed, err:%d\n",
+ ret);
+ goto err;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "parse audio routing failed, err:%d\n",
+ ret);
+ goto err;
+ }
+
+ match = of_match_node(msm8998_asoc_machine_of_match,
+ pdev->dev.of_node);
+ if (!match) {
+ dev_err(&pdev->dev, "%s: no matched codec is found.\n",
+ __func__);
+ goto err;
+ }
+
+ if (!strcmp(match->data, "tasha_codec"))
+ mclk_freq_prop_name = "qcom,tasha-mclk-clk-freq";
+ else
+ mclk_freq_prop_name = "qcom,tavil-mclk-clk-freq";
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ mclk_freq_prop_name, &pdata->mclk_freq);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed, err%d\n",
+ mclk_freq_prop_name,
+ pdev->dev.of_node->full_name, ret);
+ goto err;
+ }
+
+ if (pdata->mclk_freq != CODEC_EXT_CLK_RATE) {
+ dev_err(&pdev->dev, "unsupported mclk freq %u\n",
+ pdata->mclk_freq);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = msm_populate_dai_link_component_of_node(card);
+ if (ret) {
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ ret = msm_init_wsa_dev(pdev, card);
+ if (ret)
+ goto err;
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret == -EPROBE_DEFER) {
+ if (codec_reg_done)
+ ret = -EINVAL;
+ goto err;
+ } else if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err;
+ }
+ dev_info(&pdev->dev, "Sound card %s registered\n", card->name);
+ spdev = pdev;
+
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: failed to add child nodes, ret=%d\n",
+ __func__, ret);
+ } else {
+ pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,hph-en1-gpio", 0);
+ if (!pdata->hph_en1_gpio_p) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,hph-en1-gpio",
+ pdev->dev.of_node->full_name);
+ }
+
+ pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,hph-en0-gpio", 0);
+ if (!pdata->hph_en0_gpio_p) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,hph-en0-gpio",
+ pdev->dev.of_node->full_name);
+ }
+ }
+
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type);
+ if (ret) {
+ dev_dbg(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,mbhc-audio-jack-type",
+ pdev->dev.of_node->full_name);
+ dev_dbg(&pdev->dev, "Jack type properties set to default");
+ } else {
+ if (!strcmp(mbhc_audio_jack_type, "4-pole-jack"))
+ dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
+ else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack"))
+ dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
+ else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack"))
+ dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
+ else
+ dev_dbg(&pdev->dev, "Unknown value, set to default");
+ }
+ /*
+ * Parse US-Euro gpio info from DT. Report no error if us-euro
+ * entry is not found in DT file as some targets do not support
+ * US-Euro detection
+ */
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (!gpio_is_valid(pdata->us_euro_gpio))
+ pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (!gpio_is_valid(pdata->us_euro_gpio) && (!pdata->us_euro_gpio_p)) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,us-euro-gpios", pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected",
+ "qcom,us-euro-gpios");
+ wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic;
+ }
+
+ ret = msm_prepare_us_euro(card);
+ if (ret)
+ dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
+ ret);
+
+ i2s_auxpcm_init(pdev);
+
+ is_initial_boot = true;
+ ret = audio_notifier_register("msm8998", AUDIO_NOTIFIER_ADSP_DOMAIN,
+ &service_nb);
+ if (ret < 0)
+ pr_err("%s: Audio notifier register failed ret = %d\n",
+ __func__, ret);
+
+ return 0;
+err:
+ if (pdata->us_euro_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ pdata->us_euro_gpio = 0;
+ }
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+
+static int msm_asoc_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+
+ gpio_free(pdata->us_euro_gpio);
+ i2s_auxpcm_deinit();
+
+ snd_soc_unregister_card(card);
+ return 0;
+}
+
+static struct platform_driver msm8998_asoc_machine_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = msm8998_asoc_machine_of_match,
+ },
+ .probe = msm_asoc_machine_probe,
+ .remove = msm_asoc_machine_remove,
+};
+module_platform_driver(msm8998_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, msm8998_asoc_machine_of_match);
diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/msmfalcon-common.c
new file mode 100644
index 0000000..5928982
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-common.c
@@ -0,0 +1,2806 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/input.h>
+#include <linux/of_gpio.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <sound/pcm_params.h>
+#include <sound/q6afe-v2.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "msm-audio-pinctrl.h"
+#include "msmfalcon-common.h"
+#include "msmfalcon-internal.h"
+#include "msmfalcon-external.h"
+#include "../codecs/msm8x16/msm8x16-wcd.h"
+#include "../codecs/wsa881x.h"
+
+#define DRV_NAME "msmfalcon-asoc-snd"
+
+#define DEV_NAME_STR_LEN 32
+#define DEFAULT_MCLK_RATE 9600000
+
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+/* TDM default config */
+static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* SEC TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* TERT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* QUAT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ }
+};
+
+/* TDM default config */
+static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* SEC TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* TERT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ },
+ { /* QUAT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ }
+};
+
+static struct dev_config usb_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
+static struct dev_config usb_tx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 1,
+};
+
+enum {
+ PRIM_MI2S = 0,
+ SEC_MI2S,
+ TERT_MI2S,
+ QUAT_MI2S,
+ MI2S_MAX,
+};
+
+enum {
+ PRIM_AUX_PCM = 0,
+ SEC_AUX_PCM,
+ TERT_AUX_PCM,
+ QUAT_AUX_PCM,
+ AUX_PCM_MAX,
+};
+
+enum {
+ PCM_I2S_SEL_PRIM = 0,
+ PCM_I2S_SEL_SEC,
+ PCM_I2S_SEL_TERT,
+ PCM_I2S_SEL_QUAT,
+ PCM_I2S_SEL_MAX,
+};
+
+struct mi2s_aux_pcm_common_conf {
+ struct mutex lock;
+ void *pcm_i2s_sel_vt_addr;
+};
+
+struct mi2s_conf {
+ struct mutex lock;
+ u32 ref_cnt;
+ u32 msm_is_mi2s_master;
+};
+
+struct auxpcm_conf {
+ struct mutex lock;
+ u32 ref_cnt;
+};
+
+struct msm_wsa881x_dev_info {
+ struct device_node *of_node;
+ u32 index;
+};
+static struct snd_soc_aux_dev *msm_aux_dev;
+static struct snd_soc_codec_conf *msm_codec_conf;
+
+static bool msm_swap_gnd_mic(struct snd_soc_codec *codec);
+
+static struct wcd_mbhc_config mbhc_cfg = {
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .detect_extn_cable = true,
+ .mono_stero_detection = false,
+ .swap_gnd_mic = NULL,
+ .hs_ext_micbias = false,
+ .key_code[0] = KEY_MEDIA,
+ .key_code[1] = KEY_VOICECOMMAND,
+ .key_code[2] = KEY_VOLUMEUP,
+ .key_code[3] = KEY_VOLUMEDOWN,
+ .key_code[4] = 0,
+ .key_code[5] = 0,
+ .key_code[6] = 0,
+ .key_code[7] = 0,
+ .linein_th = 5000,
+ .moisture_en = false,
+ .mbhc_micbias = 0,
+ .anc_micbias = 0,
+ .enable_anc_mic_detect = false,
+};
+
+static struct dev_config proxy_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
+/* Default configuration of MI2S channels */
+static struct dev_config mi2s_rx_cfg[] = {
+ [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static struct dev_config mi2s_tx_cfg[] = {
+ [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config aux_pcm_rx_cfg[] = {
+ [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config aux_pcm_tx_cfg[] = {
+ [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static char const *ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
+static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
+static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_96", "KHZ_192"};
+static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+ "S32_LE"};
+static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
+static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
+static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
+ "KHZ_44P1", "KHZ_48", "KHZ_96",
+ "KHZ_192", "KHZ_352P8", "KHZ_384"};
+static const char *const usb_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
+ "KHZ_16", "KHZ_22P05",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_96", "KHZ_192", "KHZ_384"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
+
+static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ }
+};
+
+static struct mi2s_aux_pcm_common_conf mi2s_auxpcm_conf[PCM_I2S_SEL_MAX];
+static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
+static struct auxpcm_conf auxpcm_intf_conf[AUX_PCM_MAX];
+
+static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: proxy_rx channels = %d\n",
+ __func__, proxy_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = proxy_rx_cfg.channels - 2;
+
+ return 0;
+}
+
+static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ proxy_rx_cfg.channels = ucontrol->value.integer.value[0] + 2;
+ pr_debug("%s: proxy_rx channels = %d\n",
+ __func__, proxy_rx_cfg.channels);
+
+ return 1;
+}
+
+static int tdm_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 7:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 8:
+ sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int tdm_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 8;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
+ struct tdm_port *port)
+{
+ if (port) {
+ if (strnstr(kcontrol->id.name, "PRI",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_PRI;
+ } else if (strnstr(kcontrol->id.name, "SEC",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_SEC;
+ } else if (strnstr(kcontrol->id.name, "TERT",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_TERT;
+ } else if (strnstr(kcontrol->id.name, "QUAT",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_QUAT;
+ } else {
+ pr_err("%s: unsupported mode in: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ if (strnstr(kcontrol->id.name, "RX_0",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_0",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_0;
+ } else if (strnstr(kcontrol->id.name, "RX_1",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_1",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_1;
+ } else if (strnstr(kcontrol->id.name, "RX_2",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_2",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_2;
+ } else if (strnstr(kcontrol->id.name, "RX_3",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_3",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_3;
+ } else if (strnstr(kcontrol->id.name, "RX_4",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_4",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_4;
+ } else if (strnstr(kcontrol->id.name, "RX_5",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_5",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_5;
+ } else if (strnstr(kcontrol->id.name, "RX_6",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_6",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_6;
+ } else if (strnstr(kcontrol->id.name, "RX_7",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_7",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_7;
+ } else {
+ pr_err("%s: unsupported channel in: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
+ tdm_rx_cfg[port.mode][port.channel].sample_rate);
+
+ pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].sample_rate =
+ tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
+ tdm_tx_cfg[port.mode][port.channel].sample_rate);
+
+ pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].sample_rate =
+ tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_get_format(int value)
+{
+ int format = 0;
+
+ switch (value) {
+ case 0:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return format;
+}
+
+static int tdm_get_format_val(int format)
+{
+ int value = 0;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ value = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ value = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ value = 2;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ return value;
+}
+
+static int tdm_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_format_val(
+ tdm_rx_cfg[port.mode][port.channel].bit_format);
+
+ pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].bit_format =
+ tdm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_format_val(
+ tdm_tx_cfg[port.mode][port.channel].bit_format);
+
+ pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].bit_format =
+ tdm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+
+ ucontrol->value.enumerated.item[0] =
+ tdm_rx_cfg[port.mode][port.channel].channels - 1;
+
+ pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].channels - 1,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].channels,
+ ucontrol->value.enumerated.item[0] + 1);
+ }
+ return ret;
+}
+
+static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] =
+ tdm_tx_cfg[port.mode][port.channel].channels - 1;
+
+ pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].channels - 1,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].channels,
+ ucontrol->value.enumerated.item[0] + 1);
+ }
+ return ret;
+}
+
+static int aux_pcm_get_sample_rate(int value)
+{
+ int sample_rate;
+
+ switch (value) {
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 0:
+ default:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int aux_pcm_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx;
+
+ if (strnstr(kcontrol->id.name, "PRIM_AUX_PCM",
+ sizeof("PRIM_AUX_PCM")))
+ idx = PRIM_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "SEC_AUX_PCM",
+ sizeof("SEC_AUX_PCM")))
+ idx = SEC_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "TERT_AUX_PCM",
+ sizeof("TERT_AUX_PCM")))
+ idx = TERT_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM",
+ sizeof("QUAT_AUX_PCM")))
+ idx = QUAT_AUX_PCM;
+ else {
+ pr_err("%s: unsupported port: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_rx_cfg[idx].sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(aux_pcm_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_tx_cfg[idx].sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(aux_pcm_tx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx;
+
+ if (strnstr(kcontrol->id.name, "PRIM_MI2S_RX",
+ sizeof("PRIM_MI2S_RX")))
+ idx = PRIM_MI2S;
+ else if (strnstr(kcontrol->id.name, "SEC_MI2S_RX",
+ sizeof("SEC_MI2S_RX")))
+ idx = SEC_MI2S;
+ else if (strnstr(kcontrol->id.name, "TERT_MI2S_RX",
+ sizeof("TERT_MI2S_RX")))
+ idx = TERT_MI2S;
+ else if (strnstr(kcontrol->id.name, "QUAT_MI2S_RX",
+ sizeof("QUAT_MI2S_RX")))
+ idx = QUAT_MI2S;
+ else if (strnstr(kcontrol->id.name, "PRIM_MI2S_TX",
+ sizeof("PRIM_MI2S_TX")))
+ idx = PRIM_MI2S;
+ else if (strnstr(kcontrol->id.name, "SEC_MI2S_TX",
+ sizeof("SEC_MI2S_TX")))
+ idx = SEC_MI2S;
+ else if (strnstr(kcontrol->id.name, "TERT_MI2S_TX",
+ sizeof("TERT_MI2S_TX")))
+ idx = TERT_MI2S;
+ else if (strnstr(kcontrol->id.name, "QUAT_MI2S_TX",
+ sizeof("QUAT_MI2S_TX")))
+ idx = QUAT_MI2S;
+ else {
+ pr_err("%s: unsupported channel: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int mi2s_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 6;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int mi2s_get_sample_rate(int value)
+{
+ int sample_rate;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(mi2s_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(mi2s_tx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = mi2s_rx_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].channels);
+
+ return 1;
+}
+
+static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = mi2s_tx_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].channels);
+
+ return 1;
+}
+
+static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: usb_audio_rx_ch = %d\n", __func__,
+ usb_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = usb_rx_cfg.channels - 1;
+ return 0;
+}
+
+static int usb_audio_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ usb_rx_cfg.channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, usb_rx_cfg.channels);
+ return 1;
+}
+
+static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+
+ switch (usb_rx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: usb_audio_rx_sample_rate = %d\n", __func__,
+ usb_rx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 9:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 8:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 7:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, usb_audio_rx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ usb_rx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (usb_rx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+static int usb_audio_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: usb_audio_tx_ch = %d\n", __func__,
+ usb_tx_cfg.channels);
+ ucontrol->value.integer.value[0] = usb_tx_cfg.channels - 1;
+ return 0;
+}
+
+static int usb_audio_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ usb_tx_cfg.channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, usb_tx_cfg.channels);
+ return 1;
+}
+
+static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+
+ switch (usb_tx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ default:
+ sample_rate_val = 6;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: usb_audio_tx_sample_rate = %d\n", __func__,
+ usb_tx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 9:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 8:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 7:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, usb_audio_tx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ usb_tx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (usb_tx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_tx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_tx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+const struct snd_kcontrol_new msm_common_snd_controls[] = {
+ SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
+ proxy_rx_ch_get, proxy_rx_ch_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_RX SampleRate", sec_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_RX SampleRate", tert_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_RX SampleRate", quat_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_TX SampleRate", sec_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_TX SampleRate", tert_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_TX SampleRate", quat_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX SampleRate", prim_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX SampleRate", sec_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX SampleRate", tert_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX SampleRate", quat_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX SampleRate", prim_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", sec_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX SampleRate", tert_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX Channels", sec_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX Channels", sec_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX Channels", tert_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX Channels", tert_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX Channels", quat_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX Channels", usb_rx_chs,
+ usb_audio_rx_ch_get, usb_audio_rx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs,
+ usb_audio_tx_ch_get, usb_audio_tx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format,
+ usb_audio_rx_format_get, usb_audio_rx_format_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format,
+ usb_audio_tx_format_get, usb_audio_tx_format_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate,
+ usb_audio_rx_sample_rate_get,
+ usb_audio_rx_sample_rate_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate,
+ usb_audio_tx_sample_rate_get,
+ usb_audio_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+};
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
+ int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+/**
+ * msm_common_be_hw_params_fixup - updates settings of ALSA BE hw params.
+ *
+ * @rtd: runtime dailink instance
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0.
+ */
+int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ int rc = 0;
+
+ pr_debug("%s: format = %d, rate = %d\n",
+ __func__, params_format(params), params_rate(params));
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_USB_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ usb_rx_cfg.bit_format);
+ rate->min = rate->max = usb_rx_cfg.sample_rate;
+ channels->min = channels->max = usb_rx_cfg.channels;
+ break;
+
+ case MSM_BACKEND_DAI_USB_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ usb_tx_cfg.bit_format);
+ rate->min = rate->max = usb_tx_cfg.sample_rate;
+ channels->min = channels->max = usb_tx_cfg.channels;
+ break;
+
+ case MSM_BACKEND_DAI_AFE_PCM_RX:
+ channels->min = channels->max = proxy_rx_cfg.channels;
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[SEC_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[SEC_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[SEC_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[SEC_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[TERT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[TERT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[TERT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[TERT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[PRIM_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[PRIM_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[SEC_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[SEC_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[TERT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[TERT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[QUAT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[QUAT_MI2S].channels;
+ break;
+
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return rc;
+}
+EXPORT_SYMBOL(msm_common_be_hw_params_fixup);
+
+/**
+ * msm_aux_pcm_snd_startup - startup ops of auxpcm.
+ *
+ * @substream: PCM stream pointer of associated backend dailink
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_aux_pcm_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id - 1;
+ return ret = 0;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__, substream->name, substream->stream,
+ cpu_dai->name, cpu_dai->id);
+
+ if (index < PRIM_AUX_PCM || index > QUAT_AUX_PCM) {
+ ret = -EINVAL;
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, cpu_dai->id);
+ goto done;
+ }
+
+ mutex_lock(&auxpcm_intf_conf[index].lock);
+ if (++auxpcm_intf_conf[index].ref_cnt == 1) {
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(1,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_tert_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ }
+ if (IS_ERR_VALUE(ret))
+ auxpcm_intf_conf[index].ref_cnt--;
+
+ mutex_unlock(&auxpcm_intf_conf[index].lock);
+
+done:
+ return ret;
+}
+EXPORT_SYMBOL(msm_aux_pcm_snd_startup);
+
+/**
+ * msm_aux_pcm_snd_shutdown - shutdown ops of auxpcm.
+ *
+ * @substream: PCM stream pointer of associated backend dailink
+ */
+void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int index = rtd->cpu_dai->id - 1;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__,
+ substream->name, substream->stream,
+ rtd->cpu_dai->name, rtd->cpu_dai->id);
+
+ if (index < PRIM_AUX_PCM || index > QUAT_AUX_PCM) {
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, rtd->cpu_dai->id);
+ return;
+ }
+
+ mutex_lock(&auxpcm_intf_conf[index].lock);
+ if (--auxpcm_intf_conf[index].ref_cnt == 0) {
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(0,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_tert_muxsel_virt_addr is NULL\n",
+ __func__);
+ auxpcm_intf_conf[index].ref_cnt++;
+ }
+ }
+ mutex_unlock(&auxpcm_intf_conf[index].lock);
+}
+EXPORT_SYMBOL(msm_aux_pcm_snd_shutdown);
+
+static int msm_get_port_id(int be_id)
+{
+ int afe_port_id;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_PRI_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_PRI_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
+ default:
+ pr_err("%s: Invalid be_id: %d\n", __func__, be_id);
+ afe_port_id = -EINVAL;
+ }
+
+ return afe_port_id;
+}
+
+static u32 get_mi2s_bits_per_sample(u32 bit_format)
+{
+ u32 bit_per_sample;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_per_sample = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_per_sample = 16;
+ break;
+ }
+
+ return bit_per_sample;
+}
+
+static void update_mi2s_clk_val(int dai_id, int stream)
+{
+ u32 bit_per_sample;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(mi2s_rx_cfg[dai_id].bit_format);
+ mi2s_clk[dai_id].clk_freq_in_hz =
+ mi2s_rx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
+ } else {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(mi2s_tx_cfg[dai_id].bit_format);
+ mi2s_clk[dai_id].clk_freq_in_hz =
+ mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
+ }
+
+ if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
+ mi2s_clk[dai_id].clk_freq_in_hz = 0;
+}
+
+static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int port_id = 0;
+ int index = cpu_dai->id;
+
+ port_id = msm_get_port_id(rtd->dai_link->be_id);
+ if (IS_ERR_VALUE(port_id)) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto done;
+ }
+
+ if (enable) {
+ update_mi2s_clk_val(index, substream->stream);
+ dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+ mi2s_clk[index].clk_freq_in_hz);
+ }
+
+ mi2s_clk[index].enable = enable;
+ ret = afe_set_lpass_clock_v2(port_id,
+ &mi2s_clk[index]);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed for port 0x%x , err:%d\n",
+ __func__, port_id, ret);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+/**
+ * msm_mi2s_snd_startup - startup ops of mi2s.
+ *
+ * @substream: PCM stream pointer of associated backend dailink
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id;
+ unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__, substream->name, substream->stream,
+ cpu_dai->name, cpu_dai->id);
+
+ if (index < PRIM_MI2S || index > QUAT_MI2S) {
+ ret = -EINVAL;
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, cpu_dai->id);
+ goto done;
+ }
+ /*
+ * Muxtex protection in case the same MI2S
+ * interface using for both TX and RX so
+ * that the same clock won't be enable twice.
+ */
+ mutex_lock(&mi2s_intf_conf[index].lock);
+ if (++mi2s_intf_conf[index].ref_cnt == 1) {
+ ret = msm_mi2s_set_sclk(substream, true);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed to enable MI2S clock, err:%d\n",
+ __func__, ret);
+ goto clean_up;
+ }
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(0,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_muxsel_virt_addr is NULL for dai %d\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto clk_off;
+ }
+ /* Check if msm needs to provide the clock to the interface */
+ if (!mi2s_intf_conf[index].msm_is_mi2s_master)
+ fmt = SND_SOC_DAIFMT_CBM_CFM;
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(rtd->card->dev,
+ "%s: set fmt cpu dai failed for MI2S (%d), err:%d\n",
+ __func__, index, ret);
+ goto clk_off;
+ }
+ }
+clk_off:
+ if (IS_ERR_VALUE(ret))
+ msm_mi2s_set_sclk(substream, false);
+clean_up:
+ if (IS_ERR_VALUE(ret))
+ mi2s_intf_conf[index].ref_cnt--;
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+done:
+ return ret;
+}
+EXPORT_SYMBOL(msm_mi2s_snd_startup);
+
+/**
+ * msm_mi2s_snd_shutdown - shutdown ops of mi2s.
+ *
+ * @substream: PCM stream pointer of associated backend dailink
+ */
+void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int index = rtd->cpu_dai->id;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ if (index < PRIM_MI2S || index > QUAT_MI2S) {
+ pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index);
+ return;
+ }
+
+ mutex_lock(&mi2s_intf_conf[index].lock);
+ if (--mi2s_intf_conf[index].ref_cnt == 0) {
+ ret = msm_mi2s_set_sclk(substream, false);
+ if (ret < 0) {
+ pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
+ __func__, index, ret);
+ mi2s_intf_conf[index].ref_cnt++;
+ }
+ }
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+}
+EXPORT_SYMBOL(msm_mi2s_snd_shutdown);
+
+/* Validate whether US EU switch is present or not */
+static int msm_prepare_us_euro(struct snd_soc_card *card)
+{
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int ret = 0;
+
+ if (pdata->us_euro_gpio >= 0) {
+ dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__,
+ pdata->us_euro_gpio);
+ ret = gpio_request(pdata->us_euro_gpio, "TASHA_CODEC_US_EURO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request codec US/EURO gpio %d error %d\n",
+ __func__, pdata->us_euro_gpio, ret);
+ }
+ }
+
+ return ret;
+}
+
+static bool msm_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int value = 0;
+
+ if (pdata->us_euro_gpio_p) {
+ value = msm_cdc_pinctrl_get_state(pdata->us_euro_gpio_p);
+ if (value)
+ msm_cdc_pinctrl_select_sleep_state(
+ pdata->us_euro_gpio_p);
+ else
+ msm_cdc_pinctrl_select_active_state(
+ pdata->us_euro_gpio_p);
+ } else if (pdata->us_euro_gpio >= 0) {
+ value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+ gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+ }
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ return true;
+}
+
+static int msm_populate_dai_link_component_of_node(
+ struct snd_soc_card *card)
+{
+ int i, index, ret = 0;
+ struct device *cdev = card->dev;
+ struct snd_soc_dai_link *dai_link = card->dai_link;
+ struct device_node *phandle;
+
+ if (!cdev) {
+ pr_err("%s: Sound card device memory NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < card->num_links; i++) {
+ if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
+ continue;
+
+ /* populate platform_of_node for snd card dai links */
+ if (dai_link[i].platform_name &&
+ !dai_link[i].platform_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-platform-names",
+ dai_link[i].platform_name);
+ if (index < 0) {
+ pr_err("%s: No match found for platform name: %s\n",
+ __func__, dai_link[i].platform_name);
+ ret = index;
+ goto cpu_dai;
+ }
+ phandle = of_parse_phandle(cdev->of_node,
+ "asoc-platform",
+ index);
+ if (!phandle) {
+ pr_err("%s: retrieving phandle for platform %s, index %d failed\n",
+ __func__, dai_link[i].platform_name,
+ index);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].platform_of_node = phandle;
+ dai_link[i].platform_name = NULL;
+ }
+cpu_dai:
+ /* populate cpu_of_node for snd card dai links */
+ if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-cpu-names",
+ dai_link[i].cpu_dai_name);
+ if (index < 0)
+ goto codec_dai;
+ phandle = of_parse_phandle(cdev->of_node, "asoc-cpu",
+ index);
+ if (!phandle) {
+ pr_err("%s: retrieving phandle for cpu dai %s failed\n",
+ __func__, dai_link[i].cpu_dai_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].cpu_of_node = phandle;
+ dai_link[i].cpu_dai_name = NULL;
+ }
+codec_dai:
+ /* populate codec_of_node for snd card dai links */
+ if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-codec-names",
+ dai_link[i].codec_name);
+ if (index < 0)
+ continue;
+ phandle = of_parse_phandle(cdev->of_node, "asoc-codec",
+ index);
+ if (!phandle) {
+ pr_err("%s: retrieving phandle for codec dai %s failed\n",
+ __func__, dai_link[i].codec_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].codec_of_node = phandle;
+ dai_link[i].codec_name = NULL;
+ }
+ }
+err:
+ return ret;
+}
+
+static int msm_wsa881x_init(struct snd_soc_component *component)
+{
+ u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106};
+ u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107};
+ unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
+ unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+ struct msm_asoc_mach_data *pdata;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+
+ if (!codec) {
+ pr_err("%s codec is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!strcmp(component->name_prefix, "SpkrLeft")) {
+ dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n",
+ __func__, codec->component.name);
+ wsa881x_set_channel_map(codec, &spkleft_ports[0],
+ WSA881X_MAX_SWR_PORTS, &ch_mask[0],
+ &ch_rate[0]);
+ if (dapm->component) {
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
+ }
+ } else if (!strcmp(component->name_prefix, "SpkrRight")) {
+ dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n",
+ __func__, codec->component.name);
+ wsa881x_set_channel_map(codec, &spkright_ports[0],
+ WSA881X_MAX_SWR_PORTS, &ch_mask[0],
+ &ch_rate[0]);
+ if (dapm->component) {
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
+ }
+ } else {
+ dev_err(codec->dev, "%s: wrong codec name %s\n", __func__,
+ codec->component.name);
+ return -EINVAL;
+ }
+
+
+ pdata = snd_soc_card_get_drvdata(component->card);
+ if (pdata && pdata->codec_root)
+ wsa881x_codec_info_create_codec_entry(pdata->codec_root,
+ codec);
+ return 0;
+}
+
+
+static int msm_init_wsa_dev(struct platform_device *pdev,
+ struct snd_soc_card *card)
+{
+ struct device_node *wsa_of_node;
+ u32 wsa_max_devs;
+ u32 wsa_dev_cnt;
+ char *dev_name_str = NULL;
+ struct msm_wsa881x_dev_info *wsa881x_dev_info;
+ const char *wsa_auxdev_name_prefix[1];
+ int found = 0;
+ int i;
+ int ret;
+
+ /* Get maximum WSA device count for this platform */
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,wsa-max-devs", &wsa_max_devs);
+ if (ret) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa-max-devs property missing in DT %s, ret = %d\n",
+ __func__, pdev->dev.of_node->full_name, ret);
+ goto err_dt;
+ }
+ if (wsa_max_devs == 0) {
+ dev_warn(&pdev->dev,
+ "%s: Max WSA devices is 0 for this target?\n",
+ __func__);
+ goto err_dt;
+ }
+
+ /* Get count of WSA device phandles for this platform */
+ wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
+ "qcom,wsa-devs", NULL);
+ if (wsa_dev_cnt == -ENOENT) {
+ dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
+ __func__);
+ goto err_dt;
+ } else if (wsa_dev_cnt <= 0) {
+ dev_err(&pdev->dev,
+ "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
+ __func__, wsa_dev_cnt);
+ ret = -EINVAL;
+ goto err_dt;
+ }
+
+ /*
+ * Expect total phandles count to be NOT less than maximum possible
+ * WSA count. However, if it is less, then assign same value to
+ * max count as well.
+ */
+ if (wsa_dev_cnt < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
+ __func__, wsa_max_devs, wsa_dev_cnt);
+ wsa_max_devs = wsa_dev_cnt;
+ }
+
+ /* Make sure prefix string passed for each WSA device */
+ ret = of_property_count_strings(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix");
+ if (ret != wsa_dev_cnt) {
+ dev_err(&pdev->dev,
+ "%s: expecting %d wsa prefix. Defined only %d in DT\n",
+ __func__, wsa_dev_cnt, ret);
+ ret = -EINVAL;
+ goto err_dt;
+ }
+
+ /*
+ * Alloc mem to store phandle and index info of WSA device, if already
+ * registered with ALSA core
+ */
+ wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
+ sizeof(struct msm_wsa881x_dev_info),
+ GFP_KERNEL);
+ if (!wsa881x_dev_info) {
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ /*
+ * search and check whether all WSA devices are already
+ * registered with ALSA core or not. If found a node, store
+ * the node and the index in a local array of struct for later
+ * use.
+ */
+ for (i = 0; i < wsa_dev_cnt; i++) {
+ wsa_of_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,wsa-devs", i);
+ if (unlikely(!wsa_of_node)) {
+ /* we should not be here */
+ dev_err(&pdev->dev,
+ "%s: wsa dev node is not present\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_dev_node;
+ }
+ if (soc_find_component(wsa_of_node, NULL)) {
+ /* WSA device registered with ALSA core */
+ wsa881x_dev_info[found].of_node = wsa_of_node;
+ wsa881x_dev_info[found].index = i;
+ found++;
+ if (found == wsa_max_devs)
+ break;
+ }
+ }
+
+ if (found < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: failed to find %d components. Found only %d\n",
+ __func__, wsa_max_devs, found);
+ return -EPROBE_DEFER;
+ }
+ dev_info(&pdev->dev,
+ "%s: found %d wsa881x devices registered with ALSA core\n",
+ __func__, found);
+
+ card->num_aux_devs = wsa_max_devs;
+ card->num_configs = wsa_max_devs;
+
+ /* Alloc array of AUX devs struct */
+ msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_aux_dev),
+ GFP_KERNEL);
+ if (!msm_aux_dev) {
+ ret = -ENOMEM;
+ goto err_auxdev_mem;
+ }
+
+ /* Alloc array of codec conf struct */
+ msm_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_codec_conf),
+ GFP_KERNEL);
+ if (!msm_codec_conf) {
+ ret = -ENOMEM;
+ goto err_codec_conf;
+ }
+
+ for (i = 0; i < card->num_aux_devs; i++) {
+ dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
+ GFP_KERNEL);
+ if (!dev_name_str) {
+ ret = -ENOMEM;
+ goto err_dev_str;
+ }
+
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix",
+ wsa881x_dev_info[i].index,
+ wsa_auxdev_name_prefix);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: failed to read wsa aux dev prefix, ret = %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto err_dt_prop;
+ }
+
+ snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
+ msm_aux_dev[i].name = dev_name_str;
+ msm_aux_dev[i].codec_name = NULL;
+ msm_aux_dev[i].codec_of_node =
+ wsa881x_dev_info[i].of_node;
+ msm_aux_dev[i].init = msm_wsa881x_init;
+ msm_codec_conf[i].dev_name = NULL;
+ msm_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0];
+ msm_codec_conf[i].of_node = wsa881x_dev_info[i].of_node;
+ }
+ card->codec_conf = msm_codec_conf;
+ card->aux_dev = msm_aux_dev;
+
+ return 0;
+
+err_dt_prop:
+ devm_kfree(&pdev->dev, dev_name_str);
+err_dev_str:
+ devm_kfree(&pdev->dev, msm_codec_conf);
+err_codec_conf:
+ devm_kfree(&pdev->dev, msm_aux_dev);
+err_auxdev_mem:
+err_dev_node:
+ devm_kfree(&pdev->dev, wsa881x_dev_info);
+err_mem:
+err_dt:
+ return ret;
+}
+
+static void msm_free_auxdev_mem(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ int i;
+
+ if (card->num_aux_devs > 0) {
+ for (i = 0; i < card->num_aux_devs; i++) {
+ kfree(msm_aux_dev[i].codec_name);
+ kfree(msm_codec_conf[i].dev_name);
+ kfree(msm_codec_conf[i].name_prefix);
+ }
+ }
+}
+
+static void i2s_auxpcm_init(struct platform_device *pdev)
+{
+ struct resource *muxsel;
+ int count;
+ u32 mi2s_master_slave[MI2S_MAX];
+ int ret;
+ char *str[PCM_I2S_SEL_MAX] = {
+ "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel"
+ };
+
+ for (count = 0; count < MI2S_MAX; count++) {
+ mutex_init(&mi2s_intf_conf[count].lock);
+ mi2s_intf_conf[count].ref_cnt = 0;
+ }
+
+ for (count = 0; count < AUX_PCM_MAX; count++) {
+ mutex_init(&auxpcm_intf_conf[count].lock);
+ auxpcm_intf_conf[count].ref_cnt = 0;
+ }
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++) {
+ mutex_init(&mi2s_auxpcm_conf[count].lock);
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr = NULL;
+ }
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++) {
+ muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ str[count]);
+ if (muxsel) {
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr
+ = ioremap(muxsel->start, resource_size(muxsel));
+ }
+ }
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-mi2s-master",
+ mi2s_master_slave, MI2S_MAX);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n",
+ __func__);
+ } else {
+ for (count = 0; count < MI2S_MAX; count++) {
+ mi2s_intf_conf[count].msm_is_mi2s_master =
+ mi2s_master_slave[count];
+ }
+ }
+}
+
+static void i2s_auxpcm_deinit(void)
+{
+ int count;
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++)
+ if (mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr !=
+ NULL)
+ iounmap(
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr);
+}
+
+static const struct of_device_id msmfalcon_asoc_machine_of_match[] = {
+ { .compatible = "qcom,msmfalcon-asoc-snd",
+ .data = "internal_codec"},
+ { .compatible = "qcom,msmfalcon-asoc-snd-tasha",
+ .data = "tasha_codec"},
+ { .compatible = "qcom,msmfalcon-asoc-snd-tavil",
+ .data = "tavil_codec"},
+ {},
+};
+
+static int msm_asoc_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
+ const char *mclk = "qcom,msm-mclk-freq";
+ int ret = -EINVAL, id;
+ const struct of_device_id *match;
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_asoc_mach_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ match = of_match_node(msmfalcon_asoc_machine_of_match,
+ pdev->dev.of_node);
+ if (!match)
+ goto err;
+
+ ret = of_property_read_u32(pdev->dev.of_node, mclk, &id);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: missing %s in dt node\n", __func__, mclk);
+ id = DEFAULT_MCLK_RATE;
+ }
+ pdata->mclk_freq = id;
+
+ if (!strcmp(match->data, "tasha_codec") ||
+ !strcmp(match->data, "tavil_codec")) {
+ if (!strcmp(match->data, "tasha_codec"))
+ pdata->snd_card_val = EXT_SND_CARD_TASHA;
+ else
+ pdata->snd_card_val = EXT_SND_CARD_TAVIL;
+ ret = msm_ext_cdc_init(pdev, pdata, &card, &mbhc_cfg);
+ if (ret)
+ goto err;
+ } else if (!strcmp(match->data, "internal_codec")) {
+ pdata->snd_card_val = INT_SND_CARD;
+ ret = msm_int_cdc_init(pdev, pdata, &card, &mbhc_cfg);
+ if (ret)
+ goto err;
+ } else {
+ dev_err(&pdev->dev,
+ "%s: Not a matching DT sound node\n", __func__);
+ goto err;
+ }
+ if (!card)
+ goto err;
+
+ if (pdata->snd_card_val == INT_SND_CARD) {
+ /*reading the gpio configurations from dtsi file*/
+ ret = msm_gpioset_initialize(CLIENT_WCD, &pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "%s: error reading dtsi files%d\n",
+ __func__, ret);
+ goto err;
+ }
+ }
+
+ /*
+ * Parse US-Euro gpio info from DT. Report no error if us-euro
+ * entry is not found in DT file as some targets do not support
+ * US-Euro detection
+ */
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (!gpio_is_valid(pdata->us_euro_gpio))
+ pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (!gpio_is_valid(pdata->us_euro_gpio) && (!pdata->us_euro_gpio_p)) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,us-euro-gpios", pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected",
+ "qcom,us-euro-gpios");
+ mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic;
+ }
+
+ ret = msm_prepare_us_euro(card);
+ if (ret)
+ dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
+ ret);
+
+ i2s_auxpcm_init(pdev);
+
+ ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
+ if (ret)
+ goto err;
+
+ ret = msm_populate_dai_link_component_of_node(card);
+ if (ret) {
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ ret = msm_init_wsa_dev(pdev, card);
+ if (ret)
+ goto err;
+
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err;
+ }
+ if (pdata->snd_card_val != INT_SND_CARD)
+ msm_ext_register_audio_notifier();
+ return 0;
+err:
+ if (pdata->us_euro_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ pdata->us_euro_gpio = 0;
+ }
+ if (pdata->hph_en1_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free hph_en1_gpio %d\n",
+ __func__, pdata->hph_en1_gpio);
+ gpio_free(pdata->hph_en1_gpio);
+ pdata->hph_en1_gpio = 0;
+ }
+ if (pdata->hph_en0_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free hph_en0_gpio %d\n",
+ __func__, pdata->hph_en0_gpio);
+ gpio_free(pdata->hph_en0_gpio);
+ pdata->hph_en0_gpio = 0;
+ }
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+
+static int msm_asoc_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ if (pdata->snd_card_val == INT_SND_CARD)
+ mutex_destroy(&pdata->cdc_int_mclk0_mutex);
+ msm_free_auxdev_mem(pdev);
+
+ gpio_free(pdata->us_euro_gpio);
+ gpio_free(pdata->hph_en1_gpio);
+ gpio_free(pdata->hph_en0_gpio);
+ i2s_auxpcm_deinit();
+ snd_soc_unregister_card(card);
+ return 0;
+}
+
+static struct platform_driver msmfalcon_asoc_machine_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = msmfalcon_asoc_machine_of_match,
+ },
+ .probe = msm_asoc_machine_probe,
+ .remove = msm_asoc_machine_remove,
+};
+module_platform_driver(msmfalcon_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, msmfalcon_asoc_machine_of_match);
diff --git a/sound/soc/msm/msmfalcon-common.h b/sound/soc/msm/msmfalcon-common.h
new file mode 100644
index 0000000..5f6b859
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-common.h
@@ -0,0 +1,103 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_COMMON
+#define __MSM_COMMON
+
+#include <sound/soc.h>
+#include <sound/q6afe-v2.h>
+#include "../codecs/wcd-mbhc-v2.h"
+
+#define SAMPLING_RATE_8KHZ 8000
+#define SAMPLING_RATE_11P025KHZ 11025
+#define SAMPLING_RATE_16KHZ 16000
+#define SAMPLING_RATE_22P05KHZ 22050
+#define SAMPLING_RATE_32KHZ 32000
+#define SAMPLING_RATE_44P1KHZ 44100
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_88P2KHZ 88200
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_176P4KHZ 176400
+#define SAMPLING_RATE_192KHZ 192000
+#define SAMPLING_RATE_352P8KHZ 352800
+#define SAMPLING_RATE_384KHZ 384000
+
+#define TDM_CHANNEL_MAX 8
+#define TDM_SLOT_OFFSET_MAX 8
+
+enum {
+ TDM_0 = 0,
+ TDM_1,
+ TDM_2,
+ TDM_3,
+ TDM_4,
+ TDM_5,
+ TDM_6,
+ TDM_7,
+ TDM_PORT_MAX,
+};
+
+enum {
+ TDM_PRI = 0,
+ TDM_SEC,
+ TDM_TERT,
+ TDM_QUAT,
+ TDM_INTERFACE_MAX,
+};
+
+struct tdm_port {
+ u32 mode;
+ u32 channel;
+};
+
+extern const struct snd_kcontrol_new msm_common_snd_controls[];
+struct msmfalcon_codec {
+ void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
+ enum afe_config_type config_type);
+};
+
+enum {
+ INT_SND_CARD,
+ EXT_SND_CARD_TASHA,
+ EXT_SND_CARD_TAVIL,
+};
+
+struct msm_asoc_mach_data {
+ int us_euro_gpio; /* used by gpio driver API */
+ int hph_en1_gpio;
+ int hph_en0_gpio;
+ struct device_node *us_euro_gpio_p; /* used by pinctrl API */
+ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
+ struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
+ struct snd_soc_codec *codec;
+ struct msmfalcon_codec msmfalcon_codec_fn;
+ struct snd_info_entry *codec_root;
+ int spk_ext_pa_gpio;
+ int mclk_freq;
+ int lb_mode;
+ int snd_card_val;
+ u8 micbias1_cap_mode;
+ u8 micbias2_cap_mode;
+ atomic_t int_mclk0_rsc_ref;
+ atomic_t int_mclk0_enabled;
+ struct mutex cdc_int_mclk0_mutex;
+ struct delayed_work disable_int_mclk0_work;
+ struct afe_clk_set digital_cdc_core_clk;
+};
+
+int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+int msm_aux_pcm_snd_startup(struct snd_pcm_substream *substream);
+void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream);
+int msm_mi2s_snd_startup(struct snd_pcm_substream *substream);
+void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
+#endif
diff --git a/sound/soc/msm/msmfalcon-ext-dai-links.c b/sound/soc/msm/msmfalcon-ext-dai-links.c
new file mode 100644
index 0000000..6f066c5
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-ext-dai-links.c
@@ -0,0 +1,1967 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "../codecs/wcd9335.h"
+#include "msmfalcon-common.h"
+#include "msmfalcon-external.h"
+
+#define DEV_NAME_STR_LEN 32
+#define __CHIPSET__ "MSMFALCON "
+#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
+
+#define WCN_CDC_SLIM_RX_CH_MAX 2
+#define WCN_CDC_SLIM_TX_CH_MAX 3
+
+static struct snd_soc_card snd_soc_card_msm_card_tavil;
+static struct snd_soc_card snd_soc_card_msm_card_tasha;
+
+static struct snd_soc_ops msm_ext_slimbus_be_ops = {
+ .hw_params = msm_snd_hw_params,
+};
+
+static struct snd_soc_ops msm_ext_cpe_ops = {
+ .hw_params = msm_snd_cpe_hw_params,
+};
+
+static struct snd_soc_ops msm_ext_slimbus_2_be_ops = {
+ .hw_params = msm_ext_slimbus_2_hw_params,
+};
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .shutdown = msm_mi2s_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_aux_pcm_be_ops = {
+ .startup = msm_aux_pcm_snd_startup,
+ .shutdown = msm_aux_pcm_snd_shutdown,
+};
+
+static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd)
+{
+ unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158};
+ unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+}
+
+static int msm_wcn_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret;
+
+ dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret) {
+ dev_err(rtd->dev,
+ "%s: failed to get BTFM codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch);
+ if (ret)
+ dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+
+exit:
+ return ret;
+}
+
+static struct snd_soc_ops msm_wcn_ops = {
+ .hw_params = msm_wcn_hw_params,
+};
+
+/*TDM default offset currently only supporting TDM_RX_0 and TDM_TX_0 */
+static unsigned int tdm_slot_offset[TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
+ {0, 4, 8, 12, 16, 20, 24, 28},/* TX_0 | RX_0 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_1 | RX_1 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_2 | RX_2 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_3 | RX_3 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_4 | RX_4 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_5 | RX_5 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_6 | RX_6 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_7 | RX_7 */
+};
+
+static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width,
+ int slots)
+{
+ unsigned int slot_mask = 0;
+ int i, j;
+ unsigned int *slot_offset;
+
+ for (i = TDM_0; i < TDM_PORT_MAX; i++) {
+ slot_offset = tdm_slot_offset[i];
+
+ for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) {
+ if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ slot_mask |=
+ (1 << ((slot_offset[j] * 8) / slot_width));
+ else
+ break;
+ }
+ }
+
+ return slot_mask;
+}
+
+static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int channels, slot_width, slots;
+ unsigned int slot_mask;
+ unsigned int *slot_offset;
+ int offset_channels = 0;
+ int i;
+
+ pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+ channels = params_channels(params);
+ switch (channels) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /*
+ * up to 8 channels HW config should
+ * use 32 bit slot width for max support of
+ * stream bit width. (slot_width > bit_width)
+ */
+ slot_width = 32;
+ break;
+ default:
+ pr_err("%s: invalid param format 0x%x\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+ slots = 8;
+ slot_mask = tdm_param_set_slot_mask(cpu_dai->id,
+ slot_width,
+ slots);
+ if (!slot_mask) {
+ pr_err("%s: invalid slot_mask 0x%x\n",
+ __func__, slot_mask);
+ return -EINVAL;
+ }
+ break;
+ default:
+ pr_err("%s: invalid param channels %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ /* currently only supporting TDM_RX_0 and TDM_TX_0 */
+ switch (cpu_dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ slot_offset = tdm_slot_offset[TDM_0];
+ break;
+ default:
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ offset_channels++;
+ else
+ break;
+ }
+
+ if (offset_channels == 0) {
+ pr_err("%s: slot offset not supported, offset_channels %d\n",
+ __func__, offset_channels);
+ return -EINVAL;
+ }
+
+ if (channels > offset_channels) {
+ pr_err("%s: channels %d exceed offset_channels %d\n",
+ __func__, channels, offset_channels);
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ channels, slot_offset);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
+ slot_offset, 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static struct snd_soc_ops msm_tdm_be_ops = {
+ .hw_params = msm_tdm_snd_hw_params
+};
+
+static struct snd_soc_dai_link msm_ext_tasha_fe_dai[] = {
+ /* tasha_vifeedback for speaker protection */
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx2",
+ .ignore_suspend = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_ext_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx2",
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_ext_slimbus_2_be_ops,
+ },
+ /* CPE LSM direct dai-link */
+ {
+ .name = "CPE Listen service",
+ .stream_name = "CPE Listen Audio Service",
+ .cpu_dai_name = "msm-dai-slim",
+ .platform_name = "msm-cpe-lsm",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "tasha_mad1",
+ .codec_name = "tasha_codec",
+ .ops = &msm_ext_cpe_ops,
+ },
+ {
+ .name = "SLIMBUS_6 Hostless Playback",
+ .stream_name = "SLIMBUS_6 Hostless",
+ .cpu_dai_name = "SLIMBUS6_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* CPE LSM EC PP direct dai-link */
+ {
+ .name = "CPE Listen service ECPP",
+ .stream_name = "CPE Listen Audio Service ECPP",
+ .cpu_dai_name = "CPE_LSM_NOHOST",
+ .platform_name = "msm-cpe-lsm.3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "tasha_cpe",
+ .codec_name = "tasha_codec",
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_tavil_fe_dai[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_ext_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_ext_slimbus_2_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_tasha_be_dai[] = {
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_ext_slimbus_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_ext_slimbus_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx3",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_5_RX,
+ .stream_name = "Slimbus5 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16394",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mad1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_6_RX,
+ .stream_name = "Slimbus6 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16396",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx4",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_tavil_be_dai[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_ext_slimbus_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_ext_slimbus_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx3",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_2_RX,
+ .stream_name = "Slimbus2 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx2",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_5_RX,
+ .stream_name = "Slimbus5 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16394",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_mad1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_6_RX,
+ .stream_name = "Slimbus6 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16396",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx4",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_common_fe_dai[] = {
+ /* FrontEnd DAI Links */
+ {/* hw:x,0 */
+ .name = MSM_DAILINK_NAME(Media1),
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {/* hw:x,1 */
+ .name = MSM_DAILINK_NAME(Media2),
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {/* hw:x,2 */
+ .name = "VoiceMMode1",
+ .stream_name = "VoiceMMode1",
+ .cpu_dai_name = "VoiceMMode1",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE1,
+ },
+ {/* hw:x,3 */
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {/* hw:x,4 */
+ .name = MSM_DAILINK_NAME(ULL),
+ .stream_name = "ULL",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-dsp.2",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {/* hw:x,5 */
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* This dai link has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,6 */
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,7 */
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {/* hw:x,8 */
+ .name = MSM_DAILINK_NAME(Compress1),
+ .stream_name = "Compress1",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {/* hw:x,9*/
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,10 */
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,11 */
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,12 */
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,13 */
+ .name = MSM_DAILINK_NAME(LowLatency),
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
+ /* LSM FE */
+ {/* hw:x,14 */
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ {/* hw:x,15 */
+ .name = MSM_DAILINK_NAME(Compress2),
+ .stream_name = "Compress2",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {/* hw:x,16 */
+ .name = MSM_DAILINK_NAME(Compress3),
+ .stream_name = "Compress3",
+ .cpu_dai_name = "MultiMedia10",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+ },
+ {/* hw:x,17 */
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ),
+ .stream_name = "MM_NOIRQ",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-pcm-dsp-noirq",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
+ {/* hw:x,18 */
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,19 */
+ .name = "VoiceMMode2",
+ .stream_name = "VoiceMMode2",
+ .cpu_dai_name = "VoiceMMode2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE2,
+ },
+ {/* hw:x,20 */
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {/* hw:x,21 */
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {/* hw:x,22 */
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {/* hw:x,23 */
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {/* hw:x,24 */
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM6
+ },
+ {/* hw:x,25 */
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {/* hw:x,26 */
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {/* hw:x,27 */
+ .name = MSM_DAILINK_NAME(Media9),
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
+ {/* hw:x,28 */
+ .name = MSM_DAILINK_NAME(Compress4),
+ .stream_name = "Compress4",
+ .cpu_dai_name = "MultiMedia11",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA11,
+ },
+ {/* hw:x,29 */
+ .name = MSM_DAILINK_NAME(Compress5),
+ .stream_name = "Compress5",
+ .cpu_dai_name = "MultiMedia12",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA12,
+ },
+ {/* hw:x,30 */
+ .name = MSM_DAILINK_NAME(Compress6),
+ .stream_name = "Compress6",
+ .cpu_dai_name = "MultiMedia13",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA13,
+ },
+ {/* hw:x,31 */
+ .name = MSM_DAILINK_NAME(Compress7),
+ .stream_name = "Compress7",
+ .cpu_dai_name = "MultiMedia14",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+ },
+ {/* hw:x,32 */
+ .name = MSM_DAILINK_NAME(Compress8),
+ .stream_name = "Compress8",
+ .cpu_dai_name = "MultiMedia15",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15,
+ },
+ {/* hw:x,33 */
+ .name = MSM_DAILINK_NAME(Compress9),
+ .stream_name = "Compress9",
+ .cpu_dai_name = "MultiMedia16",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA16,
+ },
+ {/* hw:x,34 */
+ .name = "SLIMBUS_8 Hostless",
+ .stream_name = "SLIMBUS8_HOSTLESS Capture",
+ .cpu_dai_name = "SLIMBUS8_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_common_be_dai[] = {
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_RX,
+ .stream_name = "USB Audio Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.28672",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_USB_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_TX,
+ .stream_name = "USB Audio Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.28673",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_USB_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_RX_0,
+ .stream_name = "Primary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36864",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_TX_0,
+ .stream_name = "Primary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36865",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_RX_0,
+ .stream_name = "Secondary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36880",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_TX_0,
+ .stream_name = "Secondary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36881",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_RX_0,
+ .stream_name = "Tertiary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36896",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_TX_0,
+ .stream_name = "Tertiary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36897",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_RX_0,
+ .stream_name = "Quaternary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36912",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_TX_0,
+ .stream_name = "Quaternary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36913",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
+ {
+ .name = LPASS_BE_PRI_MI2S_RX,
+ .stream_name = "Primary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_MI2S_TX,
+ .stream_name = "Primary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_RX,
+ .stream_name = "Secondary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_TX,
+ .stream_name = "Secondary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_RX,
+ .stream_name = "Tertiary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_TX,
+ .stream_name = "Tertiary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_RX,
+ .stream_name = "Quaternary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_TX,
+ .stream_name = "Quaternary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
+ /* Primary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Secondary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_SEC_AUXPCM_RX,
+ .stream_name = "Sec AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SEC_AUXPCM_TX,
+ .stream_name = "Sec AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Tertiary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_TERT_AUXPCM_RX,
+ .stream_name = "Tert AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_TERT_AUXPCM_TX,
+ .stream_name = "Tert AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Quaternary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_RX,
+ .stream_name = "Quat AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_TX,
+ .stream_name = "Quat AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_7_RX,
+ .stream_name = "Slimbus7 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16398",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ /* BT codec driver determines capabilities based on
+ * dai name, bt codecdai name should always contains
+ * supported usecase information
+ */
+ .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_7_TX,
+ .stream_name = "Slimbus7 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16399",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_bt_sco_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_8_TX,
+ .stream_name = "Slimbus8 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16401",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_fm_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .init = &msm_wcn_init,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_tasha_dai_links[
+ARRAY_SIZE(msm_ext_common_fe_dai) +
+ARRAY_SIZE(msm_ext_tasha_fe_dai) +
+ARRAY_SIZE(msm_ext_common_be_dai) +
+ARRAY_SIZE(msm_ext_tasha_be_dai) +
+ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ARRAY_SIZE(msm_auxpcm_be_dai_links) +
+ARRAY_SIZE(msm_wcn_be_dai_links)];
+
+static struct snd_soc_dai_link msm_ext_tavil_dai_links[
+ARRAY_SIZE(msm_ext_common_fe_dai) +
+ARRAY_SIZE(msm_ext_tavil_fe_dai) +
+ARRAY_SIZE(msm_ext_common_be_dai) +
+ARRAY_SIZE(msm_ext_tavil_be_dai) +
+ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ARRAY_SIZE(msm_auxpcm_be_dai_links) +
+ARRAY_SIZE(msm_wcn_be_dai_links)];
+
+/**
+ * populate_snd_card_dailinks - prepares dailink array and initializes card.
+ *
+ * @dev: device handle
+ *
+ * Returns card on success or NULL on failure.
+ */
+struct snd_soc_card *populate_snd_card_dailinks(struct device *dev,
+ int snd_card_val)
+{
+ struct snd_soc_card *card;
+ struct snd_soc_dai_link *msm_ext_dai_links = NULL;
+ int ret, len1, len2, len3, len4;
+ enum codec_variant codec_ver = 0;
+
+ if (snd_card_val == EXT_SND_CARD_TASHA) {
+ card = &snd_soc_card_msm_card_tasha;
+ } else if (snd_card_val == EXT_SND_CARD_TAVIL) {
+ card = &snd_soc_card_msm_card_tavil;
+ } else {
+ dev_err(dev, "%s: failing as no matching card name\n",
+ __func__);
+ return NULL;
+ }
+
+ card->dev = dev;
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret) {
+ dev_err(dev, "%s: parse card name failed, err:%d\n",
+ __func__, ret);
+ return NULL;
+ }
+
+ if (strnstr(card->name, "tasha", strlen(card->name))) {
+ codec_ver = tasha_codec_ver();
+ if (codec_ver == WCD9326)
+ card->name = "msmfalcon-tashalite-snd-card";
+
+ len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
+ len2 = len1 + ARRAY_SIZE(msm_ext_tasha_fe_dai);
+ len3 = len2 + ARRAY_SIZE(msm_ext_common_be_dai);
+ memcpy(msm_ext_tasha_dai_links, msm_ext_common_fe_dai,
+ sizeof(msm_ext_common_fe_dai));
+ memcpy(msm_ext_tasha_dai_links + len1,
+ msm_ext_tasha_fe_dai, sizeof(msm_ext_tasha_fe_dai));
+ memcpy(msm_ext_tasha_dai_links + len2,
+ msm_ext_common_be_dai, sizeof(msm_ext_common_be_dai));
+ memcpy(msm_ext_tasha_dai_links + len3,
+ msm_ext_tasha_be_dai, sizeof(msm_ext_tasha_be_dai));
+ len4 = len3 + ARRAY_SIZE(msm_ext_tasha_be_dai);
+ if (of_property_read_bool(dev->of_node,
+ "qcom,mi2s-audio-intf")) {
+ memcpy(msm_ext_tasha_dai_links + len4,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ len4 += ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,auxpcm-audio-intf")) {
+ memcpy(msm_ext_tasha_dai_links + len4,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ len4 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(msm_ext_tasha_dai_links + len4,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
+ len4 += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
+ msm_ext_dai_links = msm_ext_tasha_dai_links;
+ } else if (strnstr(card->name, "tavil", strlen(card->name))) {
+ len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
+ len2 = len1 + ARRAY_SIZE(msm_ext_tavil_fe_dai);
+ len3 = len2 + ARRAY_SIZE(msm_ext_common_be_dai);
+ memcpy(msm_ext_tavil_dai_links, msm_ext_common_fe_dai,
+ sizeof(msm_ext_common_fe_dai));
+ memcpy(msm_ext_tavil_dai_links + len1,
+ msm_ext_tavil_fe_dai, sizeof(msm_ext_tavil_fe_dai));
+ memcpy(msm_ext_tavil_dai_links + len2,
+ msm_ext_common_be_dai, sizeof(msm_ext_common_be_dai));
+ memcpy(msm_ext_tavil_dai_links + len3,
+ msm_ext_tavil_be_dai, sizeof(msm_ext_tavil_be_dai));
+ len4 = len3 + ARRAY_SIZE(msm_ext_tavil_be_dai);
+ if (of_property_read_bool(dev->of_node,
+ "qcom,mi2s-audio-intf")) {
+ memcpy(msm_ext_tavil_dai_links + len4,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ len4 += ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,auxpcm-audio-intf")) {
+ memcpy(msm_ext_tavil_dai_links + len4,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ len4 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(msm_ext_tavil_dai_links + len4,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
+ len4 += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
+ msm_ext_dai_links = msm_ext_tavil_dai_links;
+ } else {
+ dev_err(dev, "%s: failing as no matching card name\n",
+ __func__);
+ return NULL;
+ }
+ card->dai_link = msm_ext_dai_links;
+ card->num_links = len4;
+
+ return card;
+}
+EXPORT_SYMBOL(populate_snd_card_dailinks);
diff --git a/sound/soc/msm/msmfalcon-external.c b/sound/soc/msm/msmfalcon-external.c
new file mode 100644
index 0000000..d7b002e
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-external.c
@@ -0,0 +1,1765 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/q6core.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "msm-audio-pinctrl.h"
+#include "msmfalcon-common.h"
+#include "msmfalcon-external.h"
+#include "../codecs/wcd9335.h"
+#include "../codecs/wcd934x/wcd934x.h"
+#include "../codecs/wcd934x/wcd934x-mbhc.h"
+
+#define MSMFALCON_SPK_ON 1
+#define MSMFALCON_SPK_OFF 0
+
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define CODEC_EXT_CLK_RATE 9600000
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
+#define WSA8810_NAME_1 "wsa881x.20170211"
+#define WSA8810_NAME_2 "wsa881x.20170212"
+
+static int msm_ext_spk_control = 1;
+static struct wcd_mbhc_config *wcd_mbhc_cfg_ptr;
+
+struct msm_asoc_wcd93xx_codec {
+ void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
+ enum afe_config_type config_type);
+ void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
+};
+
+static struct msm_asoc_wcd93xx_codec msm_codec_fn;
+static struct platform_device *spdev;
+
+static bool is_initial_boot;
+
+static void *def_ext_mbhc_cal(void);
+
+enum {
+ SLIM_RX_0 = 0,
+ SLIM_RX_1,
+ SLIM_RX_2,
+ SLIM_RX_3,
+ SLIM_RX_4,
+ SLIM_RX_5,
+ SLIM_RX_6,
+ SLIM_RX_7,
+ SLIM_RX_MAX,
+};
+
+enum {
+ SLIM_TX_0 = 0,
+ SLIM_TX_1,
+ SLIM_TX_2,
+ SLIM_TX_3,
+ SLIM_TX_4,
+ SLIM_TX_5,
+ SLIM_TX_6,
+ SLIM_TX_7,
+ SLIM_TX_8,
+ SLIM_TX_MAX,
+};
+
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+/* Default configuration of slimbus channels */
+static struct dev_config slim_rx_cfg[] = {
+ [SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config slim_tx_cfg[] = {
+ [SLIM_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static int msm_vi_feed_tx_ch = 2;
+static const char *const slim_rx_ch_text[] = {"One", "Two"};
+static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static const char *const vi_feed_ch_text[] = {"One", "Two"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+ "S32_LE"};
+static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96", "KHZ_176P4",
+ "KHZ_192", "KHZ_352P8", "KHZ_384"};
+static const char *const spk_function_text[] = {"Off", "On"};
+static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_48"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(spk_func_en, spk_function_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_1_tx_chs, slim_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
+
+static int slim_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 10;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int slim_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 7:
+ sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 8:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 9:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 10:
+ sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int slim_get_bit_format_val(int bit_format)
+{
+ int val = 0;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ val = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ val = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static int slim_get_bit_format(int val)
+{
+ int bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+
+ switch (val) {
+ case 0:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 3:
+ bit_fmt = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return bit_fmt;
+}
+
+static int slim_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int port_id = 0;
+
+ if (strnstr(kcontrol->id.name, "SLIM_0_RX", sizeof("SLIM_0_RX")))
+ port_id = SLIM_RX_0;
+ else if (strnstr(kcontrol->id.name, "SLIM_2_RX", sizeof("SLIM_2_RX")))
+ port_id = SLIM_RX_2;
+ else if (strnstr(kcontrol->id.name, "SLIM_5_RX", sizeof("SLIM_5_RX")))
+ port_id = SLIM_RX_5;
+ else if (strnstr(kcontrol->id.name, "SLIM_6_RX", sizeof("SLIM_6_RX")))
+ port_id = SLIM_RX_6;
+ else if (strnstr(kcontrol->id.name, "SLIM_0_TX", sizeof("SLIM_0_TX")))
+ port_id = SLIM_TX_0;
+ else if (strnstr(kcontrol->id.name, "SLIM_1_TX", sizeof("SLIM_1_TX")))
+ port_id = SLIM_TX_1;
+ else {
+ pr_err("%s: unsupported channel: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return port_id;
+}
+
+static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * Slimbus_7_Rx/Tx sample rate values should always be in sync (same)
+ * when used for BT_SCO use case. Return either Rx or Tx sample rate
+ * value.
+ */
+ switch (slim_rx_cfg[SLIM_RX_7].sample_rate) {
+ case SAMPLING_RATE_48KHZ:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: sample rate = %d", __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 0:
+ default:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n",
+ __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate,
+ slim_tx_cfg[SLIM_TX_7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_sample_rate_val(slim_rx_cfg[ch_num].sample_rate);
+
+ pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].sample_rate =
+ slim_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_sample_rate_val(slim_tx_cfg[ch_num].sample_rate);
+
+ pr_debug("%s: slim[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate = 0;
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ sample_rate = slim_get_sample_rate(ucontrol->value.enumerated.item[0]);
+ if (sample_rate == SAMPLING_RATE_44P1KHZ) {
+ pr_err("%s: Unsupported sample rate %d: for Tx path\n",
+ __func__, sample_rate);
+ return -EINVAL;
+ }
+ slim_tx_cfg[ch_num].sample_rate = sample_rate;
+
+ pr_debug("%s: slim[%d]_tx_sample_rate = %d, value = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_bit_format_val(slim_rx_cfg[ch_num].bit_format);
+
+ pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_rx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].bit_format =
+ slim_get_bit_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_rx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_bit_format_val(slim_tx_cfg[ch_num].bit_format);
+
+ pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_tx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_tx_cfg[ch_num].bit_format =
+ slim_get_bit_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_tx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_slim_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].channels);
+ ucontrol->value.enumerated.item[0] = slim_rx_cfg[ch_num].channels - 1;
+
+ return 0;
+}
+
+static int msm_slim_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].channels);
+
+ return 1;
+}
+
+static int msm_slim_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].channels);
+ ucontrol->value.enumerated.item[0] = slim_tx_cfg[ch_num].channels - 1;
+
+ return 0;
+}
+
+static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_tx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].channels);
+
+ return 1;
+}
+
+static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
+ pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
+ return 1;
+}
+
+static void *def_ext_mbhc_cal(void)
+{
+ void *tavil_wcd_cal;
+ struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_high;
+
+ tavil_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
+ if (!tavil_wcd_cal)
+ return NULL;
+
+#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tavil_wcd_cal)->X) = (Y))
+ S(v_hs_max, 1600);
+#undef S
+#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal)->X) = (Y))
+ S(num_btn, WCD_MBHC_DEF_BUTTONS);
+#undef S
+
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal);
+ btn_high = ((void *)&btn_cfg->_v_btn_low) +
+ (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+ btn_high[0] = 75;
+ btn_high[1] = 150;
+ btn_high[2] = 237;
+ btn_high[3] = 500;
+ btn_high[4] = 500;
+ btn_high[5] = 500;
+ btn_high[6] = 500;
+ btn_high[7] = 500;
+
+ return tavil_wcd_cal;
+}
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+
+static void msm_ext_control(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+
+ pr_debug("%s: msm_ext_spk_control = %d", __func__, msm_ext_spk_control);
+ if (msm_ext_spk_control == MSMFALCON_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+ }
+ snd_soc_dapm_sync(dapm);
+}
+
+static int msm_ext_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_ext_spk_control = %d\n",
+ __func__, msm_ext_spk_control);
+ ucontrol->value.integer.value[0] = msm_ext_spk_control;
+ return 0;
+}
+
+static int msm_ext_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (msm_ext_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm_ext_spk_control = ucontrol->value.integer.value[0];
+ msm_ext_control(codec);
+ return 1;
+}
+
+
+int msm_ext_enable_codec_mclk(struct snd_soc_codec *codec, int enable,
+ bool dapm)
+{
+ int ret;
+
+ pr_debug("%s: enable = %d\n", __func__, enable);
+
+ if (!strcmp(dev_name(codec->dev), "tasha_codec"))
+ ret = tasha_cdc_mclk_enable(codec, enable, dapm);
+ else if (!strcmp(dev_name(codec->dev), "tavil_codec"))
+ ret = tavil_cdc_mclk_enable(codec, enable);
+ else {
+ dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", spk_func_en, msm_ext_get_spk,
+ msm_ext_set_spk),
+ SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_2_RX Channels", slim_2_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", slim_0_tx_chs,
+ msm_slim_tx_ch_get, msm_slim_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_1_TX Channels", slim_1_tx_chs,
+ msm_slim_tx_ch_get, msm_slim_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_5_RX Channels", slim_5_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_6_RX Channels", slim_6_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs,
+ msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_5_RX Format", slim_5_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_6_RX Format", slim_6_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format,
+ slim_tx_bit_format_get, slim_tx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_0_TX SampleRate", slim_0_tx_sample_rate,
+ slim_tx_sample_rate_get, slim_tx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_5_RX SampleRate", slim_5_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_6_RX SampleRate", slim_6_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("BT SampleRate", bt_sample_rate,
+ msm_bt_sample_rate_get,
+ msm_bt_sample_rate_put),
+};
+
+static int msm_slim_get_ch_from_beid(int32_t be_id)
+{
+ int ch_id = 0;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_SLIMBUS_0_RX:
+ ch_id = SLIM_RX_0;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_1_RX:
+ ch_id = SLIM_RX_1;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_2_RX:
+ ch_id = SLIM_RX_2;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_3_RX:
+ ch_id = SLIM_RX_3;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_4_RX:
+ ch_id = SLIM_RX_4;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_6_RX:
+ ch_id = SLIM_RX_6;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_0_TX:
+ ch_id = SLIM_TX_0;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_3_TX:
+ ch_id = SLIM_TX_3;
+ break;
+ default:
+ ch_id = SLIM_RX_0;
+ break;
+ }
+
+ return ch_id;
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+/**
+ * msm_ext_be_hw_params_fixup - updates settings of ALSA BE hw params.
+ *
+ * @rtd: runtime dailink instance
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0 on success or rc on failure.
+ */
+int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ int rc = 0;
+ int idx;
+ void *config = NULL;
+ struct snd_soc_codec *codec = rtd->codec;
+
+ pr_debug("%s: format = %d, rate = %d\n",
+ __func__, params_format(params), params_rate(params));
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_SLIMBUS_0_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_1_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_2_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_3_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_4_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_6_RX:
+ idx = msm_slim_get_ch_from_beid(dai_link->be_id);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[idx].bit_format);
+ rate->min = rate->max = slim_rx_cfg[idx].sample_rate;
+ channels->min = channels->max = slim_rx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_0_TX:
+ case MSM_BACKEND_DAI_SLIMBUS_3_TX:
+ idx = msm_slim_get_ch_from_beid(dai_link->be_id);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_tx_cfg[idx].bit_format);
+ rate->min = rate->max = slim_tx_cfg[idx].sample_rate;
+ channels->min = channels->max = slim_tx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_1_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_tx_cfg[1].bit_format);
+ rate->min = rate->max = slim_tx_cfg[1].sample_rate;
+ channels->min = channels->max = slim_tx_cfg[1].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_4_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FORMAT_S32_LE);
+ rate->min = rate->max = SAMPLING_RATE_8KHZ;
+ channels->min = channels->max = msm_vi_feed_tx_ch;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_5_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[5].bit_format);
+ rate->min = rate->max = slim_rx_cfg[5].sample_rate;
+ channels->min = channels->max = slim_rx_cfg[5].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_5_TX:
+ rate->min = rate->max = SAMPLING_RATE_16KHZ;
+ channels->min = channels->max = 1;
+
+ config = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ if (config) {
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG,
+ config, SLIMBUS_5_TX);
+ if (rc)
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ }
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[SLIM_RX_7].bit_format);
+ rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate;
+ channels->min = channels->max =
+ slim_rx_cfg[SLIM_RX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_8_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_8].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_8].channels;
+ break;
+
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return rc;
+}
+EXPORT_SYMBOL(msm_ext_be_hw_params_fixup);
+
+/**
+ * msm_snd_hw_params - hw params ops of backend dailink.
+ *
+ * @substream: PCM stream of associated backend dailink.
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ int ret = 0;
+ u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ u32 user_set_tx_ch = 0;
+ u32 rx_ch_count;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_5_RX) {
+ pr_debug("%s: rx_5_ch=%d\n", __func__,
+ slim_rx_cfg[5].channels);
+ rx_ch_count = slim_rx_cfg[5].channels;
+ } else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_2_RX) {
+ pr_debug("%s: rx_2_ch=%d\n", __func__,
+ slim_rx_cfg[2].channels);
+ rx_ch_count = slim_rx_cfg[2].channels;
+ } else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_6_RX) {
+ pr_debug("%s: rx_6_ch=%d\n", __func__,
+ slim_rx_cfg[6].channels);
+ rx_ch_count = slim_rx_cfg[6].channels;
+ } else {
+ pr_debug("%s: rx_0_ch=%d\n", __func__,
+ slim_rx_cfg[0].channels);
+ rx_ch_count = slim_rx_cfg[0].channels;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ rx_ch_count, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ } else {
+ pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+ codec_dai->name, codec_dai->id, user_set_tx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ /* For <codec>_tx1 case */
+ if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_0_TX)
+ user_set_tx_ch = slim_tx_cfg[0].channels;
+ /* For <codec>_tx3 case */
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_1_TX)
+ user_set_tx_ch = slim_tx_cfg[1].channels;
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_4_TX)
+ user_set_tx_ch = msm_vi_feed_tx_ch;
+ else
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), be_id (%d)\n",
+ __func__, slim_tx_cfg[0].channels, user_set_tx_ch,
+ tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0, 0);
+ if (ret < 0)
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ }
+
+err_ch_map:
+ return ret;
+}
+EXPORT_SYMBOL(msm_snd_hw_params);
+
+/**
+ * msm_ext_slimbus_2_hw_params - hw params ops of slimbus_2 BE.
+ *
+ * @substream: PCM stream of associated backend dailink.
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_ext_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ num_rx_ch = params_channels(params);
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ num_tx_ch = params_channels(params);
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+EXPORT_SYMBOL(msm_ext_slimbus_2_hw_params);
+
+/**
+ * msm_snd_cpe_hw_params - hw params ops of CPE backend.
+ *
+ * @substream: PCM stream of associated backend dailink.
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ int ret = 0;
+ u32 tx_ch[SLIM_MAX_TX_PORTS];
+ u32 tx_ch_cnt = 0;
+
+ if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("%s: Invalid stream type %d\n",
+ __func__, substream->stream);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pr_debug("%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, NULL, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ pr_debug("%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+end:
+ return ret;
+}
+EXPORT_SYMBOL(msm_snd_cpe_hw_params);
+
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+ int rc;
+ void *config_data;
+
+ pr_debug("%s: enter\n", __func__);
+
+ if (!msm_codec_fn.get_afe_config_fn) {
+ dev_err(codec->dev, "%s: codec get afe config not init'ed\n",
+ __func__);
+ return -EINVAL;
+ }
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTERS_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTER_PAGE_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
+ 0);
+ if (rc)
+ pr_err("%s: Failed to set cdc register page config\n",
+ __func__);
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_SLIMBUS_SLAVE_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave config %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_AANC_VERSION);
+ if (config_data) {
+ rc = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set AANC version %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ rc = afe_set_config(AFE_CLIP_BANK_SEL,
+ config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTER_PAGE_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
+ 0);
+ if (rc)
+ pr_err("%s: Failed to set cdc register page config\n",
+ __func__);
+ }
+
+ return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+ afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+ afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+}
+
+static int msm_adsp_power_up_config(struct snd_soc_codec *codec)
+{
+ int ret = 0;
+ unsigned long timeout;
+ int adsp_ready = 0;
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+ do {
+ if (q6core_is_adsp_ready()) {
+ pr_debug("%s: ADSP Audio is ready\n", __func__);
+ adsp_ready = 1;
+ break;
+ }
+ /*
+ * ADSP will be coming up after subsystem restart and
+ * it might not be fully up when the control reaches
+ * here. So, wait for 50msec before checking ADSP state
+ */
+ msleep(50);
+ } while (time_after(timeout, jiffies));
+
+ if (!adsp_ready) {
+ pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+ ret = -ETIMEDOUT;
+ goto err_fail;
+ }
+
+ ret = msm_afe_set_config(codec);
+ if (ret)
+ pr_err("%s: Failed to set AFE config. err %d\n",
+ __func__, ret);
+
+ return 0;
+
+err_fail:
+ return ret;
+}
+
+static int msmfalcon_notifier_service_cb(struct notifier_block *this,
+ unsigned long opcode, void *ptr)
+{
+ int ret;
+ struct snd_soc_card *card = NULL;
+ const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *codec;
+
+ pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
+
+ switch (opcode) {
+ case AUDIO_NOTIFIER_SERVICE_DOWN:
+ /*
+ * Use flag to ignore initial boot notifications
+ * On initial boot msm_adsp_power_up_config is
+ * called on init. There is no need to clear
+ * and set the config again on initial boot.
+ */
+ if (is_initial_boot)
+ break;
+ msm_afe_clear_config();
+ break;
+ case AUDIO_NOTIFIER_SERVICE_UP:
+ if (is_initial_boot) {
+ is_initial_boot = false;
+ break;
+ }
+ if (!spdev)
+ return -EINVAL;
+
+ card = platform_get_drvdata(spdev);
+ rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+ if (!rtd) {
+ dev_err(card->dev,
+ "%s: snd_soc_get_pcm_runtime for %s failed!\n",
+ __func__, be_dl_name);
+ ret = -EINVAL;
+ goto done;
+ }
+ codec = rtd->codec;
+
+ ret = msm_adsp_power_up_config(codec);
+ if (ret < 0) {
+ dev_err(card->dev,
+ "%s: msm_adsp_power_up_config failed ret = %d!\n",
+ __func__, ret);
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+done:
+ return NOTIFY_OK;
+}
+
+static struct notifier_block service_nb = {
+ .notifier_call = msmfalcon_notifier_service_cb,
+ .priority = -INT_MAX,
+};
+
+static int msm_config_hph_en0_gpio(struct snd_soc_codec *codec, bool high)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata;
+ int val;
+
+ if (!card)
+ return 0;
+
+ pdata = snd_soc_card_get_drvdata(card);
+ if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio))
+ return 0;
+
+ val = gpio_get_value_cansleep(pdata->hph_en0_gpio);
+ if ((!!val) == high)
+ return 0;
+
+ gpio_direction_output(pdata->hph_en0_gpio, (int)high);
+
+ return 1;
+}
+
+static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ if (!strcmp(dev_name(codec->dev), "tasha_codec"))
+ ret = tasha_cdc_mclk_tx_enable(codec, enable, dapm);
+ else {
+ dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int msm_ext_mclk_tx_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 0, true);
+ }
+ return 0;
+}
+
+static int msm_ext_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_ext_enable_codec_mclk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_ext_enable_codec_mclk(codec, 0, true);
+ }
+ return 0;
+}
+
+static int msm_ext_prepare_hifi(struct msm_asoc_mach_data *pdata)
+{
+ int ret = 0;
+
+ if (gpio_is_valid(pdata->hph_en1_gpio)) {
+ pr_debug("%s: hph_en1_gpio request %d\n", __func__,
+ pdata->hph_en1_gpio);
+ ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio");
+ if (ret) {
+ pr_err("%s: hph_en1_gpio request failed, ret:%d\n",
+ __func__, ret);
+ goto err;
+ }
+ }
+ if (gpio_is_valid(pdata->hph_en0_gpio)) {
+ pr_debug("%s: hph_en0_gpio request %d\n", __func__,
+ pdata->hph_en0_gpio);
+ ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio");
+ if (ret)
+ pr_err("%s: hph_en0_gpio request failed, ret:%d\n",
+ __func__, ret);
+ }
+
+err:
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY_S("MCLK", -1, SND_SOC_NOPM, 0, 0,
+ msm_ext_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("MCLK TX", -1, SND_SOC_NOPM, 0, 0,
+ msm_ext_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic7", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic8", NULL),
+
+ SND_SOC_DAPM_MIC("Digital Mic0", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
+ {"MIC BIAS1", NULL, "MCLK TX"},
+ {"MIC BIAS2", NULL, "MCLK TX"},
+ {"MIC BIAS3", NULL, "MCLK TX"},
+ {"MIC BIAS4", NULL, "MCLK TX"},
+};
+
+static struct snd_soc_dapm_route wcd_audio_paths[] = {
+ {"MIC BIAS1", NULL, "MCLK"},
+ {"MIC BIAS2", NULL, "MCLK"},
+ {"MIC BIAS3", NULL, "MCLK"},
+ {"MIC BIAS4", NULL, "MCLK"},
+};
+
+/**
+ * msm_audrx_init - Audio init function of sound card instantiate.
+ *
+ * @rtd: runtime dailink instance
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ void *config_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux;
+ struct snd_card *card;
+ struct snd_info_entry *entry;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(rtd->card);
+
+ /* Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+ pr_debug("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ rtd->pmdown_time = 0;
+
+ ret = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (ret < 0) {
+ pr_err("%s: add_codec_controls failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
+ ARRAY_SIZE(msm_dapm_widgets));
+
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec"))
+ snd_soc_dapm_add_routes(dapm, wcd_audio_paths_tasha,
+ ARRAY_SIZE(wcd_audio_paths_tasha));
+ else
+ snd_soc_dapm_add_routes(dapm, wcd_audio_paths,
+ ARRAY_SIZE(wcd_audio_paths));
+
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
+ snd_soc_dapm_ignore_suspend(dapm, "MADINPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Secondary Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_1 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_3 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_2 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_4 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic7");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic8");
+
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC6");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC0");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HEADPHONE");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
+ snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+
+ snd_soc_dapm_sync(dapm);
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+ if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+ msm_codec_fn.get_afe_config_fn = tavil_get_afe_config;
+ } else {
+ msm_codec_fn.get_afe_config_fn = tasha_get_afe_config;
+ msm_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit;
+ }
+
+ ret = msm_adsp_power_up_config(codec);
+ if (ret) {
+ pr_err("%s: Failed to set AFE config %d\n", __func__, ret);
+ goto err_afe_cfg;
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_AANC_VERSION);
+ if (config_data) {
+ ret = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ ret = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ ret = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+ }
+
+ /*
+ * Send speaker configuration only for WSA8810.
+ * Defalut configuration is for WSA8815.
+ */
+ if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+ if (rtd_aux && rtd_aux->component)
+ if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
+ !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
+ tavil_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+ tavil_set_spkr_gain_offset(rtd->codec,
+ RX_GAIN_OFFSET_M1P5_DB);
+ }
+ card = rtd->card->snd_card;
+ entry = snd_info_create_subdir(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ pdata->codec_root = NULL;
+ goto done;
+ }
+ pdata->codec_root = entry;
+ tavil_codec_info_create_codec_entry(pdata->codec_root, codec);
+ } else {
+ if (rtd_aux && rtd_aux->component)
+ if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
+ !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
+ tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+ tasha_set_spkr_gain_offset(rtd->codec,
+ RX_GAIN_OFFSET_M1P5_DB);
+ }
+ card = rtd->card->snd_card;
+ entry = snd_info_create_subdir(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ ret = 0;
+ goto err_snd_module;
+ }
+ pdata->codec_root = entry;
+ tasha_codec_info_create_codec_entry(pdata->codec_root, codec);
+ tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio, rtd->codec);
+ }
+
+ wcd_mbhc_cfg_ptr->calibration = def_ext_mbhc_cal();
+ if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+ if (wcd_mbhc_cfg_ptr->calibration) {
+ pdata->codec = codec;
+ ret = tavil_mbhc_hs_detect(codec, wcd_mbhc_cfg_ptr);
+ if (ret < 0)
+ pr_err("%s: Failed to intialise mbhc %d\n",
+ __func__, ret);
+ } else {
+ pr_err("%s: wcd_mbhc_cfg calibration is NULL\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_mbhc_cal;
+ }
+ } else {
+ if (wcd_mbhc_cfg_ptr->calibration) {
+ pdata->codec = codec;
+ ret = tasha_mbhc_hs_detect(codec, wcd_mbhc_cfg_ptr);
+ if (ret < 0)
+ pr_err("%s: Failed to intialise mbhc %d\n",
+ __func__, ret);
+ } else {
+ pr_err("%s: wcd_mbhc_cfg calibration is NULL\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_mbhc_cal;
+ }
+
+ }
+done:
+ return 0;
+
+err_snd_module:
+err_afe_cfg:
+err_mbhc_cal:
+ return ret;
+}
+EXPORT_SYMBOL(msm_audrx_init);
+
+/**
+ * msm_ext_register_audio_notifier - register SSR notifier.
+ */
+void msm_ext_register_audio_notifier(void)
+{
+ int ret;
+
+ ret = audio_notifier_register("msmfalcon", AUDIO_NOTIFIER_ADSP_DOMAIN,
+ &service_nb);
+ if (ret < 0)
+ pr_err("%s: Audio notifier register failed ret = %d\n",
+ __func__, ret);
+}
+EXPORT_SYMBOL(msm_ext_register_audio_notifier);
+
+/**
+ * msm_ext_cdc_init - external codec machine specific init.
+ *
+ * @pdev: platform device handle
+ * @pdata: private data of machine driver
+ * @card: sound card pointer reference
+ * @mbhc_cfg: MBHC config reference
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_ext_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *wcd_mbhc_cfg_ptr1)
+{
+ int ret = 0;
+
+ wcd_mbhc_cfg_ptr = wcd_mbhc_cfg_ptr1;
+ pdev->id = 0;
+ wcd_mbhc_cfg_ptr->moisture_en = true;
+ wcd_mbhc_cfg_ptr->mbhc_micbias = MIC_BIAS_2;
+ wcd_mbhc_cfg_ptr->anc_micbias = MIC_BIAS_2;
+ wcd_mbhc_cfg_ptr->enable_anc_mic_detect = false;
+
+ *card = populate_snd_card_dailinks(&pdev->dev, pdata->snd_card_val);
+ if (!(*card)) {
+ dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ spdev = pdev;
+ platform_set_drvdata(pdev, *card);
+ snd_soc_card_set_drvdata(*card, pdata);
+ is_initial_boot = true;
+ pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,hph-en1-gpio", 0);
+ if (!gpio_is_valid(pdata->hph_en1_gpio))
+ pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,hph-en1-gpio", 0);
+ if (!gpio_is_valid(pdata->hph_en1_gpio) && (!pdata->hph_en1_gpio_p)) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,hph-en1-gpio", pdev->dev.of_node->full_name);
+ }
+
+ pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,hph-en0-gpio", 0);
+ if (!gpio_is_valid(pdata->hph_en0_gpio))
+ pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,hph-en0-gpio", 0);
+ if (!gpio_is_valid(pdata->hph_en0_gpio) && (!pdata->hph_en0_gpio_p)) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,hph-en0-gpio", pdev->dev.of_node->full_name);
+ }
+
+ ret = msm_ext_prepare_hifi(pdata);
+ if (ret) {
+ dev_dbg(&pdev->dev, "msm_ext_prepare_hifi failed (%d)\n",
+ ret);
+ ret = 0;
+ }
+err:
+ return ret;
+}
+EXPORT_SYMBOL(msm_ext_cdc_init);
diff --git a/sound/soc/msm/msmfalcon-external.h b/sound/soc/msm/msmfalcon-external.h
new file mode 100644
index 0000000..654cb70
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-external.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSMFALCON_EXTERNAL
+#define __MSMFALCON_EXTERNAL
+
+int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+int msm_ext_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+int msm_audrx_init(struct snd_soc_pcm_runtime *rtd);
+int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+struct snd_soc_card *populate_snd_card_dailinks(struct device *dev,
+ int snd_card_val);
+int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+#ifdef CONFIG_SND_SOC_EXT_CODEC
+int msm_ext_cdc_init(struct platform_device *, struct msm_asoc_mach_data *,
+ struct snd_soc_card **, struct wcd_mbhc_config *);
+void msm_ext_register_audio_notifier(void);
+#else
+inline int msm_ext_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *wcd_mbhc_cfg_ptr1)
+{
+ return 0;
+}
+
+inline void msm_ext_register_audio_notifier(void)
+{
+}
+#endif
+#endif
diff --git a/sound/soc/msm/msmfalcon-internal.c b/sound/soc/msm/msmfalcon-internal.c
new file mode 100644
index 0000000..34db650
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-internal.c
@@ -0,0 +1,2970 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <sound/pcm_params.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "msm-audio-pinctrl.h"
+#include "msmfalcon-common.h"
+#include "../codecs/msm8x16/msm8x16-wcd.h"
+
+#define __CHIPSET__ "MSMFALCON "
+#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
+
+#define DEFAULT_MCLK_RATE 9600000
+#define NATIVE_MCLK_RATE 11289600
+
+#define WCD_MBHC_DEF_RLOADS 5
+
+#define WCN_CDC_SLIM_RX_CH_MAX 2
+#define WCN_CDC_SLIM_TX_CH_MAX 3
+
+enum {
+ INT0_MI2S = 0,
+ INT1_MI2S,
+ INT2_MI2S,
+ INT3_MI2S,
+ INT4_MI2S,
+ INT5_MI2S,
+ INT6_MI2S,
+ INT_MI2S_MAX,
+};
+
+enum {
+ BT_SLIM7,
+ FM_SLIM8,
+ SLIM_MAX,
+};
+
+/*TDM default offset currently only supporting TDM_RX_0 and TDM_TX_0 */
+static unsigned int tdm_slot_offset[TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
+ {0, 4, 8, 12, 16, 20, 24, 28},/* TX_0 | RX_0 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_1 | RX_1 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_2 | RX_2 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_3 | RX_3 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_4 | RX_4 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_5 | RX_5 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_6 | RX_6 */
+ {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_7 | RX_7 */
+};
+
+static struct afe_clk_set int_mi2s_clk[INT_MI2S_MAX] = {
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT1_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT2_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT4_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT5_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT6_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+};
+
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+/* Default configuration of MI2S channels */
+static struct dev_config int_mi2s_cfg[] = {
+ [INT0_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [INT1_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [INT2_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [INT3_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [INT4_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [INT5_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [INT6_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static struct dev_config bt_fm_cfg[] = {
+ [BT_SLIM7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [FM_SLIM8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static char const *int_mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_96", "KHZ_192"};
+static const char *const int_mi2s_ch_text[] = {"One", "Two"};
+static const char *const int_mi2s_tx_ch_text[] = {"One", "Two",
+ "Three", "Four"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
+static const char *const loopback_mclk_text[] = {"DISABLE", "ENABLE"};
+static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_48"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_sample_rate, int_mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_chs, int_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int2_mi2s_tx_sample_rate, int_mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int2_mi2s_tx_chs, int_mi2s_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int2_mi2s_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int3_mi2s_tx_sample_rate, int_mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int3_mi2s_tx_chs, int_mi2s_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int3_mi2s_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_sample_rate, int_mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_chs, int_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int5_mi2s_tx_chs, int_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(loopback_mclk_en, loopback_mclk_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
+
+static int msm_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+static int msm_int_enable_dig_cdc_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm);
+static int msm_int_mclk0_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+static int msm_int_mi2s_snd_startup(struct snd_pcm_substream *substream);
+static void msm_int_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
+
+static struct wcd_mbhc_config *mbhc_cfg_ptr;
+
+static int int_mi2s_get_bit_format_val(int bit_format)
+{
+ int val = 0;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ val = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static int int_mi2s_get_bit_format(int val)
+{
+ int bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+
+ switch (val) {
+ case 0:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ default:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return bit_fmt;
+}
+
+static int int_mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int port_id = 0;
+
+ if (strnstr(kcontrol->id.name, "INT0_MI2S", sizeof("INT0_MI2S")))
+ port_id = INT0_MI2S;
+ else if (strnstr(kcontrol->id.name, "INT2_MI2S", sizeof("INT2_MI2S")))
+ port_id = INT2_MI2S;
+ else if (strnstr(kcontrol->id.name, "INT3_MI2S", sizeof("INT3_MI2S")))
+ port_id = INT3_MI2S;
+ else if (strnstr(kcontrol->id.name, "INT4_MI2S", sizeof("INT4_MI2S")))
+ port_id = INT4_MI2S;
+ else {
+ pr_err("%s: unsupported channel: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return port_id;
+}
+
+static int int_mi2s_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = int_mi2s_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ int_mi2s_get_bit_format_val(int_mi2s_cfg[ch_num].bit_format);
+
+ pr_debug("%s: int_mi2s[%d]_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, int_mi2s_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int int_mi2s_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = int_mi2s_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ int_mi2s_cfg[ch_num].bit_format =
+ int_mi2s_get_bit_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: int_mi2s[%d]_rx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, int_mi2s_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
+ int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static int int_mi2s_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 6;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int int_mi2s_get_sample_rate(int value)
+{
+ int sample_rate;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int int_mi2s_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = int_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ int_mi2s_cfg[idx].sample_rate =
+ int_mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_sample_rate = %d, item = %d\n", __func__,
+ idx, int_mi2s_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int int_mi2s_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = int_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ int_mi2s_get_sample_rate_val(int_mi2s_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_sample_rate = %d, item = %d\n", __func__,
+ idx, int_mi2s_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int int_mi2s_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = int_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: int_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, int_mi2s_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = int_mi2s_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int int_mi2s_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = int_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ int_mi2s_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: int_mi2s_[%d]_ch = %d\n", __func__,
+ idx, int_mi2s_cfg[idx].channels);
+
+ return 1;
+}
+
+static const struct snd_soc_dapm_widget msm_int_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY_S("INT_MCLK0", -1, SND_SOC_NOPM, 0, 0,
+ msm_int_mclk0_event, SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic2", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic3", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic4", msm_dmic_event),
+};
+
+static int msm_config_hph_compander_gpio(bool enable)
+{
+ int ret = 0;
+
+ pr_debug("%s: %s HPH Compander\n", __func__,
+ enable ? "Enable" : "Disable");
+
+ if (enable) {
+ ret = msm_gpioset_activate(CLIENT_WCD, "comp_gpio");
+ if (ret) {
+ pr_err("%s: gpio set cannot be activated %s\n",
+ __func__, "comp_gpio");
+ goto done;
+ }
+ } else {
+ ret = msm_gpioset_suspend(CLIENT_WCD, "comp_gpio");
+ if (ret) {
+ pr_err("%s: gpio set cannot be de-activated %s\n",
+ __func__, "comp_gpio");
+ goto done;
+ }
+ }
+
+done:
+ return ret;
+}
+
+static int is_ext_spk_gpio_support(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata)
+{
+ const char *spk_ext_pa = "qcom,msm-spk-ext-pa";
+
+ pr_debug("%s:Enter\n", __func__);
+
+ pdata->spk_ext_pa_gpio = of_get_named_gpio(pdev->dev.of_node,
+ spk_ext_pa, 0);
+
+ if (pdata->spk_ext_pa_gpio < 0) {
+ dev_dbg(&pdev->dev,
+ "%s: missing %s in dt node\n", __func__, spk_ext_pa);
+ } else {
+ if (!gpio_is_valid(pdata->spk_ext_pa_gpio)) {
+ pr_err("%s: Invalid external speaker gpio: %d",
+ __func__, pdata->spk_ext_pa_gpio);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int enable_spk_ext_pa(struct snd_soc_codec *codec, int enable)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (!gpio_is_valid(pdata->spk_ext_pa_gpio)) {
+ pr_err("%s: Invalid gpio: %d\n", __func__,
+ pdata->spk_ext_pa_gpio);
+ return false;
+ }
+
+ pr_debug("%s: %s external speaker PA\n", __func__,
+ enable ? "Enable" : "Disable");
+
+ if (enable) {
+ ret = msm_gpioset_activate(CLIENT_WCD, "ext_spk_gpio");
+ if (ret) {
+ pr_err("%s: gpio set cannot be de-activated %s\n",
+ __func__, "ext_spk_gpio");
+ return ret;
+ }
+ gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable);
+ } else {
+ gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable);
+ ret = msm_gpioset_suspend(CLIENT_WCD, "ext_spk_gpio");
+ if (ret) {
+ pr_err("%s: gpio set cannot be de-activated %s\n",
+ __func__, "ext_spk_gpio");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int int_mi2s_get_idx_from_beid(int32_t be_id)
+{
+ int idx = 0;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_INT0_MI2S_RX:
+ idx = INT0_MI2S;
+ break;
+ case MSM_BACKEND_DAI_INT2_MI2S_TX:
+ idx = INT2_MI2S;
+ break;
+ case MSM_BACKEND_DAI_INT3_MI2S_TX:
+ idx = INT3_MI2S;
+ break;
+ case MSM_BACKEND_DAI_INT4_MI2S_RX:
+ idx = INT4_MI2S;
+ break;
+ case MSM_BACKEND_DAI_INT5_MI2S_TX:
+ idx = INT5_MI2S;
+ break;
+ default:
+ idx = INT0_MI2S;
+ break;
+ }
+
+ return idx;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
+static int int_mi2s_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ int idx;
+
+ pr_debug("%s: format = %d, rate = %d\n",
+ __func__, params_format(params), params_rate(params));
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_INT0_MI2S_RX:
+ case MSM_BACKEND_DAI_INT2_MI2S_TX:
+ case MSM_BACKEND_DAI_INT3_MI2S_TX:
+ case MSM_BACKEND_DAI_INT4_MI2S_RX:
+ case MSM_BACKEND_DAI_INT5_MI2S_TX:
+ idx = int_mi2s_get_idx_from_beid(dai_link->be_id);
+ rate->min = rate->max = int_mi2s_cfg[idx].sample_rate;
+ channels->min = channels->max =
+ int_mi2s_cfg[idx].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ int_mi2s_cfg[idx].bit_format);
+ break;
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return 0;
+}
+
+static int msm_btfm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_SLIMBUS_7_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ bt_fm_cfg[BT_SLIM7].bit_format);
+ rate->min = rate->max = bt_fm_cfg[BT_SLIM7].sample_rate;
+ channels->min = channels->max =
+ bt_fm_cfg[BT_SLIM7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_8_TX:
+ rate->min = rate->max = bt_fm_cfg[FM_SLIM8].sample_rate;
+ channels->min = channels->max =
+ bt_fm_cfg[FM_SLIM8].channels;
+ break;
+
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ (int_mi2s_cfg[INT5_MI2S].channels/2 - 1);
+ pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int_mi2s_cfg[INT5_MI2S].channels =
+ roundup_pow_of_two(ucontrol->value.integer.value[0] + 2);
+
+ pr_debug("%s: msm_vi_feed_tx_ch = %d\n",
+ __func__, int_mi2s_cfg[INT5_MI2S].channels);
+ return 1;
+}
+
+static int msm_int_enable_dig_cdc_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+ struct msm_asoc_mach_data *pdata = NULL;
+ int clk_freq_in_hz;
+ bool int_mclk0_freq_chg = false;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: enable %d mclk ref counter %d\n",
+ __func__, enable,
+ atomic_read(&pdata->int_mclk0_rsc_ref));
+ if (enable) {
+ if (int_mi2s_cfg[INT0_MI2S].sample_rate ==
+ SAMPLING_RATE_44P1KHZ)
+ clk_freq_in_hz = NATIVE_MCLK_RATE;
+ else
+ clk_freq_in_hz = pdata->mclk_freq;
+
+ if (pdata->digital_cdc_core_clk.clk_freq_in_hz
+ != clk_freq_in_hz)
+ int_mclk0_freq_chg = true;
+ if (!atomic_read(&pdata->int_mclk0_rsc_ref) ||
+ int_mclk0_freq_chg) {
+ cancel_delayed_work_sync(
+ &pdata->disable_int_mclk0_work);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if (atomic_read(&pdata->int_mclk0_enabled) == false ||
+ int_mclk0_freq_chg) {
+ pdata->digital_cdc_core_clk.clk_freq_in_hz =
+ clk_freq_in_hz;
+ pdata->digital_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s: failed to enable CCLK\n",
+ __func__);
+ mutex_unlock(
+ &pdata->cdc_int_mclk0_mutex);
+ return ret;
+ }
+ pr_debug("enabled digital codec core clk\n");
+ atomic_set(&pdata->int_mclk0_enabled, true);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ }
+ atomic_inc(&pdata->int_mclk0_rsc_ref);
+ } else {
+ cancel_delayed_work_sync(&pdata->disable_int_mclk0_work);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if (atomic_read(&pdata->int_mclk0_enabled) == true) {
+ pdata->digital_cdc_core_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0)
+ pr_err("%s: failed to disable CCLK\n",
+ __func__);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ }
+ return ret;
+}
+
+static int loopback_mclk_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static int loopback_mclk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = -EINVAL;
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: mclk_rsc_ref %d enable %ld\n",
+ __func__, atomic_read(&pdata->int_mclk0_rsc_ref),
+ ucontrol->value.integer.value[0]);
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ ret = msm_gpioset_activate(CLIENT_WCD, "int_pdm");
+ if (ret) {
+ pr_err("%s: failed to enable the pri gpios: %d\n",
+ __func__, ret);
+ break;
+ }
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if ((!atomic_read(&pdata->int_mclk0_rsc_ref)) &&
+ (!atomic_read(&pdata->int_mclk0_enabled))) {
+ pdata->digital_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s: failed to enable the MCLK: %d\n",
+ __func__, ret);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ ret = msm_gpioset_suspend(CLIENT_WCD,
+ "int_pdm");
+ if (ret)
+ pr_err("%s: failed to disable the pri gpios: %d\n",
+ __func__, ret);
+ break;
+ }
+ atomic_set(&pdata->int_mclk0_enabled, true);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ atomic_inc(&pdata->int_mclk0_rsc_ref);
+ msm8x16_wcd_mclk_enable(codec, 1, true);
+ break;
+ case 0:
+ if (atomic_read(&pdata->int_mclk0_rsc_ref) <= 0)
+ break;
+ msm8x16_wcd_mclk_enable(codec, 0, true);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if ((!atomic_dec_return(&pdata->int_mclk0_rsc_ref)) &&
+ (atomic_read(&pdata->int_mclk0_enabled))) {
+ pdata->digital_cdc_core_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s: failed to disable the CCLK: %d\n",
+ __func__, ret);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ break;
+ }
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ ret = msm_gpioset_suspend(CLIENT_WCD, "int_pdm");
+ if (ret)
+ pr_err("%s: failed to disable the pri gpios: %d\n",
+ __func__, ret);
+ break;
+ default:
+ pr_err("%s: Unexpected input value\n", __func__);
+ break;
+ }
+ return ret;
+}
+
+static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * Slimbus_7_Rx/Tx sample rate values should always be in sync (same)
+ * when used for BT_SCO use case. Return either Rx or Tx sample rate
+ * value.
+ */
+ switch (bt_fm_cfg[BT_SLIM7].sample_rate) {
+ case SAMPLING_RATE_48KHZ:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: sample rate = %d", __func__,
+ bt_fm_cfg[BT_SLIM7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 0:
+ default:
+ bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rates: slim7_rx = %d, value = %d\n",
+ __func__,
+ bt_fm_cfg[BT_SLIM7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("INT0_MI2S_RX Format", int0_mi2s_rx_format,
+ int_mi2s_bit_format_get, int_mi2s_bit_format_put),
+ SOC_ENUM_EXT("INT2_MI2S_TX Format", int2_mi2s_tx_format,
+ int_mi2s_bit_format_get, int_mi2s_bit_format_put),
+ SOC_ENUM_EXT("INT3_MI2S_TX Format", int3_mi2s_tx_format,
+ int_mi2s_bit_format_get, int_mi2s_bit_format_put),
+ SOC_ENUM_EXT("INT0_MI2S_RX SampleRate", int0_mi2s_rx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT2_MI2S_TX SampleRate", int2_mi2s_tx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT3_MI2S_TX SampleRate", int3_mi2s_tx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT0_MI2S_RX SampleRate", int0_mi2s_rx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT2_MI2S_TX SampleRate", int2_mi2s_tx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT3_MI2S_TX SampleRate", int3_mi2s_tx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT0_MI2S_RX Channels", int0_mi2s_rx_chs,
+ int_mi2s_ch_get, int_mi2s_ch_put),
+ SOC_ENUM_EXT("INT2_MI2S_TX Channels", int2_mi2s_tx_chs,
+ int_mi2s_ch_get, int_mi2s_ch_put),
+ SOC_ENUM_EXT("INT3_MI2S_TX Channels", int3_mi2s_tx_chs,
+ int_mi2s_ch_get, int_mi2s_ch_put),
+ SOC_ENUM_EXT("Loopback MCLK", loopback_mclk_en,
+ loopback_mclk_get, loopback_mclk_put),
+ SOC_ENUM_EXT("BT SampleRate", bt_sample_rate,
+ msm_bt_sample_rate_get,
+ msm_bt_sample_rate_put),
+};
+
+static const struct snd_kcontrol_new msm_swr_controls[] = {
+ SOC_ENUM_EXT("INT4_MI2S_RX Format", int4_mi2s_rx_format,
+ int_mi2s_bit_format_get, int_mi2s_bit_format_put),
+ SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT4_MI2S_RX Channels", int4_mi2s_rx_chs,
+ int_mi2s_ch_get, int_mi2s_ch_put),
+ SOC_ENUM_EXT("VI_FEED_TX Channels", int5_mi2s_tx_chs,
+ msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+};
+
+static int msm_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ int ret = 0;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = msm_gpioset_activate(CLIENT_WCD, "dmic_gpio");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be activated %sd",
+ __func__, "dmic_gpio");
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = msm_gpioset_suspend(CLIENT_WCD, "dmic_gpio");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be de-activated %sd",
+ __func__, "dmic_gpio");
+ return ret;
+ }
+ break;
+ default:
+ pr_err("%s: invalid DAPM event %d\n", __func__, event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_int_mclk0_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ int ret = 0;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ pr_debug("%s: mclk_res_ref = %d\n",
+ __func__, atomic_read(&pdata->int_mclk0_rsc_ref));
+ ret = msm_gpioset_suspend(CLIENT_WCD, "int_pdm");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be de-activated %sd",
+ __func__, "int_pdm");
+ return ret;
+ }
+ if (atomic_read(&pdata->int_mclk0_rsc_ref) == 0) {
+ pr_debug("%s: disabling MCLK\n", __func__);
+ /* disable the codec mclk config*/
+ msm8x16_wcd_mclk_enable(codec, 0, true);
+ msm_int_enable_dig_cdc_clk(codec, 0, true);
+ }
+ break;
+ default:
+ pr_err("%s: invalid DAPM event %d\n", __func__, event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int int_mi2s_get_port_id(int be_id)
+{
+ int afe_port_id;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_INT0_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_INT0_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_INT2_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_INT2_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_INT3_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_INT3_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_INT4_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_INT4_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_INT5_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_INT5_MI2S_TX;
+ break;
+ default:
+ pr_err("%s: Invalid be_id: %d\n", __func__, be_id);
+ afe_port_id = -EINVAL;
+ }
+
+ return afe_port_id;
+}
+
+static int int_mi2s_get_index(int port_id)
+{
+ int index;
+
+ switch (port_id) {
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ index = INT0_MI2S;
+ break;
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ index = INT2_MI2S;
+ break;
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ index = INT3_MI2S;
+ break;
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ index = INT4_MI2S;
+ break;
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ index = INT5_MI2S;
+ break;
+ default:
+ pr_err("%s: Invalid port_id: %d\n", __func__, port_id);
+ index = -EINVAL;
+ }
+
+ return index;
+}
+
+static u32 get_int_mi2s_bits_per_sample(u32 bit_format)
+{
+ u32 bit_per_sample;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_per_sample = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_per_sample = 16;
+ break;
+ }
+
+ return bit_per_sample;
+}
+
+static void update_int_mi2s_clk_val(int idx, int stream)
+{
+ u32 bit_per_sample;
+
+ bit_per_sample =
+ get_int_mi2s_bits_per_sample(int_mi2s_cfg[idx].bit_format);
+ int_mi2s_clk[idx].clk_freq_in_hz =
+ (int_mi2s_cfg[idx].sample_rate * int_mi2s_cfg[idx].channels
+ * bit_per_sample);
+}
+
+static int int_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int port_id = 0;
+ int index;
+
+ port_id = int_mi2s_get_port_id(rtd->dai_link->be_id);
+ if (IS_ERR_VALUE(port_id)) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto done;
+ }
+ index = int_mi2s_get_index(port_id);
+ if (index < 0) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto done;
+ }
+ if (enable) {
+ update_int_mi2s_clk_val(index, substream->stream);
+ dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+ int_mi2s_clk[index].clk_freq_in_hz);
+ }
+
+ int_mi2s_clk[index].enable = enable;
+ ret = afe_set_lpass_clock_v2(port_id,
+ &int_mi2s_clk[index]);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed for port 0x%x , err:%d\n",
+ __func__, port_id, ret);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int msm_swr_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = int_mi2s_set_sclk(substream, true);
+ if (ret < 0) {
+ pr_err("%s: failed to enable sclk %d\n",
+ __func__, ret);
+ return ret;
+ }
+ /* Enable the codec mclk config */
+ ret = msm_gpioset_activate(CLIENT_WCD, "swr_pin");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be activated %sd",
+ __func__, "swr_pin");
+ return ret;
+ }
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("%s: set fmt cpu dai failed; ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static void msm_swr_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = int_mi2s_set_sclk(substream, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed; ret=%d\n", __func__,
+ ret);
+}
+
+static int msm_int_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = int_mi2s_set_sclk(substream, true);
+ if (ret < 0) {
+ pr_err("%s: failed to enable sclk %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = msm_int_enable_dig_cdc_clk(codec, 1, true);
+ if (ret < 0) {
+ pr_err("failed to enable mclk\n");
+ return ret;
+ }
+ /* Enable the codec mclk config */
+ ret = msm_gpioset_activate(CLIENT_WCD, "int_pdm");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be activated %s\n",
+ __func__, "int_pdm");
+ return ret;
+ }
+ msm8x16_wcd_mclk_enable(codec, 1, true);
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("%s: set fmt cpu dai failed; ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static void msm_int_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = int_mi2s_set_sclk(substream, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed; ret=%d\n", __func__,
+ ret);
+ if (atomic_read(&pdata->int_mclk0_rsc_ref) > 0) {
+ atomic_dec(&pdata->int_mclk0_rsc_ref);
+ pr_debug("%s: decrementing mclk_res_ref %d\n",
+ __func__,
+ atomic_read(&pdata->int_mclk0_rsc_ref));
+ }
+}
+
+static void *def_msm_int_wcd_mbhc_cal(void)
+{
+ void *msm_int_wcd_cal;
+ struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+
+ msm_int_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ WCD_MBHC_DEF_RLOADS), GFP_KERNEL);
+ if (!msm_int_wcd_cal)
+ return NULL;
+
+#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(msm_int_wcd_cal)->X) = (Y))
+ S(v_hs_max, 1500);
+#undef S
+#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(msm_int_wcd_cal)->X) = (Y))
+ S(num_btn, WCD_MBHC_DEF_BUTTONS);
+#undef S
+
+
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(msm_int_wcd_cal);
+ btn_low = btn_cfg->_v_btn_low;
+ btn_high = ((void *)&btn_cfg->_v_btn_low) +
+ (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+ /*
+ * In SW we are maintaining two sets of threshold register
+ * one for current source and another for Micbias.
+ * all btn_low corresponds to threshold for current source
+ * all bt_high corresponds to threshold for Micbias
+ * Below thresholds are based on following resistances
+ * 0-70 == Button 0
+ * 110-180 == Button 1
+ * 210-290 == Button 2
+ * 360-680 == Button 3
+ */
+ btn_low[0] = 75;
+ btn_high[0] = 75;
+ btn_low[1] = 150;
+ btn_high[1] = 150;
+ btn_low[2] = 225;
+ btn_high[2] = 225;
+ btn_low[3] = 450;
+ btn_high[3] = 450;
+ btn_low[4] = 500;
+ btn_high[4] = 500;
+
+ return msm_int_wcd_cal;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = -ENOMEM;
+
+ pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+
+ snd_soc_add_codec_controls(codec, msm_common_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+
+ snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets,
+ ARRAY_SIZE(msm_int_dapm_widgets));
+
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Secondary Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "HEADPHONE");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK_OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
+
+ snd_soc_dapm_sync(dapm);
+
+ msm8x16_wcd_spk_ext_pa_cb(enable_spk_ext_pa, codec);
+ msm8x16_wcd_hph_comp_cb(msm_config_hph_compander_gpio, codec);
+
+ mbhc_cfg_ptr->calibration = def_msm_int_wcd_mbhc_cal();
+ if (mbhc_cfg_ptr->calibration) {
+ ret = msm8x16_wcd_hs_detect(codec, mbhc_cfg_ptr);
+ if (ret) {
+ pr_err("%s: msm8x16_wcd_hs_detect failed\n", __func__);
+ kfree(mbhc_cfg_ptr->calibration);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int msm_swr_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+
+ snd_soc_add_codec_controls(codec, msm_swr_controls,
+ ARRAY_SIZE(msm_swr_controls));
+
+ snd_soc_dapm_ignore_suspend(dapm, "AIF1_SWR Playback");
+ snd_soc_dapm_ignore_suspend(dapm, "VIfeed_SWR");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF1_SWR VI");
+ snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_SWR");
+
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd)
+{
+ unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158};
+ unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+}
+
+static int msm_wcn_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret;
+
+ dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret) {
+ dev_err(rtd->dev,
+ "%s: failed to get BTFM codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch);
+ if (ret)
+ dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+
+exit:
+ return ret;
+}
+
+static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width,
+ int slots)
+{
+ unsigned int slot_mask = 0;
+ int i, j;
+ unsigned int *slot_offset;
+
+ for (i = TDM_0; i < TDM_PORT_MAX; i++) {
+ slot_offset = tdm_slot_offset[i];
+
+ for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) {
+ if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ slot_mask |=
+ (1 << ((slot_offset[j] * 8) / slot_width));
+ else
+ break;
+ }
+ }
+
+ return slot_mask;
+}
+
+static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int channels, slot_width, slots;
+ unsigned int slot_mask;
+ unsigned int *slot_offset;
+ int offset_channels = 0;
+ int i;
+
+ pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+ channels = params_channels(params);
+ switch (channels) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /*
+ * up to 8 channels HW config should
+ * use 32 bit slot width for max support of
+ * stream bit width. (slot_width > bit_width)
+ */
+ slot_width = 32;
+ break;
+ default:
+ pr_err("%s: invalid param format 0x%x\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+ slots = 8;
+ slot_mask = tdm_param_set_slot_mask(cpu_dai->id,
+ slot_width,
+ slots);
+ if (!slot_mask) {
+ pr_err("%s: invalid slot_mask 0x%x\n",
+ __func__, slot_mask);
+ return -EINVAL;
+ }
+ break;
+ default:
+ pr_err("%s: invalid param channels %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ /* currently only supporting TDM_RX_0 and TDM_TX_0 */
+ switch (cpu_dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ slot_offset = tdm_slot_offset[TDM_0];
+ break;
+ default:
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ offset_channels++;
+ else
+ break;
+ }
+
+ if (offset_channels == 0) {
+ pr_err("%s: slot offset not supported, offset_channels %d\n",
+ __func__, offset_channels);
+ return -EINVAL;
+ }
+
+ if (channels > offset_channels) {
+ pr_err("%s: channels %d exceed offset_channels %d\n",
+ __func__, channels, offset_channels);
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ channels, slot_offset);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
+ slot_offset, 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static struct snd_soc_ops msm_tdm_be_ops = {
+ .hw_params = msm_tdm_snd_hw_params
+};
+
+static struct snd_soc_ops msm_wcn_ops = {
+ .hw_params = msm_wcn_hw_params,
+};
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .shutdown = msm_mi2s_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_aux_pcm_be_ops = {
+ .startup = msm_aux_pcm_snd_startup,
+ .shutdown = msm_aux_pcm_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_int_mi2s_be_ops = {
+ .startup = msm_int_mi2s_snd_startup,
+ .shutdown = msm_int_mi2s_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_swr_mi2s_be_ops = {
+ .startup = msm_swr_mi2s_snd_startup,
+ .shutdown = msm_swr_mi2s_snd_shutdown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_int_dai[] = {
+ /* FrontEnd DAI Links */
+ {/* hw:x,0 */
+ .name = MSM_DAILINK_NAME(Media1),
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {/* hw:x,1 */
+ .name = MSM_DAILINK_NAME(Media2),
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {/* hw:x,2 */
+ .name = "VoiceMMode1",
+ .stream_name = "VoiceMMode1",
+ .cpu_dai_name = "VoiceMMode1",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE1,
+ },
+ {/* hw:x,3 */
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {/* hw:x,4 */
+ .name = MSM_DAILINK_NAME(ULL),
+ .stream_name = "ULL",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-dsp.2",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {/* hw:x,5 */
+ .name = "INT4 MI2S_RX Hostless",
+ .stream_name = "INT4 MI2S_RX Hostless",
+ .cpu_dai_name = "INT4_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,6 */
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,7 */
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {/* hw:x,8 */
+ .name = MSM_DAILINK_NAME(Compress1),
+ .stream_name = "Compress1",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {/* hw:x,9*/
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,10 */
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,11 */
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,12 */
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,13 */
+ .name = MSM_DAILINK_NAME(LowLatency),
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
+ /* LSM FE */
+ {/* hw:x,14 */
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ {/* hw:x,15 */
+ .name = MSM_DAILINK_NAME(Compress2),
+ .stream_name = "Compress2",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {/* hw:x,16 */
+ .name = MSM_DAILINK_NAME(Compress3),
+ .stream_name = "Compress3",
+ .cpu_dai_name = "MultiMedia10",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+ },
+ {/* hw:x,17 */
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ),
+ .stream_name = "MM_NOIRQ",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-pcm-dsp-noirq",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
+ {/* hw:x,18 */
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,19 */
+ .name = "VoiceMMode2",
+ .stream_name = "VoiceMMode2",
+ .cpu_dai_name = "VoiceMMode2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE2,
+ },
+ {/* hw:x,20 */
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {/* hw:x,21 */
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {/* hw:x,22 */
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {/* hw:x,23 */
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {/* hw:x,24 */
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM6
+ },
+ {/* hw:x,25 */
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {/* hw:x,26 */
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {/* hw:x,27 */
+ .name = MSM_DAILINK_NAME(Media9),
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
+ {/* hw:x,28 */
+ .name = MSM_DAILINK_NAME(Compress4),
+ .stream_name = "Compress4",
+ .cpu_dai_name = "MultiMedia11",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA11,
+ },
+ {/* hw:x,29 */
+ .name = MSM_DAILINK_NAME(Compress5),
+ .stream_name = "Compress5",
+ .cpu_dai_name = "MultiMedia12",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA12,
+ },
+ {/* hw:x,30 */
+ .name = MSM_DAILINK_NAME(Compress6),
+ .stream_name = "Compress6",
+ .cpu_dai_name = "MultiMedia13",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA13,
+ },
+ {/* hw:x,31 */
+ .name = MSM_DAILINK_NAME(Compress7),
+ .stream_name = "Compress7",
+ .cpu_dai_name = "MultiMedia14",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+ },
+ {/* hw:x,32 */
+ .name = MSM_DAILINK_NAME(Compress8),
+ .stream_name = "Compress8",
+ .cpu_dai_name = "MultiMedia15",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15,
+ },
+ {/* hw:x,33 */
+ .name = MSM_DAILINK_NAME(Compress9),
+ .stream_name = "Compress9",
+ .cpu_dai_name = "MultiMedia16",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA16,
+ },
+ {/* hw:x,34 */
+ .name = "SLIMBUS_8 Hostless",
+ .stream_name = "SLIMBUS8_HOSTLESS Capture",
+ .cpu_dai_name = "SLIMBUS8_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,35 */
+ .name = LPASS_BE_INT5_MI2S_TX,
+ .stream_name = "INT5_mi2s Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.12",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "msm_swr_codec",
+ .codec_dai_name = "msm_swr_vifeedback",
+ .be_id = MSM_BACKEND_DAI_INT5_MI2S_TX,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_swr_mi2s_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,36 */
+ .name = "Primary MI2S_RX Hostless",
+ .stream_name = "Primary MI2S_RX Hostless",
+ .cpu_dai_name = "PRI_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,37 */
+ .name = "Secondary MI2S_RX Hostless",
+ .stream_name = "Secondary MI2S_RX Hostless",
+ .cpu_dai_name = "SEC_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,38 */
+ .name = "Tertiary MI2S_RX Hostless",
+ .stream_name = "Tertiary MI2S_RX Hostless",
+ .cpu_dai_name = "TERT_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,39 */
+ .name = "INT0 MI2S_RX Hostless",
+ .stream_name = "INT0 MI2S_RX Hostless",
+ .cpu_dai_name = "INT0_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* Backend I2S DAI Links */
+ {
+ .name = LPASS_BE_INT0_MI2S_RX,
+ .stream_name = "INT0 MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.7",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "cajon_codec",
+ .codec_dai_name = "msm8x16_wcd_i2s_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
+ ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .be_id = MSM_BACKEND_DAI_INT0_MI2S_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_int_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT4_MI2S_RX,
+ .stream_name = "INT4 MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.11",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm_swr_codec",
+ .codec_dai_name = "msm_swr_i2s_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_INT4_MI2S_RX,
+ .init = &msm_swr_audrx_init,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_swr_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT2_MI2S_TX,
+ .stream_name = "INT2 MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.9",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "cajon_codec",
+ .codec_dai_name = "msm8x16_wcd_i2s_tx2",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
+ ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .be_id = MSM_BACKEND_DAI_INT2_MI2S_TX,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_int_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT3_MI2S_TX,
+ .stream_name = "INT3 MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.10",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "cajon_codec",
+ .codec_dai_name = "msm8x16_wcd_i2s_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
+ ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .be_id = MSM_BACKEND_DAI_INT3_MI2S_TX,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_int_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_RX,
+ .stream_name = "USB Audio Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.28672",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_USB_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_TX,
+ .stream_name = "USB Audio Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.28673",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_USB_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_RX_0,
+ .stream_name = "Primary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36864",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_TX_0,
+ .stream_name = "Primary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36865",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_RX_0,
+ .stream_name = "Secondary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36880",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_TX_0,
+ .stream_name = "Secondary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36881",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_RX_0,
+ .stream_name = "Tertiary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36896",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_TX_0,
+ .stream_name = "Tertiary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36897",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_RX_0,
+ .stream_name = "Quaternary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36912",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_TX_0,
+ .stream_name = "Quaternary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36913",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
+ {
+ .name = LPASS_BE_PRI_MI2S_RX,
+ .stream_name = "Primary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_MI2S_TX,
+ .stream_name = "Primary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_RX,
+ .stream_name = "Secondary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_TX,
+ .stream_name = "Secondary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_RX,
+ .stream_name = "Tertiary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_TX,
+ .stream_name = "Tertiary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_RX,
+ .stream_name = "Quaternary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_TX,
+ .stream_name = "Quaternary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
+ /* Primary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Secondary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_SEC_AUXPCM_RX,
+ .stream_name = "Sec AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SEC_AUXPCM_TX,
+ .stream_name = "Sec AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Tertiary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_TERT_AUXPCM_RX,
+ .stream_name = "Tert AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_TERT_AUXPCM_TX,
+ .stream_name = "Tert AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Quaternary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_RX,
+ .stream_name = "Quat AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_TX,
+ .stream_name = "Quat AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+};
+
+
+static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_7_RX,
+ .stream_name = "Slimbus7 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16398",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ /* BT codec driver determines capabilities based on
+ * dai name, bt codecdai name should always contains
+ * supported usecase information
+ */
+ .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ .be_hw_params_fixup = msm_btfm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_7_TX,
+ .stream_name = "Slimbus7 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16399",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_bt_sco_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ .be_hw_params_fixup = msm_btfm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_8_TX,
+ .stream_name = "Slimbus8 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16401",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_fm_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ .be_hw_params_fixup = msm_btfm_be_hw_params_fixup,
+ .init = &msm_wcn_init,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_int_dai_links[
+ARRAY_SIZE(msm_int_dai) +
+ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ARRAY_SIZE(msm_auxpcm_be_dai_links)+
+ARRAY_SIZE(msm_wcn_be_dai_links)];
+
+static struct snd_soc_card msmfalcon_card = {
+ /* snd_soc_card_msmfalcon */
+ .name = "msmfalcon-snd-card",
+ .dai_link = msm_int_dai,
+ .num_links = ARRAY_SIZE(msm_int_dai),
+};
+
+static void msm_disable_int_mclk0(struct work_struct *work)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct delayed_work *dwork;
+ int ret = 0;
+
+ dwork = to_delayed_work(work);
+ pdata = container_of(dwork, struct msm_asoc_mach_data,
+ disable_int_mclk0_work);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ pr_debug("%s: mclk_enabled %d mclk_rsc_ref %d\n", __func__,
+ atomic_read(&pdata->int_mclk0_enabled),
+ atomic_read(&pdata->int_mclk0_rsc_ref));
+
+ if (atomic_read(&pdata->int_mclk0_enabled) == true
+ && atomic_read(&pdata->int_mclk0_rsc_ref) == 0) {
+ pr_debug("Disable the mclk\n");
+ pdata->digital_cdc_core_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0)
+ pr_err("%s failed to disable the CCLK\n", __func__);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+}
+
+static void msm_int_dt_parse_cap_info(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata)
+{
+ const char *ext1_cap = "qcom,msm-micbias1-ext-cap";
+ const char *ext2_cap = "qcom,msm-micbias2-ext-cap";
+
+ pdata->micbias1_cap_mode =
+ (of_property_read_bool(pdev->dev.of_node, ext1_cap) ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+
+ pdata->micbias2_cap_mode =
+ (of_property_read_bool(pdev->dev.of_node, ext2_cap) ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+}
+
+static struct snd_soc_card *msm_int_populate_sndcard_dailinks(
+ struct device *dev)
+{
+ struct snd_soc_card *card = &msmfalcon_card;
+ struct snd_soc_dai_link *dailink;
+ int len1;
+
+ card->name = dev_name(dev);
+ len1 = ARRAY_SIZE(msm_int_dai);
+ memcpy(msm_int_dai_links, msm_int_dai, sizeof(msm_int_dai));
+ dailink = msm_int_dai_links;
+ if (of_property_read_bool(dev->of_node,
+ "qcom,mi2s-audio-intf")) {
+ memcpy(dailink + len1,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ len1 += ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,auxpcm-audio-intf")) {
+ memcpy(dailink + len1,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ len1 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(dailink + len1,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
+ len1 += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
+ card->dai_link = dailink;
+ card->num_links = len1;
+ return card;
+}
+
+static int msm_internal_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card *card)
+{
+ const char *type = NULL;
+ const char *hs_micbias_type = "qcom,msm-hs-micbias-type";
+ int ret;
+
+ ret = is_ext_spk_gpio_support(pdev, pdata);
+ if (ret < 0)
+ dev_dbg(&pdev->dev,
+ "%s: doesn't support external speaker pa\n",
+ __func__);
+
+ ret = of_property_read_string(pdev->dev.of_node,
+ hs_micbias_type, &type);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: missing %s in dt node\n",
+ __func__, hs_micbias_type);
+ goto err;
+ }
+ if (!strcmp(type, "external")) {
+ dev_dbg(&pdev->dev, "Headset is using external micbias\n");
+ mbhc_cfg_ptr->hs_ext_micbias = true;
+ } else {
+ dev_dbg(&pdev->dev, "Headset is using internal micbias\n");
+ mbhc_cfg_ptr->hs_ext_micbias = false;
+ }
+
+ /* initialize the int_mclk0 */
+ pdata->digital_cdc_core_clk.clk_set_minor_version =
+ AFE_API_VERSION_I2S_CONFIG;
+ pdata->digital_cdc_core_clk.clk_id =
+ Q6AFE_LPASS_CLK_ID_INT_MCLK_0;
+ pdata->digital_cdc_core_clk.clk_freq_in_hz =
+ pdata->mclk_freq;
+ pdata->digital_cdc_core_clk.clk_attri =
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
+ pdata->digital_cdc_core_clk.clk_root =
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+ pdata->digital_cdc_core_clk.enable = 1;
+
+ /* Initialize loopback mode to false */
+ pdata->lb_mode = false;
+
+ msm_int_dt_parse_cap_info(pdev, pdata);
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, pdata);
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret)
+ goto err;
+ /* initialize timer */
+ INIT_DELAYED_WORK(&pdata->disable_int_mclk0_work,
+ msm_disable_int_mclk0);
+ mutex_init(&pdata->cdc_int_mclk0_mutex);
+ atomic_set(&pdata->int_mclk0_rsc_ref, 0);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+
+ dev_info(&pdev->dev, "%s: default codec configured\n", __func__);
+
+ return 0;
+err:
+ return ret;
+}
+
+/**
+ * msm_int_cdc_init - internal codec machine specific init.
+ *
+ * @pdev: platform device handle
+ * @pdata: private data of machine driver
+ * @card: sound card pointer reference
+ * @mbhc_cfg: MBHC config reference
+ *
+ * Returns 0.
+ */
+int msm_int_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ mbhc_cfg_ptr = mbhc_cfg;
+
+ *card = msm_int_populate_sndcard_dailinks(&pdev->dev);
+ msm_internal_init(pdev, pdata, *card);
+ return 0;
+}
+EXPORT_SYMBOL(msm_int_cdc_init);
diff --git a/sound/soc/msm/msmfalcon-internal.h b/sound/soc/msm/msmfalcon-internal.h
new file mode 100644
index 0000000..e5e3e7c
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-internal.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSMFALCON_INTERNAL
+#define __MSMFALCON_INTERNAL
+
+#include <sound/soc.h>
+
+#ifdef CONFIG_SND_SOC_INT_CODEC
+int msm_int_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *mbhc_cfg);
+#else
+int msm_int_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
new file mode 100644
index 0000000..461c09d
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -0,0 +1,21 @@
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
+ msm-compress-q6-v2.o msm-compr-q6-v2.o \
+ msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
+ msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
+ msm-lsm-client.o msm-pcm-host-voice-v2.o \
+ msm-audio-effects-q6-v2.o msm-pcm-loopback-v2.o \
+ msm-dai-slim.o \
+ adsp_err.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
+ msm-dai-stub-v2.o
+obj-$(CONFIG_SND_HWDEP) += msm-pcm-routing-devdep.o
+obj-$(CONFIG_DTS_EAGLE) += msm-dts-eagle.o
+obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
+obj-$(CONFIG_DOLBY_DS2) += msm-ds2-dap-config.o
+obj-$(CONFIG_DTS_SRS_TM) += msm-dts-srs-tm-config.o
+obj-$(CONFIG_QTI_PP) += msm-qti-pp-config.o
+obj-y += audio_calibration.o audio_cal_utils.o q6adm.o q6afe.o q6asm.o \
+ q6audio-v2.o q6voice.o q6core.o rtac.o q6lsm.o audio_slimslave.o \
+ msm-pcm-q6-noirq.o
+ocmem-audio-objs += audio_ocmem.o
+obj-$(CONFIG_AUDIO_OCMEM) += ocmem-audio.o
diff --git a/sound/soc/msm/qdsp6v2/adsp_err.c b/sound/soc/msm/qdsp6v2/adsp_err.c
new file mode 100644
index 0000000..d17bd6a
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/adsp_err.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <sound/apr_audio-v2.h>
+
+
+/* ERROR STRING */
+/* Success. The operation completed with no errors. */
+#define ADSP_EOK_STR "ADSP_EOK"
+/* General failure. */
+#define ADSP_EFAILED_STR "ADSP_EFAILED"
+/* Bad operation parameter. */
+#define ADSP_EBADPARAM_STR "ADSP_EBADPARAM"
+/* Unsupported routine or operation. */
+#define ADSP_EUNSUPPORTED_STR "ADSP_EUNSUPPORTED"
+/* Unsupported version. */
+#define ADSP_EVERSION_STR "ADSP_EVERSION"
+/* Unexpected problem encountered. */
+#define ADSP_EUNEXPECTED_STR "ADSP_EUNEXPECTED"
+/* Unhandled problem occurred. */
+#define ADSP_EPANIC_STR "ADSP_EPANIC"
+/* Unable to allocate resource. */
+#define ADSP_ENORESOURCE_STR "ADSP_ENORESOURCE"
+/* Invalid handle. */
+#define ADSP_EHANDLE_STR "ADSP_EHANDLE"
+/* Operation is already processed. */
+#define ADSP_EALREADY_STR "ADSP_EALREADY"
+/* Operation is not ready to be processed. */
+#define ADSP_ENOTREADY_STR "ADSP_ENOTREADY"
+/* Operation is pending completion. */
+#define ADSP_EPENDING_STR "ADSP_EPENDING"
+/* Operation could not be accepted or processed. */
+#define ADSP_EBUSY_STR "ADSP_EBUSY"
+/* Operation aborted due to an error. */
+#define ADSP_EABORTED_STR "ADSP_EABORTED"
+/* Operation preempted by a higher priority. */
+#define ADSP_EPREEMPTED_STR "ADSP_EPREEMPTED"
+/* Operation requests intervention to complete. */
+#define ADSP_ECONTINUE_STR "ADSP_ECONTINUE"
+/* Operation requests immediate intervention to complete. */
+#define ADSP_EIMMEDIATE_STR "ADSP_EIMMEDIATE"
+/* Operation is not implemented. */
+#define ADSP_ENOTIMPL_STR "ADSP_ENOTIMPL"
+/* Operation needs more data or resources. */
+#define ADSP_ENEEDMORE_STR "ADSP_ENEEDMORE"
+/* Operation does not have memory. */
+#define ADSP_ENOMEMORY_STR "ADSP_ENOMEMORY"
+/* Item does not exist. */
+#define ADSP_ENOTEXIST_STR "ADSP_ENOTEXIST"
+/* Unexpected error code. */
+#define ADSP_ERR_MAX_STR "ADSP_ERR_MAX"
+
+#ifdef CONFIG_SND_SOC_QDSP_DEBUG
+static bool adsp_err_panic;
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_adsp_err;
+
+static ssize_t adsp_err_debug_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char cmd;
+
+ if (copy_from_user(&cmd, ubuf, 1))
+ return -EFAULT;
+
+ if (cmd == '0')
+ adsp_err_panic = false;
+ else
+ adsp_err_panic = true;
+
+ return cnt;
+}
+
+static const struct file_operations adsp_err_debug_ops = {
+ .write = adsp_err_debug_write,
+};
+#endif
+#endif
+
+struct adsp_err_code {
+ int lnx_err_code;
+ char *adsp_err_str;
+};
+
+
+static struct adsp_err_code adsp_err_code_info[ADSP_ERR_MAX+1] = {
+ { 0, ADSP_EOK_STR},
+ { -ENOTRECOVERABLE, ADSP_EFAILED_STR},
+ { -EINVAL, ADSP_EBADPARAM_STR},
+ { -EOPNOTSUPP, ADSP_EUNSUPPORTED_STR},
+ { -ENOPROTOOPT, ADSP_EVERSION_STR},
+ { -ENOTRECOVERABLE, ADSP_EUNEXPECTED_STR},
+ { -ENOTRECOVERABLE, ADSP_EPANIC_STR},
+ { -ENOSPC, ADSP_ENORESOURCE_STR},
+ { -EBADR, ADSP_EHANDLE_STR},
+ { -EALREADY, ADSP_EALREADY_STR},
+ { -EPERM, ADSP_ENOTREADY_STR},
+ { -EINPROGRESS, ADSP_EPENDING_STR},
+ { -EBUSY, ADSP_EBUSY_STR},
+ { -ECANCELED, ADSP_EABORTED_STR},
+ { -EAGAIN, ADSP_EPREEMPTED_STR},
+ { -EAGAIN, ADSP_ECONTINUE_STR},
+ { -EAGAIN, ADSP_EIMMEDIATE_STR},
+ { -EAGAIN, ADSP_ENOTIMPL_STR},
+ { -ENODATA, ADSP_ENEEDMORE_STR},
+ { -EADV, ADSP_ERR_MAX_STR},
+ { -ENOMEM, ADSP_ENOMEMORY_STR},
+ { -ENODEV, ADSP_ENOTEXIST_STR},
+ { -EADV, ADSP_ERR_MAX_STR},
+};
+
+#ifdef CONFIG_SND_SOC_QDSP_DEBUG
+static inline void adsp_err_check_panic(u32 adsp_error)
+{
+ if (adsp_err_panic && adsp_error != ADSP_EALREADY)
+ panic("%s: encounter adsp_err=0x%x\n", __func__, adsp_error);
+}
+#else
+static inline void adsp_err_check_panic(u32 adsp_error) {}
+#endif
+
+int adsp_err_get_lnx_err_code(u32 adsp_error)
+{
+ adsp_err_check_panic(adsp_error);
+
+ if (adsp_error > ADSP_ERR_MAX)
+ return adsp_err_code_info[ADSP_ERR_MAX].lnx_err_code;
+ else
+ return adsp_err_code_info[adsp_error].lnx_err_code;
+}
+
+char *adsp_err_get_err_str(u32 adsp_error)
+{
+ if (adsp_error > ADSP_ERR_MAX)
+ return adsp_err_code_info[ADSP_ERR_MAX].adsp_err_str;
+ else
+ return adsp_err_code_info[adsp_error].adsp_err_str;
+}
+
+#if defined(CONFIG_SND_SOC_QDSP_DEBUG) && defined(CONFIG_DEBUG_FS)
+static int __init adsp_err_init(void)
+{
+
+
+ debugfs_adsp_err = debugfs_create_file("msm_adsp_audio_debug",
+ S_IFREG | 0444, NULL, NULL,
+ &adsp_err_debug_ops);
+
+ return 0;
+}
+
+device_initcall(adsp_err_init);
+#endif
diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
new file mode 100644
index 0000000..f88087b
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
@@ -0,0 +1,965 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <sound/audio_cal_utils.h>
+
+static int unmap_memory(struct cal_type_data *cal_type,
+ struct cal_block_data *cal_block);
+
+size_t get_cal_info_size(int32_t cal_type)
+{
+ size_t size = 0;
+
+ switch (cal_type) {
+ case CVP_VOC_RX_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_voc_top);
+ break;
+ case CVP_VOC_TX_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_voc_top);
+ break;
+ case CVP_VOCPROC_STATIC_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_vocproc);
+ break;
+ case CVP_VOCPROC_DYNAMIC_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_vocvol);
+ break;
+ case CVS_VOCSTRM_STATIC_CAL_TYPE:
+ size = 0;
+ break;
+ case CVP_VOCDEV_CFG_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_vocdev_cfg);
+ break;
+ case CVP_VOCPROC_STATIC_COL_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_voc_col);
+ break;
+ case CVP_VOCPROC_DYNAMIC_COL_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_voc_col);
+ break;
+ case CVS_VOCSTRM_STATIC_COL_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_voc_col);
+ break;
+ case ADM_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_adm_top);
+ break;
+ case ADM_CUST_TOPOLOGY_CAL_TYPE:
+ case CORE_CUSTOM_TOPOLOGIES_CAL_TYPE:
+ size = 0;
+ break;
+ case ADM_AUDPROC_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_audproc);
+ break;
+ case ADM_AUDVOL_CAL_TYPE:
+ case ADM_RTAC_AUDVOL_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_audvol);
+ break;
+ case ASM_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_asm_top);
+ break;
+ case ASM_CUST_TOPOLOGY_CAL_TYPE:
+ size = 0;
+ break;
+ case ASM_AUDSTRM_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_audstrm);
+ break;
+ case AFE_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_afe_top);
+ break;
+ case AFE_CUST_TOPOLOGY_CAL_TYPE:
+ size = 0;
+ break;
+ case AFE_COMMON_RX_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_afe);
+ break;
+ case AFE_COMMON_TX_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_afe);
+ break;
+ case AFE_FB_SPKR_PROT_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_spk_prot_cfg);
+ break;
+ case AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE:
+ /*
+ * Since get and set parameter structures are different in size
+ * use the maximum size of get and set parameter structure
+ */
+ size = max(sizeof(struct audio_cal_info_sp_th_vi_ftm_cfg),
+ sizeof(struct audio_cal_info_sp_th_vi_param));
+ break;
+ case AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE:
+ /*
+ * Since get and set parameter structures are different in size
+ * use the maximum size of get and set parameter structure
+ */
+ size = max(sizeof(struct audio_cal_info_sp_ex_vi_ftm_cfg),
+ sizeof(struct audio_cal_info_sp_ex_vi_param));
+ break;
+ case AFE_ANC_CAL_TYPE:
+ size = 0;
+ break;
+ case AFE_AANC_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_aanc);
+ break;
+ case AFE_HW_DELAY_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_hw_delay);
+ break;
+ case AFE_SIDETONE_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_sidetone);
+ break;
+ case LSM_CUST_TOPOLOGY_CAL_TYPE:
+ size = 0;
+ break;
+ case LSM_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_lsm_top);
+ break;
+ case ULP_LSM_TOPOLOGY_ID_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_lsm_top);
+ break;
+ case LSM_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_lsm);
+ break;
+ case ADM_RTAC_INFO_CAL_TYPE:
+ size = 0;
+ break;
+ case VOICE_RTAC_INFO_CAL_TYPE:
+ size = 0;
+ break;
+ case ADM_RTAC_APR_CAL_TYPE:
+ size = 0;
+ break;
+ case ASM_RTAC_APR_CAL_TYPE:
+ size = 0;
+ break;
+ case VOICE_RTAC_APR_CAL_TYPE:
+ size = 0;
+ break;
+ case MAD_CAL_TYPE:
+ size = 0;
+ break;
+ case ULP_AFE_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_afe);
+ break;
+ case ULP_LSM_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_lsm);
+ break;
+ case DTS_EAGLE_CAL_TYPE:
+ size = 0;
+ break;
+ case AUDIO_CORE_METAINFO_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_metainfo);
+ break;
+ case SRS_TRUMEDIA_CAL_TYPE:
+ size = 0;
+ break;
+ default:
+ pr_err("%s:Invalid cal type %d!",
+ __func__, cal_type);
+ }
+ return size;
+}
+
+size_t get_user_cal_type_size(int32_t cal_type)
+{
+ size_t size = 0;
+
+ switch (cal_type) {
+ case CVP_VOC_RX_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_voc_top);
+ break;
+ case CVP_VOC_TX_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_voc_top);
+ break;
+ case CVP_VOCPROC_STATIC_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_vocproc);
+ break;
+ case CVP_VOCPROC_DYNAMIC_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_vocvol);
+ break;
+ case CVS_VOCSTRM_STATIC_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_basic);
+ break;
+ case CVP_VOCDEV_CFG_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_vocdev_cfg);
+ break;
+ case CVP_VOCPROC_STATIC_COL_CAL_TYPE:
+ case CVP_VOCPROC_DYNAMIC_COL_CAL_TYPE:
+ case CVS_VOCSTRM_STATIC_COL_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_voc_col);
+ break;
+ case ADM_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_adm_top);
+ break;
+ case ADM_CUST_TOPOLOGY_CAL_TYPE:
+ case CORE_CUSTOM_TOPOLOGIES_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_basic);
+ break;
+ case ADM_AUDPROC_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_audproc);
+ break;
+ case ADM_AUDVOL_CAL_TYPE:
+ case ADM_RTAC_AUDVOL_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_audvol);
+ break;
+ case ASM_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_asm_top);
+ break;
+ case ASM_CUST_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_basic);
+ break;
+ case ASM_AUDSTRM_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_audstrm);
+ break;
+ case AFE_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_afe_top);
+ break;
+ case AFE_CUST_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_basic);
+ break;
+ case AFE_COMMON_RX_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_afe);
+ break;
+ case AFE_COMMON_TX_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_afe);
+ break;
+ case AFE_FB_SPKR_PROT_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_fb_spk_prot_cfg);
+ break;
+ case AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE:
+ /*
+ * Since get and set parameter structures are different in size
+ * use the maximum size of get and set parameter structure
+ */
+ size = max(sizeof(struct audio_cal_type_sp_th_vi_ftm_cfg),
+ sizeof(struct audio_cal_type_sp_th_vi_param));
+ break;
+ case AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE:
+ /*
+ * Since get and set parameter structures are different in size
+ * use the maximum size of get and set parameter structure
+ */
+ size = max(sizeof(struct audio_cal_type_sp_ex_vi_ftm_cfg),
+ sizeof(struct audio_cal_type_sp_ex_vi_param));
+ break;
+ case AFE_ANC_CAL_TYPE:
+ size = 0;
+ break;
+ case AFE_AANC_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_aanc);
+ break;
+ case AFE_HW_DELAY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_hw_delay);
+ break;
+ case AFE_SIDETONE_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_sidetone);
+ break;
+ case LSM_CUST_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_basic);
+ break;
+ case LSM_TOPOLOGY_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_lsm_top);
+ break;
+ case ULP_LSM_TOPOLOGY_ID_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_lsm_top);
+ break;
+ case LSM_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_lsm);
+ break;
+ case ADM_RTAC_INFO_CAL_TYPE:
+ size = 0;
+ break;
+ case VOICE_RTAC_INFO_CAL_TYPE:
+ size = 0;
+ break;
+ case ADM_RTAC_APR_CAL_TYPE:
+ size = 0;
+ break;
+ case ASM_RTAC_APR_CAL_TYPE:
+ size = 0;
+ break;
+ case VOICE_RTAC_APR_CAL_TYPE:
+ size = 0;
+ break;
+ case MAD_CAL_TYPE:
+ size = 0;
+ break;
+ case ULP_AFE_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_afe);
+ break;
+ case ULP_LSM_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_lsm);
+ break;
+ case DTS_EAGLE_CAL_TYPE:
+ size = 0;
+ break;
+ case AUDIO_CORE_METAINFO_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_metainfo);
+ break;
+ case SRS_TRUMEDIA_CAL_TYPE:
+ size = 0;
+ break;
+ default:
+ pr_err("%s:Invalid cal type %d!",
+ __func__, cal_type);
+ }
+ return size;
+}
+
+int32_t cal_utils_get_cal_type_version(void *cal_type_data)
+{
+ struct audio_cal_type_basic *data = NULL;
+
+ data = (struct audio_cal_type_basic *)cal_type_data;
+
+ return data->cal_hdr.version;
+}
+
+static struct cal_type_data *create_cal_type_data(
+ struct cal_type_info *info)
+{
+ struct cal_type_data *cal_type = NULL;
+
+ if ((info->reg.cal_type < 0) ||
+ (info->reg.cal_type >= MAX_CAL_TYPES)) {
+ pr_err("%s: cal type %d is Invalid!\n",
+ __func__, info->reg.cal_type);
+ goto done;
+ }
+
+ if (info->cal_util_callbacks.match_block == NULL) {
+ pr_err("%s: cal type %d no method to match blocks!\n",
+ __func__, info->reg.cal_type);
+ goto done;
+ }
+
+ cal_type = kmalloc(sizeof(*cal_type), GFP_KERNEL);
+ if (cal_type == NULL)
+ goto done;
+
+ INIT_LIST_HEAD(&cal_type->cal_blocks);
+ mutex_init(&cal_type->lock);
+ memcpy(&cal_type->info, info,
+ sizeof(cal_type->info));
+done:
+ return cal_type;
+}
+
+int cal_utils_create_cal_types(int num_cal_types,
+ struct cal_type_data **cal_type,
+ struct cal_type_info *info)
+{
+ int ret = 0;
+ int i;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type == NULL) {
+ pr_err("%s: cal_type is NULL!\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ } else if (info == NULL) {
+ pr_err("%s: info is NULL!\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ } else if ((num_cal_types <= 0) ||
+ (num_cal_types > MAX_CAL_TYPES)) {
+ pr_err("%s: num_cal_types of %d is Invalid!\n",
+ __func__, num_cal_types);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ for (i = 0; i < num_cal_types; i++) {
+ if ((info[i].reg.cal_type < 0) ||
+ (info[i].reg.cal_type >= MAX_CAL_TYPES)) {
+ pr_err("%s: cal type %d at index %d is Invalid!\n",
+ __func__, info[i].reg.cal_type, i);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cal_type[i] = create_cal_type_data(&info[i]);
+ if (cal_type[i] == NULL) {
+ pr_err("%s: Could not allocate cal_type of index %d!\n",
+ __func__, i);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = audio_cal_register(1, &info[i].reg);
+ if (ret < 0) {
+ pr_err("%s: audio_cal_register failed, ret = %d!\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto done;
+ }
+ pr_debug("%s: cal type %d at index %d!\n",
+ __func__, info[i].reg.cal_type, i);
+ }
+done:
+ return ret;
+}
+
+static void delete_cal_block(struct cal_block_data *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL)
+ goto done;
+
+ list_del(&cal_block->list);
+ kfree(cal_block->client_info);
+ cal_block->client_info = NULL;
+ kfree(cal_block->cal_info);
+ cal_block->cal_info = NULL;
+ if (cal_block->map_data.ion_client != NULL) {
+ msm_audio_ion_free(cal_block->map_data.ion_client,
+ cal_block->map_data.ion_handle);
+ cal_block->map_data.ion_client = NULL;
+ cal_block->map_data.ion_handle = NULL;
+ }
+ kfree(cal_block);
+done:
+ return;
+}
+
+static void destroy_all_cal_blocks(struct cal_type_data *cal_type)
+{
+ int ret = 0;
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block;
+
+ list_for_each_safe(ptr, next,
+ &cal_type->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ ret = unmap_memory(cal_type, cal_block);
+ if (ret < 0) {
+ pr_err("%s: unmap_memory failed, cal type %d, ret = %d!\n",
+ __func__,
+ cal_type->info.reg.cal_type,
+ ret);
+ }
+ delete_cal_block(cal_block);
+ cal_block = NULL;
+ }
+}
+
+static void destroy_cal_type_data(struct cal_type_data *cal_type)
+{
+ if (cal_type == NULL)
+ goto done;
+
+ destroy_all_cal_blocks(cal_type);
+ list_del(&cal_type->cal_blocks);
+ kfree(cal_type);
+done:
+ return;
+}
+
+void cal_utils_destroy_cal_types(int num_cal_types,
+ struct cal_type_data **cal_type)
+{
+ int i;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type == NULL) {
+ pr_err("%s: cal_type is NULL!\n", __func__);
+ goto done;
+ } else if ((num_cal_types <= 0) ||
+ (num_cal_types > MAX_CAL_TYPES)) {
+ pr_err("%s: num_cal_types of %d is Invalid!\n",
+ __func__, num_cal_types);
+ goto done;
+ }
+
+ for (i = 0; i < num_cal_types; i++) {
+ audio_cal_deregister(1, &cal_type[i]->info.reg);
+ destroy_cal_type_data(cal_type[i]);
+ cal_type[i] = NULL;
+ }
+done:
+ return;
+}
+
+struct cal_block_data *cal_utils_get_only_cal_block(
+ struct cal_type_data *cal_type)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+
+ if (cal_type == NULL)
+ goto done;
+
+ list_for_each_safe(ptr, next,
+ &cal_type->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+ break;
+ }
+done:
+ return cal_block;
+}
+
+bool cal_utils_match_buf_num(struct cal_block_data *cal_block,
+ void *user_data)
+{
+ bool ret = false;
+ struct audio_cal_type_basic *data = user_data;
+
+ if (cal_block->buffer_number == data->cal_hdr.buffer_number)
+ ret = true;
+
+ return ret;
+}
+
+static struct cal_block_data *get_matching_cal_block(
+ struct cal_type_data *cal_type,
+ void *data)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+
+ list_for_each_safe(ptr, next,
+ &cal_type->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ if (cal_type->info.cal_util_callbacks.
+ match_block(cal_block, data))
+ return cal_block;
+ }
+
+ return NULL;
+}
+
+static int cal_block_ion_alloc(struct cal_block_data *cal_block)
+{
+ int ret = 0;
+
+ if (cal_block == NULL) {
+ pr_err("%s: cal_block is NULL!\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_audio_ion_import("audio_cal_client",
+ &cal_block->map_data.ion_client,
+ &cal_block->map_data.ion_handle,
+ cal_block->map_data.ion_map_handle,
+ NULL, 0,
+ &cal_block->cal_data.paddr,
+ &cal_block->map_data.map_size,
+ &cal_block->cal_data.kvaddr);
+ if (ret) {
+ pr_err("%s: audio ION import failed, rc = %d\n",
+ __func__, ret);
+ ret = -ENOMEM;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static struct cal_block_data *create_cal_block(struct cal_type_data *cal_type,
+ struct audio_cal_type_basic *basic_cal,
+ size_t client_info_size, void *client_info)
+{
+ struct cal_block_data *cal_block = NULL;
+
+ if (cal_type == NULL) {
+ pr_err("%s: cal_type is NULL!\n", __func__);
+ goto done;
+ } else if (basic_cal == NULL) {
+ pr_err("%s: basic_cal is NULL!\n", __func__);
+ goto done;
+ }
+
+ cal_block = kzalloc(sizeof(*cal_block),
+ GFP_KERNEL);
+ if (cal_block == NULL)
+ goto done;
+
+ INIT_LIST_HEAD(&cal_block->list);
+ list_add_tail(&cal_block->list, &cal_type->cal_blocks);
+
+ cal_block->map_data.ion_map_handle = basic_cal->cal_data.mem_handle;
+ if (basic_cal->cal_data.mem_handle > 0) {
+ if (cal_block_ion_alloc(cal_block)) {
+ pr_err("%s: cal_block_ion_alloc failed!\n",
+ __func__);
+ goto err;
+ }
+ }
+ if (client_info_size > 0) {
+ cal_block->client_info_size = client_info_size;
+ cal_block->client_info = kmalloc(client_info_size, GFP_KERNEL);
+ if (cal_block->client_info == NULL) {
+ pr_err("%s: could not allocats client_info!\n",
+ __func__);
+ goto err;
+ }
+ if (client_info != NULL)
+ memcpy(cal_block->client_info, client_info,
+ client_info_size);
+ }
+
+ cal_block->cal_info = kzalloc(
+ get_cal_info_size(cal_type->info.reg.cal_type),
+ GFP_KERNEL);
+ if (cal_block->cal_info == NULL) {
+ pr_err("%s: could not allocats cal_info!\n",
+ __func__);
+ goto err;
+ }
+ cal_block->buffer_number = basic_cal->cal_hdr.buffer_number;
+ pr_debug("%s: created block for cal type %d, buf num %d, map handle %d, map size %zd paddr 0x%pK!\n",
+ __func__, cal_type->info.reg.cal_type,
+ cal_block->buffer_number,
+ cal_block->map_data.ion_map_handle,
+ cal_block->map_data.map_size,
+ &cal_block->cal_data.paddr);
+done:
+ return cal_block;
+err:
+ kfree(cal_block);
+ cal_block = NULL;
+ return cal_block;
+}
+
+void cal_utils_clear_cal_block_q6maps(int num_cal_types,
+ struct cal_type_data **cal_type)
+{
+ int i = 0;
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type == NULL) {
+ pr_err("%s: cal_type is NULL!\n", __func__);
+ goto done;
+ } else if ((num_cal_types <= 0) ||
+ (num_cal_types > MAX_CAL_TYPES)) {
+ pr_err("%s: num_cal_types of %d is Invalid!\n",
+ __func__, num_cal_types);
+ goto done;
+ }
+
+ for (; i < num_cal_types; i++) {
+ if (cal_type[i] == NULL)
+ continue;
+
+ mutex_lock(&cal_type[i]->lock);
+ list_for_each_safe(ptr, next,
+ &cal_type[i]->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ cal_block->map_data.q6map_handle = 0;
+ }
+ mutex_unlock(&cal_type[i]->lock);
+ }
+done:
+ return;
+}
+
+
+
+static int realloc_memory(struct cal_block_data *cal_block)
+{
+ int ret = 0;
+
+ msm_audio_ion_free(cal_block->map_data.ion_client,
+ cal_block->map_data.ion_handle);
+ cal_block->map_data.ion_client = NULL;
+ cal_block->map_data.ion_handle = NULL;
+ cal_block->cal_data.size = 0;
+
+ ret = cal_block_ion_alloc(cal_block);
+ if (ret < 0)
+ pr_err("%s: realloc_memory failed!\n",
+ __func__);
+ return ret;
+}
+
+static int map_memory(struct cal_type_data *cal_type,
+ struct cal_block_data *cal_block)
+{
+ int ret = 0;
+
+
+ if (cal_type->info.cal_util_callbacks.map_cal != NULL) {
+ if ((cal_block->map_data.ion_map_handle < 0) ||
+ (cal_block->map_data.map_size <= 0) ||
+ (cal_block->map_data.q6map_handle != 0)) {
+ goto done;
+ }
+
+ pr_debug("%s: cal type %d call map\n",
+ __func__, cal_type->info.reg.cal_type);
+ ret = cal_type->info.cal_util_callbacks.
+ map_cal(cal_type->info.reg.cal_type, cal_block);
+ if (ret < 0) {
+ pr_err("%s: map_cal failed, cal type %d, ret = %d!\n",
+ __func__, cal_type->info.reg.cal_type,
+ ret);
+ goto done;
+ }
+ }
+done:
+ return ret;
+}
+
+static int unmap_memory(struct cal_type_data *cal_type,
+ struct cal_block_data *cal_block)
+{
+ int ret = 0;
+
+ if (cal_type->info.cal_util_callbacks.unmap_cal != NULL) {
+ if ((cal_block->map_data.ion_map_handle < 0) ||
+ (cal_block->map_data.map_size <= 0) ||
+ (cal_block->map_data.q6map_handle == 0)) {
+ goto done;
+ }
+ pr_debug("%s: cal type %d call unmap\n",
+ __func__, cal_type->info.reg.cal_type);
+ ret = cal_type->info.cal_util_callbacks.
+ unmap_cal(cal_type->info.reg.cal_type, cal_block);
+ if (ret < 0) {
+ pr_err("%s: unmap_cal failed, cal type %d, ret = %d!\n",
+ __func__, cal_type->info.reg.cal_type,
+ ret);
+ goto done;
+ }
+ }
+done:
+ return ret;
+}
+
+int cal_utils_alloc_cal(size_t data_size, void *data,
+ struct cal_type_data *cal_type,
+ size_t client_info_size, void *client_info)
+{
+ int ret = 0;
+ struct cal_block_data *cal_block;
+ struct audio_cal_type_alloc *alloc_data = data;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type == NULL) {
+ pr_err("%s: cal_type is NULL!\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data_size < sizeof(struct audio_cal_type_alloc)) {
+ pr_err("%s: data_size of %zd does not equal alloc struct size of %zd!\n",
+ __func__, data_size,
+ sizeof(struct audio_cal_type_alloc));
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((client_info_size > 0) && (client_info == NULL)) {
+ pr_err("%s: User info pointer is NULL but size is %zd!\n",
+ __func__, client_info_size);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (alloc_data->cal_data.mem_handle < 0) {
+ pr_err("%s: mem_handle %d invalid!\n",
+ __func__, alloc_data->cal_data.mem_handle);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&cal_type->lock);
+
+ cal_block = get_matching_cal_block(cal_type,
+ data);
+ if (cal_block != NULL) {
+ ret = unmap_memory(cal_type, cal_block);
+ if (ret < 0)
+ goto err;
+ ret = realloc_memory(cal_block);
+ if (ret < 0)
+ goto err;
+ } else {
+ cal_block = create_cal_block(cal_type,
+ (struct audio_cal_type_basic *)alloc_data,
+ client_info_size, client_info);
+ if (cal_block == NULL) {
+ pr_err("%s: create_cal_block failed for %d!\n",
+ __func__, alloc_data->cal_data.mem_handle);
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ ret = map_memory(cal_type, cal_block);
+ if (ret < 0)
+ goto err;
+err:
+ mutex_unlock(&cal_type->lock);
+done:
+ return ret;
+}
+
+int cal_utils_dealloc_cal(size_t data_size, void *data,
+ struct cal_type_data *cal_type)
+{
+ int ret = 0;
+ struct cal_block_data *cal_block;
+ struct audio_cal_type_dealloc *dealloc_data = data;
+
+ pr_debug("%s\n", __func__);
+
+
+ if (cal_type == NULL) {
+ pr_err("%s: cal_type is NULL!\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (data_size < sizeof(struct audio_cal_type_dealloc)) {
+ pr_err("%s: data_size of %zd does not equal struct size of %zd!\n",
+ __func__, data_size,
+ sizeof(struct audio_cal_type_dealloc));
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((dealloc_data->cal_data.mem_handle == -1) &&
+ (dealloc_data->cal_hdr.buffer_number == ALL_CAL_BLOCKS)) {
+ destroy_all_cal_blocks(cal_type);
+ goto done;
+ }
+
+ if (dealloc_data->cal_data.mem_handle < 0) {
+ pr_err("%s: mem_handle %d invalid!\n",
+ __func__, dealloc_data->cal_data.mem_handle);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&cal_type->lock);
+ cal_block = get_matching_cal_block(
+ cal_type,
+ data);
+ if (cal_block == NULL) {
+ pr_err("%s: allocation does not exist for %d!\n",
+ __func__, dealloc_data->cal_data.mem_handle);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = unmap_memory(cal_type, cal_block);
+ if (ret < 0)
+ goto err;
+
+ delete_cal_block(cal_block);
+err:
+ mutex_unlock(&cal_type->lock);
+done:
+ return ret;
+}
+
+int cal_utils_set_cal(size_t data_size, void *data,
+ struct cal_type_data *cal_type,
+ size_t client_info_size, void *client_info)
+{
+ int ret = 0;
+ struct cal_block_data *cal_block;
+ struct audio_cal_type_basic *basic_data = data;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type == NULL) {
+ pr_err("%s: cal_type is NULL!\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((client_info_size > 0) && (client_info == NULL)) {
+ pr_err("%s: User info pointer is NULL but size is %zd!\n",
+ __func__, client_info_size);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data_size > get_user_cal_type_size(
+ cal_type->info.reg.cal_type)) || (data_size < 0)) {
+ pr_err("%s: cal_type %d, data_size of %zd is invalid, expecting %zd!\n",
+ __func__, cal_type->info.reg.cal_type, data_size,
+ get_user_cal_type_size(cal_type->info.reg.cal_type));
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&cal_type->lock);
+ cal_block = get_matching_cal_block(
+ cal_type,
+ data);
+ if (cal_block == NULL) {
+ if (basic_data->cal_data.mem_handle > 0) {
+ pr_err("%s: allocation does not exist for %d!\n",
+ __func__, basic_data->cal_data.mem_handle);
+ ret = -EINVAL;
+ goto err;
+ } else {
+ cal_block = create_cal_block(
+ cal_type,
+ basic_data,
+ client_info_size, client_info);
+ if (cal_block == NULL) {
+ pr_err("%s: create_cal_block failed for cal type %d!\n",
+ __func__,
+ cal_type->info.reg.cal_type);
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+ }
+
+ ret = map_memory(cal_type, cal_block);
+ if (ret < 0)
+ goto err;
+
+ cal_block->cal_data.size = basic_data->cal_data.cal_size;
+
+ if (client_info_size > 0) {
+ memcpy(cal_block->client_info,
+ client_info,
+ client_info_size);
+ }
+
+ memcpy(cal_block->cal_info,
+ ((uint8_t *)data + sizeof(struct audio_cal_type_basic)),
+ data_size - sizeof(struct audio_cal_type_basic));
+
+err:
+ mutex_unlock(&cal_type->lock);
+done:
+ return ret;
+}
diff --git a/sound/soc/msm/qdsp6v2/audio_calibration.c b/sound/soc/msm/qdsp6v2/audio_calibration.c
new file mode 100644
index 0000000..808a0e4
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/audio_calibration.c
@@ -0,0 +1,636 @@
+/* Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+#include <linux/msm_audio_ion.h>
+#include <sound/audio_calibration.h>
+#include <sound/audio_cal_utils.h>
+
+struct audio_cal_client_info {
+ struct list_head list;
+ struct audio_cal_callbacks *callbacks;
+};
+
+struct audio_cal_info {
+ struct mutex common_lock;
+ struct mutex cal_mutex[MAX_CAL_TYPES];
+ struct list_head client_info[MAX_CAL_TYPES];
+ int ref_count;
+};
+
+static struct audio_cal_info audio_cal;
+
+
+static bool callbacks_are_equal(struct audio_cal_callbacks *callback1,
+ struct audio_cal_callbacks *callback2)
+{
+ bool ret = true;
+ struct audio_cal_callbacks *call1 = callback1;
+ struct audio_cal_callbacks *call2 = callback2;
+
+ pr_debug("%s\n", __func__);
+
+ if ((call1 == NULL) && (call2 == NULL))
+ ret = true;
+ else if ((call1 == NULL) || (call2 == NULL))
+ ret = false;
+ else if ((call1->alloc != call2->alloc) ||
+ (call1->dealloc != call2->dealloc) ||
+ (call1->pre_cal != call2->pre_cal) ||
+ (call1->set_cal != call2->set_cal) ||
+ (call1->get_cal != call2->get_cal) ||
+ (call1->post_cal != call2->post_cal))
+ ret = false;
+ return ret;
+}
+
+int audio_cal_deregister(int num_cal_types,
+ struct audio_cal_reg *reg_data)
+{
+ int ret = 0;
+ int i = 0;
+ struct list_head *ptr, *next;
+ struct audio_cal_client_info *client_info_node = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ if (reg_data == NULL) {
+ pr_err("%s: reg_data is NULL!\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ } else if ((num_cal_types <= 0) ||
+ (num_cal_types > MAX_CAL_TYPES)) {
+ pr_err("%s: num_cal_types of %d is Invalid!\n",
+ __func__, num_cal_types);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ for (; i < num_cal_types; i++) {
+ if ((reg_data[i].cal_type < 0) ||
+ (reg_data[i].cal_type >= MAX_CAL_TYPES)) {
+ pr_err("%s: cal type %d at index %d is Invalid!\n",
+ __func__, reg_data[i].cal_type, i);
+ ret = -EINVAL;
+ continue;
+ }
+
+ mutex_lock(&audio_cal.cal_mutex[reg_data[i].cal_type]);
+ list_for_each_safe(ptr, next,
+ &audio_cal.client_info[reg_data[i].cal_type]) {
+
+ client_info_node = list_entry(ptr,
+ struct audio_cal_client_info, list);
+ if (callbacks_are_equal(client_info_node->callbacks,
+ ®_data[i].callbacks)) {
+ list_del(&client_info_node->list);
+ kfree(client_info_node->callbacks);
+ client_info_node->callbacks = NULL;
+ kfree(client_info_node);
+ client_info_node = NULL;
+ break;
+ }
+ }
+ mutex_unlock(&audio_cal.cal_mutex[reg_data[i].cal_type]);
+ }
+done:
+ return ret;
+}
+
+
+int audio_cal_register(int num_cal_types,
+ struct audio_cal_reg *reg_data)
+{
+ int ret = 0;
+ int i = 0;
+ struct audio_cal_client_info *client_info_node = NULL;
+ struct audio_cal_callbacks *callback_node = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ if (reg_data == NULL) {
+ pr_err("%s: callbacks are NULL!\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ } else if ((num_cal_types <= 0) ||
+ (num_cal_types > MAX_CAL_TYPES)) {
+ pr_err("%s: num_cal_types of %d is Invalid!\n",
+ __func__, num_cal_types);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ for (; i < num_cal_types; i++) {
+ if ((reg_data[i].cal_type < 0) ||
+ (reg_data[i].cal_type >= MAX_CAL_TYPES)) {
+ pr_err("%s: cal type %d at index %d is Invalid!\n",
+ __func__, reg_data[i].cal_type, i);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ client_info_node = kmalloc(sizeof(*client_info_node),
+ GFP_KERNEL);
+ if (client_info_node == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ INIT_LIST_HEAD(&client_info_node->list);
+
+ callback_node = kmalloc(sizeof(*callback_node),
+ GFP_KERNEL);
+ if (callback_node == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(callback_node, ®_data[i].callbacks,
+ sizeof(*callback_node));
+ client_info_node->callbacks = callback_node;
+
+ mutex_lock(&audio_cal.cal_mutex[reg_data[i].cal_type]);
+ list_add_tail(&client_info_node->list,
+ &audio_cal.client_info[reg_data[i].cal_type]);
+ mutex_unlock(&audio_cal.cal_mutex[reg_data[i].cal_type]);
+ }
+done:
+ return ret;
+err:
+ audio_cal_deregister(num_cal_types, reg_data);
+ return ret;
+}
+
+static int call_allocs(int32_t cal_type,
+ size_t cal_type_size, void *data)
+{
+ int ret = 0;
+ int ret2 = 0;
+ struct list_head *ptr, *next;
+ struct audio_cal_client_info *client_info_node = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ list_for_each_safe(ptr, next,
+ &audio_cal.client_info[cal_type]) {
+
+ client_info_node = list_entry(ptr,
+ struct audio_cal_client_info, list);
+
+ if (client_info_node->callbacks->alloc == NULL)
+ continue;
+
+ ret2 = client_info_node->callbacks->
+ alloc(cal_type, cal_type_size, data);
+ if (ret2 < 0) {
+ pr_err("%s: alloc failed!\n", __func__);
+ ret = ret2;
+ }
+ }
+ return ret;
+}
+
+static int call_deallocs(int32_t cal_type,
+ size_t cal_type_size, void *data)
+{
+ int ret = 0;
+ int ret2 = 0;
+ struct list_head *ptr, *next;
+ struct audio_cal_client_info *client_info_node = NULL;
+
+ pr_debug("%s cal type %d\n", __func__, cal_type);
+
+ list_for_each_safe(ptr, next,
+ &audio_cal.client_info[cal_type]) {
+
+ client_info_node = list_entry(ptr,
+ struct audio_cal_client_info, list);
+
+ if (client_info_node->callbacks->dealloc == NULL)
+ continue;
+
+ ret2 = client_info_node->callbacks->
+ dealloc(cal_type, cal_type_size, data);
+ if (ret2 < 0) {
+ pr_err("%s: dealloc failed!\n", __func__);
+ ret = ret2;
+ }
+ }
+ return ret;
+}
+
+static int call_pre_cals(int32_t cal_type,
+ size_t cal_type_size, void *data)
+{
+ int ret = 0;
+ int ret2 = 0;
+ struct list_head *ptr, *next;
+ struct audio_cal_client_info *client_info_node = NULL;
+
+ pr_debug("%s cal type %d\n", __func__, cal_type);
+
+ list_for_each_safe(ptr, next,
+ &audio_cal.client_info[cal_type]) {
+
+ client_info_node = list_entry(ptr,
+ struct audio_cal_client_info, list);
+
+ if (client_info_node->callbacks->pre_cal == NULL)
+ continue;
+
+ ret2 = client_info_node->callbacks->
+ pre_cal(cal_type, cal_type_size, data);
+ if (ret2 < 0) {
+ pr_err("%s: pre_cal failed!\n", __func__);
+ ret = ret2;
+ }
+ }
+ return ret;
+}
+
+static int call_post_cals(int32_t cal_type,
+ size_t cal_type_size, void *data)
+{
+ int ret = 0;
+ int ret2 = 0;
+ struct list_head *ptr, *next;
+ struct audio_cal_client_info *client_info_node = NULL;
+
+ pr_debug("%s cal type %d\n", __func__, cal_type);
+
+ list_for_each_safe(ptr, next,
+ &audio_cal.client_info[cal_type]) {
+
+ client_info_node = list_entry(ptr,
+ struct audio_cal_client_info, list);
+
+ if (client_info_node->callbacks->post_cal == NULL)
+ continue;
+
+ ret2 = client_info_node->callbacks->
+ post_cal(cal_type, cal_type_size, data);
+ if (ret2 < 0) {
+ pr_err("%s: post_cal failed!\n", __func__);
+ ret = ret2;
+ }
+ }
+ return ret;
+}
+
+static int call_set_cals(int32_t cal_type,
+ size_t cal_type_size, void *data)
+{
+ int ret = 0;
+ int ret2 = 0;
+ struct list_head *ptr, *next;
+ struct audio_cal_client_info *client_info_node = NULL;
+
+ pr_debug("%s cal type %d\n", __func__, cal_type);
+
+ list_for_each_safe(ptr, next,
+ &audio_cal.client_info[cal_type]) {
+
+ client_info_node = list_entry(ptr,
+ struct audio_cal_client_info, list);
+
+ if (client_info_node->callbacks->set_cal == NULL)
+ continue;
+
+ ret2 = client_info_node->callbacks->
+ set_cal(cal_type, cal_type_size, data);
+ if (ret2 < 0) {
+ pr_err("%s: set_cal failed!\n", __func__);
+ ret = ret2;
+ }
+ }
+ return ret;
+}
+
+static int call_get_cals(int32_t cal_type,
+ size_t cal_type_size, void *data)
+{
+ int ret = 0;
+ int ret2 = 0;
+ struct list_head *ptr, *next;
+ struct audio_cal_client_info *client_info_node = NULL;
+
+ pr_debug("%s cal type %d\n", __func__, cal_type);
+
+ list_for_each_safe(ptr, next,
+ &audio_cal.client_info[cal_type]) {
+
+ client_info_node = list_entry(ptr,
+ struct audio_cal_client_info, list);
+
+ if (client_info_node->callbacks->get_cal == NULL)
+ continue;
+
+ ret2 = client_info_node->callbacks->
+ get_cal(cal_type, cal_type_size, data);
+ if (ret2 < 0) {
+ pr_err("%s: get_cal failed!\n", __func__);
+ ret = ret2;
+ }
+ }
+ return ret;
+}
+
+static int audio_cal_open(struct inode *inode, struct file *f)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&audio_cal.common_lock);
+ audio_cal.ref_count++;
+ mutex_unlock(&audio_cal.common_lock);
+
+ return ret;
+}
+
+static void dealloc_all_clients(void)
+{
+ int i = 0;
+ struct audio_cal_type_dealloc dealloc_data;
+
+ pr_debug("%s\n", __func__);
+
+ dealloc_data.cal_hdr.version = VERSION_0_0;
+ dealloc_data.cal_hdr.buffer_number = ALL_CAL_BLOCKS;
+ dealloc_data.cal_data.mem_handle = -1;
+
+ for (; i < MAX_CAL_TYPES; i++)
+ call_deallocs(i, sizeof(dealloc_data), &dealloc_data);
+}
+
+static int audio_cal_release(struct inode *inode, struct file *f)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&audio_cal.common_lock);
+ audio_cal.ref_count--;
+ if (audio_cal.ref_count <= 0) {
+ audio_cal.ref_count = 0;
+ dealloc_all_clients();
+ }
+ mutex_unlock(&audio_cal.common_lock);
+
+ return ret;
+}
+
+static long audio_cal_shared_ioctl(struct file *file, unsigned int cmd,
+ void __user *arg)
+{
+ int ret = 0;
+ int32_t size;
+ struct audio_cal_basic *data = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ switch (cmd) {
+ case AUDIO_ALLOCATE_CALIBRATION:
+ case AUDIO_DEALLOCATE_CALIBRATION:
+ case AUDIO_PREPARE_CALIBRATION:
+ case AUDIO_SET_CALIBRATION:
+ case AUDIO_GET_CALIBRATION:
+ case AUDIO_POST_CALIBRATION:
+ break;
+ default:
+ pr_err("%s: ioctl not found!\n", __func__);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(&size, (void *)arg, sizeof(size))) {
+ pr_err("%s: Could not copy size value from user\n", __func__);
+ ret = -EFAULT;
+ goto done;
+ } else if ((size < sizeof(struct audio_cal_basic))
+ || (size > MAX_IOCTL_CMD_SIZE)) {
+ pr_err("%s: Invalid size sent to driver: %d, max size is %d, min size is %zd\n",
+ __func__, size, MAX_IOCTL_CMD_SIZE,
+ sizeof(struct audio_cal_basic));
+ ret = -EINVAL;
+ goto done;
+ }
+
+ data = kmalloc(size, GFP_KERNEL);
+ if (data == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ } else if (copy_from_user(data, (void *)arg, size)) {
+ pr_err("%s: Could not copy data from user\n",
+ __func__);
+ ret = -EFAULT;
+ goto done;
+ } else if ((data->hdr.cal_type < 0) ||
+ (data->hdr.cal_type >= MAX_CAL_TYPES)) {
+ pr_err("%s: cal type %d is Invalid!\n",
+ __func__, data->hdr.cal_type);
+ ret = -EINVAL;
+ goto done;
+ } else if ((data->hdr.cal_type_size <
+ sizeof(struct audio_cal_type_basic)) ||
+ (data->hdr.cal_type_size >
+ get_user_cal_type_size(data->hdr.cal_type))) {
+ pr_err("%s: cal type size %d is Invalid! Max is %zd!\n",
+ __func__, data->hdr.cal_type_size,
+ get_user_cal_type_size(data->hdr.cal_type));
+ ret = -EINVAL;
+ goto done;
+ } else if (data->cal_type.cal_hdr.buffer_number < 0) {
+ pr_err("%s: cal type %d Invalid buffer number %d!\n",
+ __func__, data->hdr.cal_type,
+ data->cal_type.cal_hdr.buffer_number);
+ ret = -EINVAL;
+ goto done;
+ }
+
+
+ mutex_lock(&audio_cal.cal_mutex[data->hdr.cal_type]);
+
+ switch (cmd) {
+ case AUDIO_ALLOCATE_CALIBRATION:
+ ret = call_allocs(data->hdr.cal_type,
+ data->hdr.cal_type_size, &data->cal_type);
+ break;
+ case AUDIO_DEALLOCATE_CALIBRATION:
+ ret = call_deallocs(data->hdr.cal_type,
+ data->hdr.cal_type_size, &data->cal_type);
+ break;
+ case AUDIO_PREPARE_CALIBRATION:
+ ret = call_pre_cals(data->hdr.cal_type,
+ data->hdr.cal_type_size, &data->cal_type);
+ break;
+ case AUDIO_SET_CALIBRATION:
+ ret = call_set_cals(data->hdr.cal_type,
+ data->hdr.cal_type_size, &data->cal_type);
+ break;
+ case AUDIO_GET_CALIBRATION:
+ ret = call_get_cals(data->hdr.cal_type,
+ data->hdr.cal_type_size, &data->cal_type);
+ break;
+ case AUDIO_POST_CALIBRATION:
+ ret = call_post_cals(data->hdr.cal_type,
+ data->hdr.cal_type_size, &data->cal_type);
+ break;
+ }
+
+ if (cmd == AUDIO_GET_CALIBRATION) {
+ if (data->hdr.cal_type_size == 0)
+ goto unlock;
+ if (data == NULL)
+ goto unlock;
+ if ((sizeof(data->hdr) + data->hdr.cal_type_size) > size) {
+ pr_err("%s: header size %zd plus cal type size %d are greater than data buffer size %d\n",
+ __func__, sizeof(data->hdr),
+ data->hdr.cal_type_size, size);
+ ret = -EFAULT;
+ goto unlock;
+ } else if (copy_to_user((void *)arg, data,
+ sizeof(data->hdr) + data->hdr.cal_type_size)) {
+ pr_err("%s: Could not copy cal type to user\n",
+ __func__);
+ ret = -EFAULT;
+ goto unlock;
+ }
+ }
+
+unlock:
+ mutex_unlock(&audio_cal.cal_mutex[data->hdr.cal_type]);
+done:
+ kfree(data);
+ return ret;
+}
+
+static long audio_cal_ioctl(struct file *f,
+ unsigned int cmd, unsigned long arg)
+{
+ return audio_cal_shared_ioctl(f, cmd, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+
+#define AUDIO_ALLOCATE_CALIBRATION32 _IOWR(CAL_IOCTL_MAGIC, \
+ 200, compat_uptr_t)
+#define AUDIO_DEALLOCATE_CALIBRATION32 _IOWR(CAL_IOCTL_MAGIC, \
+ 201, compat_uptr_t)
+#define AUDIO_PREPARE_CALIBRATION32 _IOWR(CAL_IOCTL_MAGIC, \
+ 202, compat_uptr_t)
+#define AUDIO_SET_CALIBRATION32 _IOWR(CAL_IOCTL_MAGIC, \
+ 203, compat_uptr_t)
+#define AUDIO_GET_CALIBRATION32 _IOWR(CAL_IOCTL_MAGIC, \
+ 204, compat_uptr_t)
+#define AUDIO_POST_CALIBRATION32 _IOWR(CAL_IOCTL_MAGIC, \
+ 205, compat_uptr_t)
+
+static long audio_cal_compat_ioctl(struct file *f,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int cmd64;
+ int ret = 0;
+
+ switch (cmd) {
+ case AUDIO_ALLOCATE_CALIBRATION32:
+ cmd64 = AUDIO_ALLOCATE_CALIBRATION;
+ break;
+ case AUDIO_DEALLOCATE_CALIBRATION32:
+ cmd64 = AUDIO_DEALLOCATE_CALIBRATION;
+ break;
+ case AUDIO_PREPARE_CALIBRATION32:
+ cmd64 = AUDIO_PREPARE_CALIBRATION;
+ break;
+ case AUDIO_SET_CALIBRATION32:
+ cmd64 = AUDIO_SET_CALIBRATION;
+ break;
+ case AUDIO_GET_CALIBRATION32:
+ cmd64 = AUDIO_GET_CALIBRATION;
+ break;
+ case AUDIO_POST_CALIBRATION32:
+ cmd64 = AUDIO_POST_CALIBRATION;
+ break;
+ default:
+ pr_err("%s: ioctl not found!\n", __func__);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = audio_cal_shared_ioctl(f, cmd64, compat_ptr(arg));
+done:
+ return ret;
+}
+#endif
+
+static const struct file_operations audio_cal_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_cal_open,
+ .release = audio_cal_release,
+ .unlocked_ioctl = audio_cal_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = audio_cal_compat_ioctl,
+#endif
+};
+
+struct miscdevice audio_cal_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_audio_cal",
+ .fops = &audio_cal_fops,
+};
+
+static int __init audio_cal_init(void)
+{
+ int i = 0;
+
+ pr_debug("%s\n", __func__);
+
+ memset(&audio_cal, 0, sizeof(audio_cal));
+ mutex_init(&audio_cal.common_lock);
+ for (; i < MAX_CAL_TYPES; i++) {
+ INIT_LIST_HEAD(&audio_cal.client_info[i]);
+ mutex_init(&audio_cal.cal_mutex[i]);
+ }
+
+ return misc_register(&audio_cal_misc);
+}
+
+static void __exit audio_cal_exit(void)
+{
+ int i = 0;
+ struct list_head *ptr, *next;
+ struct audio_cal_client_info *client_info_node;
+
+ for (; i < MAX_CAL_TYPES; i++) {
+ list_for_each_safe(ptr, next,
+ &audio_cal.client_info[i]) {
+ client_info_node = list_entry(ptr,
+ struct audio_cal_client_info, list);
+ list_del(&client_info_node->list);
+ kfree(client_info_node->callbacks);
+ client_info_node->callbacks = NULL;
+ kfree(client_info_node);
+ client_info_node = NULL;
+ }
+ }
+}
+
+subsys_initcall(audio_cal_init);
+module_exit(audio_cal_exit);
+
+MODULE_DESCRIPTION("SoC QDSP6v2 Audio Calibration driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/audio_slimslave.c b/sound/soc/msm/qdsp6v2/audio_slimslave.c
new file mode 100644
index 0000000..e9ecfd5
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/audio_slimslave.c
@@ -0,0 +1,177 @@
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <sound/audio_slimslave.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/pm_runtime.h>
+
+static struct slim_device *slim;
+static int vote_count;
+struct mutex suspend_lock;
+bool suspend;
+
+static int audio_slim_open(struct inode *inode, struct file *file)
+{
+ pr_debug("%s:\n", __func__);
+
+ if (vote_count) {
+ pr_debug("%s: unvote: vote_count=%d\n", __func__, vote_count);
+ pm_runtime_mark_last_busy(slim->dev.parent);
+ pm_runtime_put(slim->dev.parent);
+ vote_count--;
+ }
+ return 0;
+};
+
+static int audio_slim_release(struct inode *inode, struct file *file)
+{
+ pr_debug("%s:\n", __func__);
+
+ if (vote_count) {
+ pr_debug("%s: unvote: vote_count=%d\n", __func__, vote_count);
+ pm_runtime_mark_last_busy(slim->dev.parent);
+ pm_runtime_put(slim->dev.parent);
+ vote_count--;
+ } else {
+ pr_debug("%s: vote: vote_count=%d\n", __func__, vote_count);
+ pm_runtime_get_sync(slim->dev.parent);
+ vote_count++;
+ }
+ return 0;
+};
+
+static long audio_slim_ioctl(struct file *file, unsigned int cmd,
+ unsigned long u_arg)
+{
+ switch (cmd) {
+ case AUDIO_SLIMSLAVE_VOTE:
+ mutex_lock(&suspend_lock);
+ if (!vote_count && !suspend) {
+ pr_debug("%s:AUDIO_SLIMSLAVE_VOTE\n", __func__);
+ pm_runtime_get_sync(slim->dev.parent);
+ vote_count++;
+ } else {
+ pr_err("%s:Invalid vote: vote_count=%d suspend=%d\n",
+ __func__, vote_count, suspend);
+ }
+ mutex_unlock(&suspend_lock);
+ break;
+ case AUDIO_SLIMSLAVE_UNVOTE:
+ mutex_lock(&suspend_lock);
+ if (vote_count && !suspend) {
+ pr_debug("%s:AUDIO_SLIMSLAVE_UNVOTE\n", __func__);
+ pm_runtime_mark_last_busy(slim->dev.parent);
+ pm_runtime_put(slim->dev.parent);
+ vote_count--;
+ } else {
+ pr_err("%s:Invalid unvote: vote_count=%d suspend=%d\n",
+ __func__, vote_count, suspend);
+ }
+ mutex_unlock(&suspend_lock);
+ break;
+ default:
+ pr_debug("%s: Invalid ioctl cmd: %d\n", __func__, cmd);
+ break;
+ }
+ return 0;
+}
+
+static const struct file_operations audio_slimslave_fops = {
+ .open = audio_slim_open,
+ .unlocked_ioctl = audio_slim_ioctl,
+ .release = audio_slim_release,
+};
+
+struct miscdevice audio_slimslave_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = AUDIO_SLIMSLAVE_IOCTL_NAME,
+ .fops = &audio_slimslave_fops,
+};
+
+static int audio_slimslave_probe(struct slim_device *audio_slim)
+{
+ pr_debug("%s:\n", __func__);
+
+ mutex_init(&suspend_lock);
+ suspend = false;
+ slim = audio_slim;
+ misc_register(&audio_slimslave_misc);
+ return 0;
+}
+
+static int audio_slimslave_remove(struct slim_device *audio_slim)
+{
+ pr_debug("%s:\n", __func__);
+
+ misc_deregister(&audio_slimslave_misc);
+ return 0;
+}
+
+static int audio_slimslave_resume(struct slim_device *audio_slim)
+{
+ pr_debug("%s:\n", __func__);
+
+ mutex_lock(&suspend_lock);
+ suspend = false;
+ mutex_unlock(&suspend_lock);
+ return 0;
+}
+
+static int audio_slimslave_suspend(struct slim_device *audio_slim,
+ pm_message_t pmesg)
+{
+ pr_debug("%s:\n", __func__);
+
+ mutex_lock(&suspend_lock);
+ suspend = true;
+ mutex_unlock(&suspend_lock);
+ return 0;
+}
+
+static const struct slim_device_id audio_slimslave_dt_match[] = {
+ {"audio-slimslave", 0},
+ {}
+};
+
+static struct slim_driver audio_slimslave_driver = {
+ .driver = {
+ .name = "audio-slimslave",
+ .owner = THIS_MODULE,
+ },
+ .probe = audio_slimslave_probe,
+ .remove = audio_slimslave_remove,
+ .id_table = audio_slimslave_dt_match,
+ .resume = audio_slimslave_resume,
+ .suspend = audio_slimslave_suspend,
+};
+
+static int __init audio_slimslave_init(void)
+{
+ return slim_driver_register(&audio_slimslave_driver);
+}
+module_init(audio_slimslave_init);
+
+static void __exit audio_slimslave_exit(void)
+{
+
+}
+module_exit(audio_slimslave_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("Audio side Slimbus slave driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
new file mode 100644
index 0000000..225f978
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
@@ -0,0 +1,1399 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/compress_params.h>
+#include <sound/msm-audio-effects-q6-v2.h>
+#include <sound/msm-dts-eagle.h>
+#include <sound/devdep_params.h>
+
+#define MAX_ENABLE_CMD_SIZE 32
+
+#define GET_NEXT(ptr, upper_limit, rc) \
+({ \
+ if (((ptr) + 1) > (upper_limit)) { \
+ pr_err("%s: param list out of boundary\n", __func__); \
+ (rc) = -EINVAL; \
+ } \
+ ((rc) == 0) ? *(ptr)++ : -EINVAL; \
+})
+
+#define CHECK_PARAM_LEN(len, max_len, tag, rc) \
+do { \
+ if ((len) > (max_len)) { \
+ pr_err("%s: params length overflows\n", (tag)); \
+ (rc) = -EINVAL; \
+ } \
+} while (0)
+
+
+bool msm_audio_effects_is_effmodule_supp_in_top(int effect_module,
+ int topology)
+{
+ switch (effect_module) {
+ case VIRTUALIZER_MODULE:
+ case REVERB_MODULE:
+ case BASS_BOOST_MODULE:
+ case PBE_MODULE:
+ case EQ_MODULE:
+ switch (topology) {
+ case ASM_STREAM_POSTPROC_TOPO_ID_SA_PLUS:
+ case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
+ case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
+ return true;
+ default:
+ return false;
+ }
+ case DTS_EAGLE_MODULE:
+ switch (topology) {
+ case ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX:
+ case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
+ case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
+ return true;
+ default:
+ return false;
+ }
+ case SOFT_VOLUME2_MODULE:
+ case DTS_EAGLE_MODULE_ENABLE:
+ switch (topology) {
+ case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
+ case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
+int msm_audio_effects_enable_extn(struct audio_client *ac,
+ struct msm_nt_eff_all_config *effects,
+ bool flag)
+{
+ uint32_t updt_params[MAX_ENABLE_CMD_SIZE] = {0};
+ uint32_t params_length;
+ int rc = 0;
+
+ pr_debug("%s\n", __func__);
+ if (!ac) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params_length = 0;
+ updt_params[0] = AUDPROC_MODULE_ID_VIRTUALIZER;
+ updt_params[1] = AUDPROC_PARAM_ID_ENABLE;
+ updt_params[2] = VIRTUALIZER_ENABLE_PARAM_SZ;
+ updt_params[3] = flag;
+ params_length += COMMAND_PAYLOAD_SZ + VIRTUALIZER_ENABLE_PARAM_SZ;
+ if (effects->virtualizer.enable_flag)
+ q6asm_send_audio_effects_params(ac, (char *)&updt_params[0],
+ params_length);
+ memset(updt_params, 0, MAX_ENABLE_CMD_SIZE);
+ params_length = 0;
+ updt_params[0] = AUDPROC_MODULE_ID_BASS_BOOST;
+ updt_params[1] = AUDPROC_PARAM_ID_ENABLE;
+ updt_params[2] = BASS_BOOST_ENABLE_PARAM_SZ;
+ updt_params[3] = flag;
+ params_length += COMMAND_PAYLOAD_SZ + BASS_BOOST_ENABLE_PARAM_SZ;
+ if (effects->bass_boost.enable_flag)
+ q6asm_send_audio_effects_params(ac, (char *)&updt_params[0],
+ params_length);
+ memset(updt_params, 0, MAX_ENABLE_CMD_SIZE);
+ params_length = 0;
+ updt_params[0] = AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ updt_params[1] = AUDPROC_PARAM_ID_ENABLE;
+ updt_params[2] = EQ_ENABLE_PARAM_SZ;
+ updt_params[3] = flag;
+ params_length += COMMAND_PAYLOAD_SZ + EQ_ENABLE_PARAM_SZ;
+ if (effects->equalizer.enable_flag)
+ q6asm_send_audio_effects_params(ac, (char *)&updt_params[0],
+ params_length);
+ return rc;
+}
+
+int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
+ struct virtualizer_params *virtualizer,
+ long *values)
+{
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
+ int *updt_params, i, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+
+ pr_debug("%s\n", __func__);
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
+ switch (command_id) {
+ case VIRTUALIZER_ENABLE:
+ if (length != 1 || index_offset != 0) {
+ pr_err("VIRT ENABLE:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = virtualizer->enable_flag;
+ virtualizer->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s:VIRT ENABLE prev:%d, new:%d\n", __func__,
+ prev_enable_flag, virtualizer->enable_flag);
+ if (prev_enable_flag != virtualizer->enable_flag) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ VIRTUALIZER_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VIRT ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE;
+ *updt_params++ =
+ VIRTUALIZER_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ virtualizer->enable_flag;
+ }
+ break;
+ case VIRTUALIZER_STRENGTH:
+ if (length != 1 || index_offset != 0) {
+ pr_err("VIRT STRENGTH:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ virtualizer->strength =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: VIRT STRENGTH val: %d\n",
+ __func__, virtualizer->strength);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ VIRTUALIZER_STRENGTH_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VIRT STRENGTH", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH;
+ *updt_params++ =
+ VIRTUALIZER_STRENGTH_PARAM_SZ;
+ *updt_params++ =
+ virtualizer->strength;
+ }
+ break;
+ case VIRTUALIZER_OUT_TYPE:
+ if (length != 1 || index_offset != 0) {
+ pr_err("VIRT OUT_TYPE:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ virtualizer->out_type =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: VIRT OUT_TYPE val:%d\n",
+ __func__, virtualizer->out_type);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ VIRTUALIZER_OUT_TYPE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VIRT OUT_TYPE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE;
+ *updt_params++ =
+ VIRTUALIZER_OUT_TYPE_PARAM_SZ;
+ *updt_params++ =
+ virtualizer->out_type;
+ }
+ break;
+ case VIRTUALIZER_GAIN_ADJUST:
+ if (length != 1 || index_offset != 0) {
+ pr_err("VIRT GAIN_ADJUST: invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ virtualizer->gain_adjust =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: VIRT GAIN_ADJUST val:%d\n",
+ __func__, virtualizer->gain_adjust);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VIRT GAIN_ADJUST", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST;
+ *updt_params++ =
+ VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
+ *updt_params++ =
+ virtualizer->gain_adjust;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+ else
+ pr_debug("%s: did not send pp params\n", __func__);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+int msm_audio_effects_reverb_handler(struct audio_client *ac,
+ struct reverb_params *reverb,
+ long *values)
+{
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
+ int *updt_params, i, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+
+ pr_debug("%s\n", __func__);
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
+ switch (command_id) {
+ case REVERB_ENABLE:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_ENABLE:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = reverb->enable_flag;
+ reverb->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s:REVERB_ENABLE prev:%d,new:%d\n", __func__,
+ prev_enable_flag, reverb->enable_flag);
+ if (prev_enable_flag != reverb->enable_flag) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_ENABLE;
+ *updt_params++ =
+ REVERB_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ reverb->enable_flag;
+ }
+ break;
+ case REVERB_MODE:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_MODE:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->mode =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_MODE val:%d\n",
+ __func__, reverb->mode);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_MODE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_MODE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_MODE;
+ *updt_params++ =
+ REVERB_MODE_PARAM_SZ;
+ *updt_params++ =
+ reverb->mode;
+ }
+ break;
+ case REVERB_PRESET:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_PRESET:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->preset =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_PRESET val:%d\n",
+ __func__, reverb->preset);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_PRESET_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_PRESET", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_PRESET;
+ *updt_params++ =
+ REVERB_PRESET_PARAM_SZ;
+ *updt_params++ =
+ reverb->preset;
+ }
+ break;
+ case REVERB_WET_MIX:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_WET_MIX:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->wet_mix =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_WET_MIX val:%d\n",
+ __func__, reverb->wet_mix);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_WET_MIX_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_WET_MIX", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_WET_MIX;
+ *updt_params++ =
+ REVERB_WET_MIX_PARAM_SZ;
+ *updt_params++ =
+ reverb->wet_mix;
+ }
+ break;
+ case REVERB_GAIN_ADJUST:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_GAIN_ADJUST:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->gain_adjust =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_GAIN_ADJUST val:%d\n",
+ __func__, reverb->gain_adjust);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_GAIN_ADJUST_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_GAIN_ADJUST", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST;
+ *updt_params++ =
+ REVERB_GAIN_ADJUST_PARAM_SZ;
+ *updt_params++ =
+ reverb->gain_adjust;
+ }
+ break;
+ case REVERB_ROOM_LEVEL:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_ROOM_LEVEL:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->room_level =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_ROOM_LEVEL val:%d\n",
+ __func__, reverb->room_level);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_ROOM_LEVEL_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_ROOM_LEVEL", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL;
+ *updt_params++ =
+ REVERB_ROOM_LEVEL_PARAM_SZ;
+ *updt_params++ =
+ reverb->room_level;
+ }
+ break;
+ case REVERB_ROOM_HF_LEVEL:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_ROOM_HF_LEVEL:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->room_hf_level =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_ROOM_HF_LEVEL val%d\n",
+ __func__, reverb->room_hf_level);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_ROOM_HF_LEVEL_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_ROOM_HF_LEVEL", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL;
+ *updt_params++ =
+ REVERB_ROOM_HF_LEVEL_PARAM_SZ;
+ *updt_params++ =
+ reverb->room_hf_level;
+ }
+ break;
+ case REVERB_DECAY_TIME:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_DECAY_TIME:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->decay_time =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_DECAY_TIME val:%d\n",
+ __func__, reverb->decay_time);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DECAY_TIME_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DECAY_TIME", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DECAY_TIME;
+ *updt_params++ =
+ REVERB_DECAY_TIME_PARAM_SZ;
+ *updt_params++ =
+ reverb->decay_time;
+ }
+ break;
+ case REVERB_DECAY_HF_RATIO:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_DECAY_HF_RATIOinvalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->decay_hf_ratio =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_DECAY_HF_RATIO val%d\n",
+ __func__, reverb->decay_hf_ratio);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DECAY_HF_RATIO_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DECAY_HF_RATIO", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO;
+ *updt_params++ =
+ REVERB_DECAY_HF_RATIO_PARAM_SZ;
+ *updt_params++ =
+ reverb->decay_hf_ratio;
+ }
+ break;
+ case REVERB_REFLECTIONS_LEVEL:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_REFLECTION_LVLinvalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->reflections_level =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_REFLECTIONS_LEVEL val:%d\n",
+ __func__, reverb->reflections_level);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_REFLECTIONS_LEVEL", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL;
+ *updt_params++ =
+ REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
+ *updt_params++ =
+ reverb->reflections_level;
+ }
+ break;
+ case REVERB_REFLECTIONS_DELAY:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_REFLECTION_DLYinvalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->reflections_delay =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_REFLECTIONS_DELAY val:%d\n",
+ __func__, reverb->reflections_delay);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_REFLECTIONS_DELAY_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_REFLECTIONS_DELAY", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY;
+ *updt_params++ =
+ REVERB_REFLECTIONS_DELAY_PARAM_SZ;
+ *updt_params++ =
+ reverb->reflections_delay;
+ }
+ break;
+ case REVERB_LEVEL:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_LEVEL:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->level =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_LEVEL val:%d\n",
+ __func__, reverb->level);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_LEVEL_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_LEVEL", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_LEVEL;
+ *updt_params++ =
+ REVERB_LEVEL_PARAM_SZ;
+ *updt_params++ =
+ reverb->level;
+ }
+ break;
+ case REVERB_DELAY:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_DELAY:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->delay =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s:REVERB_DELAY val:%d\n",
+ __func__, reverb->delay);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DELAY_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DELAY", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DELAY;
+ *updt_params++ =
+ REVERB_DELAY_PARAM_SZ;
+ *updt_params++ =
+ reverb->delay;
+ }
+ break;
+ case REVERB_DIFFUSION:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_DIFFUSION:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->diffusion =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_DIFFUSION val:%d\n",
+ __func__, reverb->diffusion);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DIFFUSION_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DIFFUSION", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DIFFUSION;
+ *updt_params++ =
+ REVERB_DIFFUSION_PARAM_SZ;
+ *updt_params++ =
+ reverb->diffusion;
+ }
+ break;
+ case REVERB_DENSITY:
+ if (length != 1 || index_offset != 0) {
+ pr_err("REVERB_DENSITY:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->density =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: REVERB_DENSITY val:%d\n",
+ __func__, reverb->density);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DENSITY_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DENSITY", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DENSITY;
+ *updt_params++ =
+ REVERB_DENSITY_PARAM_SZ;
+ *updt_params++ =
+ reverb->density;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+ else
+ pr_debug("%s: did not send pp params\n", __func__);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
+ struct bass_boost_params *bass_boost,
+ long *values)
+{
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
+ int *updt_params, i, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+
+ pr_debug("%s\n", __func__);
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
+ switch (command_id) {
+ case BASS_BOOST_ENABLE:
+ if (length != 1 || index_offset != 0) {
+ pr_err("BASS_BOOST_ENABLE:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = bass_boost->enable_flag;
+ bass_boost->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: BASS_BOOST_ENABLE prev:%d new:%d\n",
+ __func__, prev_enable_flag,
+ bass_boost->enable_flag);
+ if (prev_enable_flag != bass_boost->enable_flag) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ BASS_BOOST_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "BASS_BOOST_ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_ENABLE;
+ *updt_params++ =
+ BASS_BOOST_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ bass_boost->enable_flag;
+ }
+ break;
+ case BASS_BOOST_MODE:
+ if (length != 1 || index_offset != 0) {
+ pr_err("BASS_BOOST_MODE:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ bass_boost->mode =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: BASS_BOOST_MODE val:%d\n",
+ __func__, bass_boost->mode);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ BASS_BOOST_MODE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "BASS_BOOST_MODE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_MODE;
+ *updt_params++ =
+ BASS_BOOST_MODE_PARAM_SZ;
+ *updt_params++ =
+ bass_boost->mode;
+ }
+ break;
+ case BASS_BOOST_STRENGTH:
+ if (length != 1 || index_offset != 0) {
+ pr_err("BASS_BOOST_STRENGTH:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ bass_boost->strength =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: BASS_BOOST_STRENGTH val:%d\n",
+ __func__, bass_boost->strength);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ BASS_BOOST_STRENGTH_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "BASS_BOOST_STRENGTH", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH;
+ *updt_params++ =
+ BASS_BOOST_STRENGTH_PARAM_SZ;
+ *updt_params++ =
+ bass_boost->strength;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+ else
+ pr_debug("%s: did not send pp params\n", __func__);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+int msm_audio_effects_pbe_handler(struct audio_client *ac,
+ struct pbe_params *pbe,
+ long *values)
+{
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
+ int *updt_params, i, j, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+
+ pr_debug("%s\n", __func__);
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
+ switch (command_id) {
+ case PBE_ENABLE:
+ pr_debug("%s: PBE_ENABLE\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = pbe->enable_flag;
+ pbe->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
+ if (prev_enable_flag != pbe->enable_flag) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ PBE_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "PBE_ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_PBE;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_PBE_ENABLE;
+ *updt_params++ =
+ PBE_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ pbe->enable_flag;
+ }
+ break;
+ case PBE_CONFIG:
+ pr_debug("%s: PBE_PARAM length %u\n", __func__, length);
+ if (length > sizeof(struct pbe_config_t) ||
+ length < PBE_CONFIG_PARAM_LEN ||
+ index_offset != 0) {
+ pr_err("no valid params, len %d\n", length);
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ + length;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "PBE_PARAM", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_PBE;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_PBE_PARAM_CONFIG;
+ *updt_params++ =
+ length;
+ for (j = 0; j < length; ) {
+ j += sizeof(*updt_params);
+ *updt_params++ =
+ GET_NEXT(
+ values,
+ param_max_offset,
+ rc);
+ }
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length && (rc == 0))
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
+ struct eq_params *eq,
+ long *values)
+{
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
+ int *updt_params, i, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+
+ pr_debug("%s\n", __func__);
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t idx;
+ int j;
+
+ switch (command_id) {
+ case EQ_ENABLE:
+ if (length != 1 || index_offset != 0) {
+ pr_err("EQ_ENABLE:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = eq->enable_flag;
+ eq->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: EQ_ENABLE prev:%d new:%d\n", __func__,
+ prev_enable_flag, eq->enable_flag);
+ if (prev_enable_flag != eq->enable_flag) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ EQ_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "EQ_ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_EQ_ENABLE;
+ *updt_params++ =
+ EQ_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ eq->enable_flag;
+ }
+ break;
+ case EQ_CONFIG:
+ if (length < EQ_CONFIG_PARAM_LEN || index_offset != 0) {
+ pr_err("EQ_CONFIG:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ pr_debug("%s: EQ_CONFIG bands:%d, pgain:%d, pset:%d\n",
+ __func__, eq->config.num_bands,
+ eq->config.eq_pregain, eq->config.preset_id);
+ for (idx = 0; idx < MAX_EQ_BANDS; idx++)
+ eq->per_band_cfg[idx].band_idx = -1;
+ eq->config.eq_pregain =
+ GET_NEXT(values, param_max_offset, rc);
+ eq->config.preset_id =
+ GET_NEXT(values, param_max_offset, rc);
+ eq->config.num_bands =
+ GET_NEXT(values, param_max_offset, rc);
+ if (eq->config.num_bands > MAX_EQ_BANDS) {
+ pr_err("EQ_CONFIG:invalid num of bands\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ if (eq->config.num_bands &&
+ (((length - EQ_CONFIG_PARAM_LEN)/
+ EQ_CONFIG_PER_BAND_PARAM_LEN)
+ != eq->config.num_bands)) {
+ pr_err("EQ_CONFIG:invalid length per band\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ for (j = 0; j < eq->config.num_bands; j++) {
+ idx = GET_NEXT(values, param_max_offset, rc);
+ if (idx >= MAX_EQ_BANDS) {
+ pr_err("EQ_CONFIG:invalid band index\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ eq->per_band_cfg[idx].band_idx = idx;
+ eq->per_band_cfg[idx].filter_type =
+ GET_NEXT(values, param_max_offset, rc);
+ eq->per_band_cfg[idx].freq_millihertz =
+ GET_NEXT(values, param_max_offset, rc);
+ eq->per_band_cfg[idx].gain_millibels =
+ GET_NEXT(values, param_max_offset, rc);
+ eq->per_band_cfg[idx].quality_factor =
+ GET_NEXT(values, param_max_offset, rc);
+ }
+ if (command_config_state == CONFIG_SET) {
+ int config_param_length = EQ_CONFIG_PARAM_SZ +
+ (EQ_CONFIG_PER_BAND_PARAM_SZ*
+ eq->config.num_bands);
+ params_length += COMMAND_PAYLOAD_SZ +
+ config_param_length;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "EQ_CONFIG", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_EQ_CONFIG;
+ *updt_params++ =
+ config_param_length;
+ *updt_params++ =
+ eq->config.eq_pregain;
+ *updt_params++ =
+ eq->config.preset_id;
+ *updt_params++ =
+ eq->config.num_bands;
+ for (idx = 0; idx < MAX_EQ_BANDS; idx++) {
+ if (eq->per_band_cfg[idx].band_idx < 0)
+ continue;
+ *updt_params++ =
+ eq->per_band_cfg[idx].filter_type;
+ *updt_params++ =
+ eq->per_band_cfg[idx].freq_millihertz;
+ *updt_params++ =
+ eq->per_band_cfg[idx].gain_millibels;
+ *updt_params++ =
+ eq->per_band_cfg[idx].quality_factor;
+ *updt_params++ =
+ eq->per_band_cfg[idx].band_idx;
+ }
+ }
+ break;
+ case EQ_BAND_INDEX:
+ if (length != 1 || index_offset != 0) {
+ pr_err("EQ_BAND_INDEX:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ idx = GET_NEXT(values, param_max_offset, rc);
+ if (idx > MAX_EQ_BANDS) {
+ pr_err("EQ_BAND_INDEX:invalid band index\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ eq->band_index = idx;
+ pr_debug("%s: EQ_BAND_INDEX val:%d\n",
+ __func__, eq->band_index);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ EQ_BAND_INDEX_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "EQ_BAND_INDEX", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_EQ_BAND_INDEX;
+ *updt_params++ =
+ EQ_BAND_INDEX_PARAM_SZ;
+ *updt_params++ =
+ eq->band_index;
+ }
+ break;
+ case EQ_SINGLE_BAND_FREQ:
+ if (length != 1 || index_offset != 0) {
+ pr_err("EQ_SINGLE_BAND_FREQ:invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ if (eq->band_index > MAX_EQ_BANDS) {
+ pr_err("EQ_SINGLE_BAND_FREQ:invalid index\n");
+ break;
+ }
+ eq->freq_millihertz =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: EQ_SINGLE_BAND_FREQ idx:%d, val:%d\n",
+ __func__, eq->band_index, eq->freq_millihertz);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ EQ_SINGLE_BAND_FREQ_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "EQ_SINGLE_BAND_FREQ", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ;
+ *updt_params++ =
+ EQ_SINGLE_BAND_FREQ_PARAM_SZ;
+ *updt_params++ =
+ eq->freq_millihertz;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+ else
+ pr_debug("%s: did not send pp params\n", __func__);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+static int __msm_audio_effects_volume_handler(struct audio_client *ac,
+ struct soft_volume_params *vol,
+ long *values,
+ int instance)
+{
+ int devices;
+ int num_commands;
+ char *params = NULL;
+ int *updt_params, i;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+ long *param_max_offset;
+ int rc = 0;
+
+ pr_debug("%s: instance: %d\n", __func__, instance);
+ if (!values) {
+ pr_err("%s: set audio effects failed, no valid data\n",
+ __func__);
+ return -EINVAL;
+ }
+ param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ devices = GET_NEXT(values, param_max_offset, rc);
+ num_commands = GET_NEXT(values, param_max_offset, rc);
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
+ switch (command_id) {
+ case SOFT_VOLUME_GAIN_2CH:
+ case SOFT_VOLUME2_GAIN_2CH:
+ if (length != 2 || index_offset != 0) {
+ pr_err("VOLUME_GAIN_2CH: invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ vol->left_gain = GET_NEXT(values, param_max_offset, rc);
+ vol->right_gain =
+ GET_NEXT(values, param_max_offset, rc);
+ vol->master_gain = 0x2000;
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ SOFT_VOLUME_GAIN_2CH_PARAM_SZ;
+ params_length += COMMAND_PAYLOAD_SZ +
+ SOFT_VOLUME_GAIN_MASTER_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VOLUME/VOLUME2_GAIN_2CH",
+ rc);
+ if (rc != 0)
+ break;
+ if (instance == SOFT_VOLUME_INSTANCE_2)
+ *updt_params++ =
+ ASM_MODULE_ID_VOL_CTRL2;
+ else
+ *updt_params++ =
+ ASM_MODULE_ID_VOL_CTRL;
+ *updt_params++ =
+ ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN;
+ *updt_params++ =
+ SOFT_VOLUME_GAIN_2CH_PARAM_SZ;
+ *updt_params++ =
+ (vol->left_gain << 16) |
+ vol->right_gain;
+ if (instance == SOFT_VOLUME_INSTANCE_2)
+ *updt_params++ =
+ ASM_MODULE_ID_VOL_CTRL2;
+ else
+ *updt_params++ =
+ ASM_MODULE_ID_VOL_CTRL;
+ *updt_params++ =
+ ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN;
+ *updt_params++ =
+ SOFT_VOLUME_GAIN_MASTER_PARAM_SZ;
+ *updt_params++ =
+ vol->master_gain;
+ }
+ break;
+ case SOFT_VOLUME_GAIN_MASTER:
+ case SOFT_VOLUME2_GAIN_MASTER:
+ if (length != 1 || index_offset != 0) {
+ pr_err("VOLUME_GAIN_MASTER: invalid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ vol->left_gain = 0x2000;
+ vol->right_gain = 0x2000;
+ vol->master_gain =
+ GET_NEXT(values, param_max_offset, rc);
+ if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ SOFT_VOLUME_GAIN_2CH_PARAM_SZ;
+ params_length += COMMAND_PAYLOAD_SZ +
+ SOFT_VOLUME_GAIN_MASTER_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VOLUME/VOLUME2_GAIN_MASTER",
+ rc);
+ if (rc != 0)
+ break;
+ if (instance == SOFT_VOLUME_INSTANCE_2)
+ *updt_params++ =
+ ASM_MODULE_ID_VOL_CTRL2;
+ else
+ *updt_params++ =
+ ASM_MODULE_ID_VOL_CTRL;
+ *updt_params++ =
+ ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN;
+ *updt_params++ =
+ SOFT_VOLUME_GAIN_2CH_PARAM_SZ;
+ *updt_params++ =
+ (vol->left_gain << 16) |
+ vol->right_gain;
+ if (instance == SOFT_VOLUME_INSTANCE_2)
+ *updt_params++ =
+ ASM_MODULE_ID_VOL_CTRL2;
+ else
+ *updt_params++ =
+ ASM_MODULE_ID_VOL_CTRL;
+ *updt_params++ =
+ ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN;
+ *updt_params++ =
+ SOFT_VOLUME_GAIN_MASTER_PARAM_SZ;
+ *updt_params++ =
+ vol->master_gain;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command id: %d to set config\n",
+ __func__, command_id);
+ break;
+ }
+ }
+ if (params_length && (rc == 0))
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+int msm_audio_effects_volume_handler(struct audio_client *ac,
+ struct soft_volume_params *vol,
+ long *values)
+{
+ return __msm_audio_effects_volume_handler(ac, vol, values,
+ SOFT_VOLUME_INSTANCE_1);
+}
+
+int msm_audio_effects_volume_handler_v2(struct audio_client *ac,
+ struct soft_volume_params *vol,
+ long *values, int instance)
+{
+ return __msm_audio_effects_volume_handler(ac, vol, values, instance);
+}
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
new file mode 100644
index 0000000..6c78f85
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -0,0 +1,1714 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm_params.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
+
+#include <sound/timer.h>
+
+#include "msm-compr-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+#include <sound/tlv.h>
+
+#define COMPRE_CAPTURE_NUM_PERIODS 16
+/* Allocate the worst case frame size for compressed audio */
+#define COMPRE_CAPTURE_HEADER_SIZE (sizeof(struct snd_compr_audio_info))
+/* Changing period size to 4032. 4032 will make sure COMPRE_CAPTURE_PERIOD_SIZE
+ * is 4096 with meta data size of 64 and MAX_NUM_FRAMES_PER_BUFFER 1
+ */
+#define COMPRE_CAPTURE_MAX_FRAME_SIZE (4032)
+#define COMPRE_CAPTURE_PERIOD_SIZE ((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
+ COMPRE_CAPTURE_HEADER_SIZE) * \
+ MAX_NUM_FRAMES_PER_BUFFER)
+#define COMPRE_OUTPUT_METADATA_SIZE (sizeof(struct output_meta_data_st))
+#define COMPRESSED_LR_VOL_MAX_STEPS 0x20002000
+
+#define MAX_AC3_PARAM_SIZE (18*2*sizeof(int))
+#define AMR_WB_BAND_MODE 8
+#define AMR_WB_DTX_MODE 0
+
+
+const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0,
+ COMPRESSED_LR_VOL_MAX_STEPS);
+
+static struct audio_locks the_locks;
+
+static struct snd_pcm_hardware msm_compr_hardware_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max =
+ COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS,
+ .period_bytes_min = COMPRE_CAPTURE_PERIOD_SIZE,
+ .period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
+ .periods_min = COMPRE_CAPTURE_NUM_PERIODS,
+ .periods_max = COMPRE_CAPTURE_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware msm_compr_hardware_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = 1024 * 1024,
+ .period_bytes_min = 128 * 1024,
+ .period_bytes_max = 256 * 1024,
+ .periods_min = 4,
+ .periods_max = 8,
+ .fifo_size = 0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+/* Add supported codecs for compress capture path */
+static uint32_t supported_compr_capture_codecs[] = {
+ SND_AUDIOCODEC_AMRWB
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static bool msm_compr_capture_codecs(uint32_t req_codec)
+{
+ int i;
+
+ pr_debug("%s req_codec:%d\n", __func__, req_codec);
+ if (req_codec == 0)
+ return false;
+ for (i = 0; i < ARRAY_SIZE(supported_compr_capture_codecs); i++) {
+ if (req_codec == supported_compr_capture_codecs[i])
+ return true;
+ }
+ return false;
+}
+
+static void compr_event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ struct compr_audio *compr = priv;
+ struct msm_audio *prtd = &compr->prtd;
+ struct snd_pcm_substream *substream = prtd->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_aio_write_param param;
+ struct audio_aio_read_param read_param;
+ struct audio_buffer *buf = NULL;
+ phys_addr_t temp;
+ struct output_meta_data_st output_meta_data;
+ uint32_t *ptrmem = (uint32_t *)payload;
+ int i = 0;
+ int time_stamp_flag = 0;
+ int buffer_length = 0;
+ int stop_playback = 0;
+
+ pr_debug("%s opcode =%08x\n", __func__, opcode);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE_V2: {
+ uint32_t *ptrmem = (uint32_t *)¶m;
+
+ pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+ pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+ prtd->pcm_irq_pos += prtd->pcm_count;
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ else
+ if (substream->timer_running)
+ snd_timer_interrupt(substream->timer, 1);
+ atomic_inc(&prtd->out_count);
+ wake_up(&the_locks.write_wait);
+ if (!atomic_read(&prtd->start)) {
+ atomic_set(&prtd->pending_buffer, 1);
+ break;
+ }
+ atomic_set(&prtd->pending_buffer, 0);
+
+ /*
+ * check for underrun
+ */
+ snd_pcm_stream_lock_irq(substream);
+ if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
+ runtime->render_flag |= SNDRV_RENDER_STOPPED;
+ stop_playback = 1;
+ }
+ snd_pcm_stream_unlock_irq(substream);
+
+ if (stop_playback) {
+ pr_err("underrun! render stopped\n");
+ break;
+ }
+
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ temp = buf[0].phys + (prtd->out_head * prtd->pcm_count);
+ pr_debug("%s:writing buffer[%d] from 0x%pK\n",
+ __func__, prtd->out_head, &temp);
+
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+ time_stamp_flag = SET_TIMESTAMP;
+ else
+ time_stamp_flag = NO_TIMESTAMP;
+ memcpy(&output_meta_data, (char *)(buf->data +
+ prtd->out_head * prtd->pcm_count),
+ COMPRE_OUTPUT_METADATA_SIZE);
+
+ buffer_length = output_meta_data.frame_size;
+ pr_debug("meta_data_length: %d, frame_length: %d\n",
+ output_meta_data.meta_data_length,
+ output_meta_data.frame_size);
+ pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+ output_meta_data.timestamp_msw,
+ output_meta_data.timestamp_lsw);
+ if (buffer_length == 0) {
+ pr_debug("Received a zero length buffer-break out");
+ break;
+ }
+ param.paddr = temp + output_meta_data.meta_data_length;
+ param.len = buffer_length;
+ param.msw_ts = output_meta_data.timestamp_msw;
+ param.lsw_ts = output_meta_data.timestamp_lsw;
+ param.flags = time_stamp_flag;
+ param.uid = prtd->session_id;
+ for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
+ i++, ++ptrmem)
+ pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1) & (runtime->periods - 1);
+ break;
+ }
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ pr_debug("ASM_DATA_CMDRSP_EOS\n");
+ if (atomic_read(&prtd->eos)) {
+ pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
+ prtd->cmd_ack = 1;
+ wake_up(&the_locks.eos_wait);
+ atomic_set(&prtd->eos, 0);
+ }
+ break;
+ case ASM_DATA_EVENT_READ_DONE_V2: {
+ pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+ pr_debug("buf = %pK, data = 0x%X, *data = %pK,\n"
+ "prtd->pcm_irq_pos = %d\n",
+ prtd->audio_client->port[OUT].buf,
+ *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
+ prtd->audio_client->port[OUT].buf->data,
+ prtd->pcm_irq_pos);
+
+ memcpy(prtd->audio_client->port[OUT].buf->data +
+ prtd->pcm_irq_pos, (ptrmem + READDONE_IDX_SIZE),
+ COMPRE_CAPTURE_HEADER_SIZE);
+ pr_debug("buf = %pK, updated data = 0x%X, *data = %pK\n",
+ prtd->audio_client->port[OUT].buf,
+ *(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
+ prtd->pcm_irq_pos),
+ prtd->audio_client->port[OUT].buf->data);
+ if (!atomic_read(&prtd->start))
+ break;
+ pr_debug("frame size=%d, buffer = 0x%X\n",
+ ptrmem[READDONE_IDX_SIZE],
+ ptrmem[READDONE_IDX_BUFADD_LSW]);
+ if (ptrmem[READDONE_IDX_SIZE] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
+ pr_err("Frame length exceeded the max length");
+ break;
+ }
+ buf = prtd->audio_client->port[OUT].buf;
+
+ pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%pK\n",
+ prtd->pcm_irq_pos, &buf[0].phys);
+ read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
+ read_param.paddr = buf[0].phys +
+ prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
+ prtd->pcm_irq_pos += prtd->pcm_count;
+
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+
+ q6asm_async_read(prtd->audio_client, &read_param);
+ break;
+ }
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case ASM_SESSION_CMD_RUN_V2: {
+ if (substream->stream
+ != SNDRV_PCM_STREAM_PLAYBACK) {
+ atomic_set(&prtd->start, 1);
+ break;
+ }
+ if (!atomic_read(&prtd->pending_buffer))
+ break;
+ pr_debug("%s: writing %d bytes of buffer[%d] to dsp\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s: writing buffer[%d] from 0x%pK head %d count %d\n",
+ __func__, prtd->out_head, &buf[0].phys,
+ prtd->pcm_count, prtd->out_head);
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+ time_stamp_flag = SET_TIMESTAMP;
+ else
+ time_stamp_flag = NO_TIMESTAMP;
+ memcpy(&output_meta_data, (char *)(buf->data +
+ prtd->out_head * prtd->pcm_count),
+ COMPRE_OUTPUT_METADATA_SIZE);
+ buffer_length = output_meta_data.frame_size;
+ pr_debug("meta_data_length: %d, frame_length: %d\n",
+ output_meta_data.meta_data_length,
+ output_meta_data.frame_size);
+ pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+ output_meta_data.timestamp_msw,
+ output_meta_data.timestamp_lsw);
+ param.paddr = buf[prtd->out_head].phys
+ + output_meta_data.meta_data_length;
+ param.len = buffer_length;
+ param.msw_ts = output_meta_data.timestamp_msw;
+ param.lsw_ts = output_meta_data.timestamp_lsw;
+ param.flags = time_stamp_flag;
+ param.uid = prtd->session_id;
+ param.metadata_len = COMPRE_OUTPUT_METADATA_SIZE;
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1)
+ & (runtime->periods - 1);
+ atomic_set(&prtd->pending_buffer, 0);
+ }
+ break;
+ case ASM_STREAM_CMD_FLUSH:
+ pr_debug("ASM_STREAM_CMD_FLUSH\n");
+ prtd->cmd_ack = 1;
+ wake_up(&the_locks.flush_wait);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int msm_compr_send_ddp_cfg(struct audio_client *ac,
+ struct snd_dec_ddp *ddp)
+{
+ int i, rc;
+
+ pr_debug("%s\n", __func__);
+
+ if (ddp->params_length / 2 > SND_DEC_DDP_MAX_PARAMS) {
+ pr_err("%s: Invalid number of params %u, max allowed %u\n",
+ __func__, ddp->params_length / 2,
+ SND_DEC_DDP_MAX_PARAMS);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ddp->params_length/2; i++) {
+ rc = q6asm_ds1_set_endp_params(ac, ddp->params_id[i],
+ ddp->params_value[i]);
+ if (rc) {
+ pr_err("sending params_id: %d failed\n",
+ ddp->params_id[i]);
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct snd_pcm_hw_params *params;
+ struct asm_aac_cfg aac_cfg;
+ uint16_t bits_per_sample = 16;
+ int ret;
+
+ struct asm_softpause_params softpause = {
+ .enable = SOFT_PAUSE_ENABLE,
+ .period = SOFT_PAUSE_PERIOD,
+ .step = SOFT_PAUSE_STEP,
+ .rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
+ };
+ struct asm_softvolume_params softvol = {
+ .period = SOFT_VOLUME_PERIOD,
+ .step = SOFT_VOLUME_STEP,
+ .rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
+ };
+
+ pr_debug("%s\n", __func__);
+
+ params = &soc_prtd->dpcm[substream->stream].hw_params;
+ if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
+ bits_per_sample = 24;
+
+ ret = q6asm_open_write_v2(prtd->audio_client,
+ compr->codec, bits_per_sample);
+ if (ret < 0) {
+ pr_err("%s: Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_pcm_routing_reg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id,
+ substream->stream);
+ /*
+ * the number of channels are required to call volume api
+ * accoridngly. So, get channels from hw params
+ */
+ if ((params_channels(params) > 0) &&
+ (params_periods(params) <= runtime->hw.channels_max))
+ prtd->channel_mode = params_channels(params);
+
+ ret = q6asm_set_softpause(prtd->audio_client, &softpause);
+ if (ret < 0)
+ pr_err("%s: Send SoftPause Param failed ret=%d\n",
+ __func__, ret);
+ ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
+ if (ret < 0)
+ pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+ __func__, ret);
+
+ ret = q6asm_set_io_mode(prtd->audio_client,
+ (COMPRESSED_IO | ASYNC_IO_MODE));
+ if (ret < 0) {
+ pr_err("%s: Set IO mode failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+ prtd->out_head = 0;
+ atomic_set(&prtd->out_count, runtime->periods);
+
+ if (prtd->enabled)
+ return 0;
+
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_MP3:
+ /* No media format block for mp3 */
+ break;
+ case SND_AUDIOCODEC_AAC:
+ pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__);
+ memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
+ aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+ aac_cfg.format = 0x03;
+ aac_cfg.ch_cfg = runtime->channels;
+ aac_cfg.sample_rate = runtime->rate;
+ ret = q6asm_media_format_block_aac(prtd->audio_client,
+ &aac_cfg);
+ if (ret < 0)
+ pr_err("%s: CMD Format block failed\n", __func__);
+ break;
+ case SND_AUDIOCODEC_AC3: {
+ struct snd_dec_ddp *ddp =
+ &compr->info.codec_param.codec.options.ddp;
+ pr_debug("%s: SND_AUDIOCODEC_AC3\n", __func__);
+ ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp);
+ if (ret < 0)
+ pr_err("%s: DDP CMD CFG failed\n", __func__);
+ break;
+ }
+ case SND_AUDIOCODEC_EAC3: {
+ struct snd_dec_ddp *ddp =
+ &compr->info.codec_param.codec.options.ddp;
+ pr_debug("%s: SND_AUDIOCODEC_EAC3\n", __func__);
+ ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp);
+ if (ret < 0)
+ pr_err("%s: DDP CMD CFG failed\n", __func__);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ prtd->enabled = 1;
+ prtd->cmd_ack = 0;
+ prtd->cmd_interrupt = 0;
+
+ return 0;
+}
+
+static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
+ struct snd_codec *codec = &compr->info.codec_param.codec;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct audio_aio_read_param read_param;
+ uint16_t bits_per_sample = 16;
+ int ret = 0;
+ int i;
+
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+
+ if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
+ bits_per_sample = 24;
+
+ if (!msm_compr_capture_codecs(
+ compr->info.codec_param.codec.id)) {
+ /*
+ * request codec invalid or not supported,
+ * use default compress format
+ */
+ compr->info.codec_param.codec.id =
+ SND_AUDIOCODEC_AMRWB;
+ }
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
+ ret = q6asm_open_read(prtd->audio_client,
+ FORMAT_AMRWB);
+ if (ret < 0) {
+ pr_err("%s: compressed Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ pr_debug("msm_pcm_routing_reg_phy_stream\n");
+ msm_pcm_routing_reg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id, substream->stream);
+ break;
+ default:
+ pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
+ /*
+ * ret = q6asm_open_read_compressed(prtd->audio_client,
+ * MAX_NUM_FRAMES_PER_BUFFER,
+ * COMPRESSED_META_DATA_MODE);
+ */
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret < 0) {
+ pr_err("%s: compressed Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ ret = q6asm_set_io_mode(prtd->audio_client,
+ (COMPRESSED_IO | ASYNC_IO_MODE));
+ if (ret < 0) {
+ pr_err("%s: Set IO mode failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (!msm_compr_capture_codecs(codec->id)) {
+ /*
+ * request codec invalid or not supported,
+ * use default compress format
+ */
+ codec->id = SND_AUDIOCODEC_AMRWB;
+ }
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+
+ if (prtd->enabled)
+ return ret;
+ read_param.len = prtd->pcm_count;
+
+ switch (codec->id) {
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("SND_AUDIOCODEC_AMRWB\n");
+ ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
+ MAX_NUM_FRAMES_PER_BUFFER,
+ /*
+ * use fixed band mode and dtx mode
+ * band mode - 23.85 kbps
+ */
+ AMR_WB_BAND_MODE,
+ /* dtx mode - disable */
+ AMR_WB_DTX_MODE);
+ if (ret < 0)
+ pr_err("%s: CMD Format block failed: %d\n",
+ __func__, ret);
+ break;
+ default:
+ pr_debug("No config for codec %d\n", codec->id);
+ }
+ pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
+ "pcm_count = %d, periods = %d\n",
+ __func__, prtd->samp_rate, prtd->channel_mode,
+ prtd->pcm_size, prtd->pcm_count, runtime->periods);
+
+ for (i = 0; i < runtime->periods; i++) {
+ read_param.uid = i;
+ switch (codec->id) {
+ case SND_AUDIOCODEC_AMRWB:
+ read_param.len = prtd->pcm_count
+ - COMPRE_CAPTURE_HEADER_SIZE;
+ read_param.paddr = buf[i].phys
+ + COMPRE_CAPTURE_HEADER_SIZE;
+ pr_debug("Push buffer [%d] to DSP, paddr: %pK, vaddr: %pK\n",
+ i, &read_param.paddr,
+ buf[i].data);
+ q6asm_async_read(prtd->audio_client, &read_param);
+ break;
+ default:
+ read_param.paddr = buf[i].phys;
+ /* q6asm_async_read_compressed(prtd->audio_client,
+ * &read_param);
+ */
+ pr_debug("%s: To add support for read compressed\n",
+ __func__);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ prtd->periods = runtime->periods;
+
+ prtd->enabled = 1;
+
+ return ret;
+}
+
+static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+
+ pr_debug("%s\n", __func__);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ prtd->pcm_irq_pos = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!msm_compr_capture_codecs(
+ compr->info.codec_param.codec.id)) {
+ /*
+ * request codec invalid or not supported,
+ * use default compress format
+ */
+ compr->info.codec_param.codec.id =
+ SND_AUDIOCODEC_AMRWB;
+ }
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ break;
+ default:
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+ break;
+ }
+ }
+ atomic_set(&prtd->pending_buffer, 1);
+ /* fallthrough */
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: Trigger start\n", __func__);
+ q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ atomic_set(&prtd->start, 1);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ break;
+ default:
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+ break;
+ }
+ }
+ atomic_set(&prtd->start, 0);
+ runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+ q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->start, 0);
+ runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void populate_codec_list(struct compr_audio *compr,
+ struct snd_pcm_runtime *runtime)
+{
+ pr_debug("%s\n", __func__);
+ /* MP3 Block */
+ compr->info.compr_cap.num_codecs = 5;
+ compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
+ compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
+ compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
+ compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
+ compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
+ compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
+ compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
+ compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
+ compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_AMRWB;
+ /* Add new codecs here */
+}
+
+static int msm_compr_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr;
+ struct msm_audio *prtd;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
+ if (compr == NULL) {
+ pr_err("Failed to allocate memory for msm_audio\n");
+ return -ENOMEM;
+ }
+ prtd = &compr->prtd;
+ prtd->substream = substream;
+ runtime->render_flag = SNDRV_DMA_MODE;
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)compr_event_handler, compr);
+ if (!prtd->audio_client) {
+ pr_info("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+
+ prtd->audio_client->perf_mode = false;
+ pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
+
+ prtd->session_id = prtd->audio_client->session;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = msm_compr_hardware_playback;
+ prtd->cmd_ack = 1;
+ } else {
+ runtime->hw = msm_compr_hardware_capture;
+ }
+
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret < 0)
+ pr_info("snd_pcm_hw_constraint_list failed\n");
+ /* Ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+ prtd->dsp_cnt = 0;
+ atomic_set(&prtd->pending_buffer, 1);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ compr->codec = FORMAT_MP3;
+ populate_codec_list(compr, runtime);
+ runtime->private_data = compr;
+ atomic_set(&prtd->eos, 0);
+ return 0;
+}
+
+static int compressed_set_volume(struct msm_audio *prtd, uint32_t volume)
+{
+ int rc = 0;
+ int avg_vol = 0;
+ int lgain = (volume >> 16) & 0xFFFF;
+ int rgain = volume & 0xFFFF;
+
+ if (prtd && prtd->audio_client) {
+ pr_debug("%s: channels %d volume 0x%x\n", __func__,
+ prtd->channel_mode, volume);
+ if ((prtd->channel_mode == 2) &&
+ (lgain != rgain)) {
+ pr_debug("%s: call q6asm_set_lrgain\n", __func__);
+ rc = q6asm_set_lrgain(prtd->audio_client, lgain, rgain);
+ } else {
+ avg_vol = (lgain + rgain)/2;
+ pr_debug("%s: call q6asm_set_volume\n", __func__);
+ rc = q6asm_set_volume(prtd->audio_client, avg_vol);
+ }
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
+ }
+ }
+ return rc;
+}
+
+static int msm_compr_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ int dir = 0;
+
+ pr_debug("%s\n", __func__);
+
+ dir = IN;
+ atomic_set(&prtd->pending_buffer, 0);
+
+ prtd->pcm_irq_pos = 0;
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+ msm_pcm_routing_dereg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return 0;
+}
+
+static int msm_compr_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ int dir = OUT;
+
+ pr_debug("%s\n", __func__);
+ atomic_set(&prtd->pending_buffer, 0);
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return 0;
+}
+
+static int msm_compr_close(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_compr_playback_close(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_compr_capture_close(substream);
+ return ret;
+}
+
+static int msm_compr_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_compr_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_compr_capture_prepare(substream);
+ return ret;
+}
+
+static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
+{
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+
+ if (prtd->pcm_irq_pos >= prtd->pcm_size)
+ prtd->pcm_irq_pos = 0;
+
+ pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
+ "frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
+ prtd->pcm_size, runtime->sample_bits,
+ runtime->frame_bits);
+ return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_compr_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ struct audio_client *ac = prtd->audio_client;
+ struct audio_port_data *apd = ac->port;
+ struct audio_buffer *ab;
+ int dir = -1;
+
+ prtd->mmap_flag = 1;
+ runtime->render_flag = SNDRV_NON_DMA_MODE;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ab = &(apd[dir].buf[0]);
+
+ return msm_audio_ion_mmap(ab, vma);
+}
+
+static int msm_compr_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct audio_buffer *buf;
+ int dir, ret;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ /* Modifying kernel hardware params based on userspace config */
+ if (params_periods(params) > 0 &&
+ (params_periods(params) != runtime->hw.periods_max)) {
+ runtime->hw.periods_max = params_periods(params);
+ }
+ if (params_period_bytes(params) > 0 &&
+ (params_period_bytes(params) != runtime->hw.period_bytes_min)) {
+ runtime->hw.period_bytes_min = params_period_bytes(params);
+ }
+ runtime->hw.buffer_bytes_max =
+ runtime->hw.period_bytes_min * runtime->hw.periods_max;
+ pr_debug("allocate %zd buffers each of size %d\n",
+ runtime->hw.period_bytes_min,
+ runtime->hw.periods_max);
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+ prtd->audio_client,
+ runtime->hw.period_bytes_min,
+ runtime->hw.periods_max);
+ if (ret < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
+ ret);
+ return -ENOMEM;
+ }
+ buf = prtd->audio_client->port[dir].buf;
+
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = buf[0].data;
+ dma_buf->addr = buf[0].phys;
+ dma_buf->bytes = runtime->hw.buffer_bytes_max;
+
+ pr_debug("%s: buf[%pK]dma_buf->area[%pK]dma_buf->addr[%pK]\n"
+ "dma_buf->bytes[%zd]\n", __func__,
+ (void *)buf, (void *)dma_buf->area,
+ &dma_buf->addr, dma_buf->bytes);
+ if (!dma_buf->area)
+ return -ENOMEM;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ return 0;
+}
+
+static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ int rc = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ uint64_t timestamp;
+ uint64_t temp;
+
+ switch (cmd) {
+ case SNDRV_COMPRESS_TSTAMP: {
+ struct snd_compr_tstamp *tstamp;
+
+ pr_debug("SNDRV_COMPRESS_TSTAMP\n");
+ tstamp = arg;
+ memset(tstamp, 0x0, sizeof(*tstamp));
+ rc = q6asm_get_session_time(prtd->audio_client, ×tamp);
+ if (rc < 0) {
+ pr_err("%s: Get Session Time return value =%lld\n",
+ __func__, timestamp);
+ return -EAGAIN;
+ }
+ temp = (timestamp * 2 * runtime->channels);
+ temp = temp * (runtime->rate/1000);
+ temp = div_u64(temp, 1000);
+ tstamp->sampling_rate = runtime->rate;
+ tstamp->timestamp = timestamp;
+ pr_debug("%s: bytes_consumed:,timestamp = %lld,\n",
+ __func__,
+ tstamp->timestamp);
+ return 0;
+ }
+ case SNDRV_COMPRESS_GET_CAPS: {
+ struct snd_compr_caps *caps;
+
+ caps = arg;
+ memset(caps, 0, sizeof(*caps));
+ pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
+ memcpy(caps, &compr->info.compr_cap, sizeof(*caps));
+ return 0;
+ }
+ case SNDRV_COMPRESS_SET_PARAMS:
+ pr_debug("SNDRV_COMPRESS_SET_PARAMS:\n");
+ memcpy(&compr->info.codec_param, (void *) arg,
+ sizeof(struct snd_compr_params));
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_MP3:
+ /* For MP3 we dont need any other parameter */
+ pr_debug("SND_AUDIOCODEC_MP3\n");
+ compr->codec = FORMAT_MP3;
+ break;
+ case SND_AUDIOCODEC_AAC:
+ pr_debug("SND_AUDIOCODEC_AAC\n");
+ compr->codec = FORMAT_MPEG4_AAC;
+ break;
+ case SND_AUDIOCODEC_AC3: {
+ char params_value[MAX_AC3_PARAM_SIZE];
+ int *params_value_data = (int *)params_value;
+ /* 36 is the max param length for ddp */
+ int i;
+ struct snd_dec_ddp *ddp =
+ &compr->info.codec_param.codec.options.ddp;
+ uint32_t params_length = 0;
+
+ memset(params_value, 0, MAX_AC3_PARAM_SIZE);
+ /* check integer overflow */
+ if (ddp->params_length > UINT_MAX/sizeof(int)) {
+ pr_err("%s: Integer overflow ddp->params_length %d\n",
+ __func__, ddp->params_length);
+ return -EINVAL;
+ }
+ params_length = ddp->params_length*sizeof(int);
+ if (params_length > MAX_AC3_PARAM_SIZE) {
+ /*MAX is 36*sizeof(int) this should not happen*/
+ pr_err("%s: params_length(%d) is greater than %zd\n",
+ __func__, params_length, MAX_AC3_PARAM_SIZE);
+ return -EINVAL;
+ }
+ pr_debug("SND_AUDIOCODEC_AC3\n");
+ compr->codec = FORMAT_AC3;
+ pr_debug("params_length: %d\n", ddp->params_length);
+ for (i = 0; i < params_length/sizeof(int); i++)
+ pr_debug("params_value[%d]: %x\n", i,
+ params_value_data[i]);
+ for (i = 0; i < ddp->params_length/2; i++) {
+ ddp->params_id[i] = params_value_data[2*i];
+ ddp->params_value[i] = params_value_data[2*i+1];
+ }
+ if (atomic_read(&prtd->start)) {
+ rc = msm_compr_send_ddp_cfg(prtd->audio_client,
+ ddp);
+ if (rc < 0)
+ pr_err("%s: DDP CMD CFG failed\n",
+ __func__);
+ }
+ break;
+ }
+ case SND_AUDIOCODEC_EAC3: {
+ char params_value[MAX_AC3_PARAM_SIZE];
+ int *params_value_data = (int *)params_value;
+ /* 36 is the max param length for ddp */
+ int i;
+ struct snd_dec_ddp *ddp =
+ &compr->info.codec_param.codec.options.ddp;
+ uint32_t params_length = 0;
+
+ memset(params_value, 0, MAX_AC3_PARAM_SIZE);
+ /* check integer overflow */
+ if (ddp->params_length > UINT_MAX/sizeof(int)) {
+ pr_err("%s: Integer overflow ddp->params_length %d\n",
+ __func__, ddp->params_length);
+ return -EINVAL;
+ }
+ params_length = ddp->params_length*sizeof(int);
+ if (params_length > MAX_AC3_PARAM_SIZE) {
+ /*MAX is 36*sizeof(int) this should not happen*/
+ pr_err("%s: params_length(%d) is greater than %zd\n",
+ __func__, params_length, MAX_AC3_PARAM_SIZE);
+ return -EINVAL;
+ }
+ pr_debug("SND_AUDIOCODEC_EAC3\n");
+ compr->codec = FORMAT_EAC3;
+ pr_debug("params_length: %d\n", ddp->params_length);
+ for (i = 0; i < ddp->params_length; i++)
+ pr_debug("params_value[%d]: %x\n", i,
+ params_value_data[i]);
+ for (i = 0; i < ddp->params_length/2; i++) {
+ ddp->params_id[i] = params_value_data[2*i];
+ ddp->params_value[i] = params_value_data[2*i+1];
+ }
+ if (atomic_read(&prtd->start)) {
+ rc = msm_compr_send_ddp_cfg(prtd->audio_client,
+ ddp);
+ if (rc < 0)
+ pr_err("%s: DDP CMD CFG failed\n",
+ __func__);
+ }
+ break;
+ }
+ default:
+ pr_debug("FORMAT_LINEAR_PCM\n");
+ compr->codec = FORMAT_LINEAR_PCM;
+ break;
+ }
+ return 0;
+ case SNDRV_PCM_IOCTL1_RESET:
+ pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
+ /* Flush only when session is started during CAPTURE,
+ * while PLAYBACK has no such restriction.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+ (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+ atomic_read(&prtd->start))) {
+ if (atomic_read(&prtd->eos)) {
+ prtd->cmd_interrupt = 1;
+ wake_up(&the_locks.eos_wait);
+ atomic_set(&prtd->eos, 0);
+ }
+
+ /* A unlikely race condition possible with FLUSH
+ * DRAIN if ack is set by flush and reset by drain
+ */
+ prtd->cmd_ack = 0;
+ rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ if (rc < 0) {
+ pr_err("%s: flush cmd failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ rc = wait_event_timeout(the_locks.flush_wait,
+ prtd->cmd_ack, 5 * HZ);
+ if (!rc)
+ pr_err("Flush cmd timeout\n");
+ prtd->pcm_irq_pos = 0;
+ }
+ break;
+ case SNDRV_COMPRESS_DRAIN:
+ pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
+ if (atomic_read(&prtd->pending_buffer)) {
+ pr_debug("%s: no pending writes, drain would block\n",
+ __func__);
+ return -EWOULDBLOCK;
+ }
+
+ atomic_set(&prtd->eos, 1);
+ atomic_set(&prtd->pending_buffer, 0);
+ prtd->cmd_ack = 0;
+ q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ /* Wait indefinitely for DRAIN. Flush can also signal this*/
+ rc = wait_event_interruptible(the_locks.eos_wait,
+ (prtd->cmd_ack || prtd->cmd_interrupt));
+
+ if (rc < 0)
+ pr_err("EOS cmd interrupted\n");
+ pr_debug("%s: SNDRV_COMPRESS_DRAIN out of wait\n", __func__);
+
+ if (prtd->cmd_interrupt)
+ rc = -EINTR;
+
+ prtd->cmd_interrupt = 0;
+ return rc;
+ default:
+ break;
+ }
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+#ifdef CONFIG_COMPAT
+struct snd_enc_wma32 {
+ u32 super_block_align; /* WMA Type-specific data */
+ u32 encodeopt1;
+ u32 encodeopt2;
+};
+
+struct snd_enc_vorbis32 {
+ s32 quality;
+ u32 managed;
+ u32 max_bit_rate;
+ u32 min_bit_rate;
+ u32 downmix;
+};
+
+struct snd_enc_real32 {
+ u32 quant_bits;
+ u32 start_region;
+ u32 num_regions;
+};
+
+struct snd_enc_flac32 {
+ u32 num;
+ u32 gain;
+};
+
+struct snd_enc_generic32 {
+ u32 bw; /* encoder bandwidth */
+ s32 reserved[15];
+};
+struct snd_dec_ddp32 {
+ u32 params_length;
+ u32 params_id[18];
+ u32 params_value[18];
+};
+
+union snd_codec_options32 {
+ struct snd_enc_wma32 wma;
+ struct snd_enc_vorbis32 vorbis;
+ struct snd_enc_real32 real;
+ struct snd_enc_flac32 flac;
+ struct snd_enc_generic32 generic;
+ struct snd_dec_ddp32 ddp;
+};
+
+struct snd_codec32 {
+ u32 id;
+ u32 ch_in;
+ u32 ch_out;
+ u32 sample_rate;
+ u32 bit_rate;
+ u32 rate_control;
+ u32 profile;
+ u32 level;
+ u32 ch_mode;
+ u32 format;
+ u32 align;
+ union snd_codec_options32 options;
+ u32 reserved[3];
+};
+
+struct snd_compressed_buffer32 {
+ u32 fragment_size;
+ u32 fragments;
+};
+
+struct snd_compr_params32 {
+ struct snd_compressed_buffer32 buffer;
+ struct snd_codec32 codec;
+ u8 no_wake_mode;
+};
+
+struct snd_compr_caps32 {
+ u32 num_codecs;
+ u32 direction;
+ u32 min_fragment_size;
+ u32 max_fragment_size;
+ u32 min_fragments;
+ u32 max_fragments;
+ u32 codecs[MAX_NUM_CODECS];
+ u32 reserved[11];
+};
+struct snd_compr_tstamp32 {
+ u32 byte_offset;
+ u32 copied_total;
+ compat_ulong_t pcm_frames;
+ compat_ulong_t pcm_io_frames;
+ u32 sampling_rate;
+ compat_u64 timestamp;
+};
+enum {
+ SNDRV_COMPRESS_TSTAMP32 = _IOR('C', 0x20, struct snd_compr_tstamp32),
+ SNDRV_COMPRESS_GET_CAPS32 = _IOWR('C', 0x10, struct snd_compr_caps32),
+ SNDRV_COMPRESS_SET_PARAMS32 =
+ _IOW('C', 0x12, struct snd_compr_params32),
+};
+static int msm_compr_compat_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ int err = 0;
+
+ switch (cmd) {
+ case SNDRV_COMPRESS_TSTAMP32: {
+ struct snd_compr_tstamp tstamp;
+ struct snd_compr_tstamp32 tstamp32;
+
+ memset(&tstamp, 0, sizeof(tstamp));
+ memset(&tstamp32, 0, sizeof(tstamp32));
+ cmd = SNDRV_COMPRESS_TSTAMP;
+ err = msm_compr_ioctl_shared(substream, cmd, &tstamp);
+ if (err) {
+ pr_err("%s: COMPRESS_TSTAMP failed rc %d\n",
+ __func__, err);
+ goto bail_out;
+ }
+ tstamp32.byte_offset = tstamp.byte_offset;
+ tstamp32.copied_total = tstamp.copied_total;
+ tstamp32.pcm_frames = tstamp.pcm_frames;
+ tstamp32.pcm_io_frames = tstamp.pcm_io_frames;
+ tstamp32.sampling_rate = tstamp.sampling_rate;
+ tstamp32.timestamp = tstamp.timestamp;
+ if (copy_to_user(arg, &tstamp32, sizeof(tstamp32))) {
+ pr_err("%s: copytouser failed COMPRESS_TSTAMP32\n",
+ __func__);
+ err = -EFAULT;
+ }
+ break;
+ }
+ case SNDRV_COMPRESS_GET_CAPS32: {
+ struct snd_compr_caps caps;
+ struct snd_compr_caps32 caps32;
+ u32 i;
+
+ memset(&caps, 0, sizeof(caps));
+ memset(&caps32, 0, sizeof(caps32));
+ cmd = SNDRV_COMPRESS_GET_CAPS;
+ err = msm_compr_ioctl_shared(substream, cmd, &caps);
+ if (err) {
+ pr_err("%s: GET_CAPS failed rc %d\n",
+ __func__, err);
+ goto bail_out;
+ }
+ pr_debug("SNDRV_COMPRESS_GET_CAPS_32\n");
+ if (!err && caps.num_codecs >= MAX_NUM_CODECS) {
+ pr_err("%s: Invalid number of codecs\n", __func__);
+ err = -EINVAL;
+ goto bail_out;
+ }
+ caps32.direction = caps.direction;
+ caps32.max_fragment_size = caps.max_fragment_size;
+ caps32.max_fragments = caps.max_fragments;
+ caps32.min_fragment_size = caps.min_fragment_size;
+ caps32.num_codecs = caps.num_codecs;
+ for (i = 0; i < caps.num_codecs; i++)
+ caps32.codecs[i] = caps.codecs[i];
+ if (copy_to_user(arg, &caps32, sizeof(caps32))) {
+ pr_err("%s: copytouser failed COMPRESS_GETCAPS32\n",
+ __func__);
+ err = -EFAULT;
+ }
+ break;
+ }
+ case SNDRV_COMPRESS_SET_PARAMS32: {
+ struct snd_compr_params32 params32;
+ struct snd_compr_params params;
+
+ memset(¶ms32, 0, sizeof(params32));
+ memset(¶ms, 0, sizeof(params));
+ cmd = SNDRV_COMPRESS_SET_PARAMS;
+ if (copy_from_user(¶ms32, arg, sizeof(params32))) {
+ pr_err("%s: copyfromuser failed SET_PARAMS32\n",
+ __func__);
+ err = -EFAULT;
+ goto bail_out;
+ }
+ params.no_wake_mode = params32.no_wake_mode;
+ params.codec.id = params32.codec.id;
+ params.codec.ch_in = params32.codec.ch_in;
+ params.codec.ch_out = params32.codec.ch_out;
+ params.codec.sample_rate = params32.codec.sample_rate;
+ params.codec.bit_rate = params32.codec.bit_rate;
+ params.codec.rate_control = params32.codec.rate_control;
+ params.codec.profile = params32.codec.profile;
+ params.codec.level = params32.codec.level;
+ params.codec.ch_mode = params32.codec.ch_mode;
+ params.codec.format = params32.codec.format;
+ params.codec.align = params32.codec.align;
+
+ switch (params.codec.id) {
+ case SND_AUDIOCODEC_WMA:
+ case SND_AUDIOCODEC_WMA_PRO:
+ params.codec.options.wma.encodeopt1 =
+ params32.codec.options.wma.encodeopt1;
+ params.codec.options.wma.encodeopt2 =
+ params32.codec.options.wma.encodeopt2;
+ params.codec.options.wma.super_block_align =
+ params32.codec.options.wma.super_block_align;
+ break;
+ case SND_AUDIOCODEC_VORBIS:
+ params.codec.options.vorbis.downmix =
+ params32.codec.options.vorbis.downmix;
+ params.codec.options.vorbis.managed =
+ params32.codec.options.vorbis.managed;
+ params.codec.options.vorbis.max_bit_rate =
+ params32.codec.options.vorbis.max_bit_rate;
+ params.codec.options.vorbis.min_bit_rate =
+ params32.codec.options.vorbis.min_bit_rate;
+ params.codec.options.vorbis.quality =
+ params32.codec.options.vorbis.quality;
+ break;
+ case SND_AUDIOCODEC_REAL:
+ params.codec.options.real.num_regions =
+ params32.codec.options.real.num_regions;
+ params.codec.options.real.quant_bits =
+ params32.codec.options.real.quant_bits;
+ params.codec.options.real.start_region =
+ params32.codec.options.real.start_region;
+ break;
+ case SND_AUDIOCODEC_FLAC:
+ params.codec.options.flac.gain =
+ params32.codec.options.flac.gain;
+ params.codec.options.flac.num =
+ params32.codec.options.flac.num;
+ break;
+ case SND_AUDIOCODEC_DTS:
+ case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+ case SND_AUDIOCODEC_DTS_LBR:
+ case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
+ case SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK:
+ break;
+ case SND_AUDIOCODEC_AC3:
+ case SND_AUDIOCODEC_EAC3:
+ params.codec.options.ddp.params_length =
+ params32.codec.options.ddp.params_length;
+ memcpy(params.codec.options.ddp.params_value,
+ params32.codec.options.ddp.params_value,
+ sizeof(params32.codec.options.ddp.params_value));
+ memcpy(params.codec.options.ddp.params_id,
+ params32.codec.options.ddp.params_id,
+ sizeof(params32.codec.options.ddp.params_id));
+ break;
+ default:
+ params.codec.options.generic.bw =
+ params32.codec.options.generic.bw;
+ break;
+ }
+ if (!err)
+ err = msm_compr_ioctl_shared(substream, cmd, ¶ms);
+ break;
+ }
+ default:
+ err = msm_compr_ioctl_shared(substream, cmd, arg);
+ }
+bail_out:
+ return err;
+
+}
+#endif
+static int msm_compr_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ int err = 0;
+
+ if (!substream) {
+ pr_err("%s: Invalid params\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s called with cmd = %d\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_COMPRESS_TSTAMP: {
+ struct snd_compr_tstamp tstamp;
+
+ if (!arg) {
+ pr_err("%s: Invalid params Tstamp\n", __func__);
+ return -EINVAL;
+ }
+ err = msm_compr_ioctl_shared(substream, cmd, &tstamp);
+ if (err)
+ pr_err("%s: COMPRESS_TSTAMP failed rc %d\n",
+ __func__, err);
+ if (!err && copy_to_user(arg, &tstamp, sizeof(tstamp))) {
+ pr_err("%s: copytouser failed COMPRESS_TSTAMP\n",
+ __func__);
+ err = -EFAULT;
+ }
+ break;
+ }
+ case SNDRV_COMPRESS_GET_CAPS: {
+ struct snd_compr_caps cap;
+
+ if (!arg) {
+ pr_err("%s: Invalid params getcaps\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
+ err = msm_compr_ioctl_shared(substream, cmd, &cap);
+ if (err)
+ pr_err("%s: GET_CAPS failed rc %d\n",
+ __func__, err);
+ if (!err && copy_to_user(arg, &cap, sizeof(cap))) {
+ pr_err("%s: copytouser failed GET_CAPS\n",
+ __func__);
+ err = -EFAULT;
+ }
+ break;
+ }
+ case SNDRV_COMPRESS_SET_PARAMS: {
+ struct snd_compr_params params;
+
+ if (!arg) {
+ pr_err("%s: Invalid params setparam\n", __func__);
+ return -EINVAL;
+ }
+ if (copy_from_user(¶ms, arg,
+ sizeof(struct snd_compr_params))) {
+ pr_err("%s: SET_PARAMS\n", __func__);
+ return -EFAULT;
+ }
+ err = msm_compr_ioctl_shared(substream, cmd, ¶ms);
+ if (err)
+ pr_err("%s: SET_PARAMS failed rc %d\n",
+ __func__, err);
+ break;
+ }
+ default:
+ err = msm_compr_ioctl_shared(substream, cmd, arg);
+ }
+ return err;
+}
+
+static int msm_compr_restart(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct audio_aio_write_param param;
+ struct audio_buffer *buf = NULL;
+ struct output_meta_data_st output_meta_data;
+ int time_stamp_flag = 0;
+ int buffer_length = 0;
+
+ pr_debug("%s, trigger restart\n", __func__);
+
+ if (runtime->render_flag & SNDRV_RENDER_STOPPED) {
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+ __func__, prtd->out_head,
+ ((unsigned int)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)));
+
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+ time_stamp_flag = SET_TIMESTAMP;
+ else
+ time_stamp_flag = NO_TIMESTAMP;
+ memcpy(&output_meta_data, (char *)(buf->data +
+ prtd->out_head * prtd->pcm_count),
+ COMPRE_OUTPUT_METADATA_SIZE);
+
+ buffer_length = output_meta_data.frame_size;
+ pr_debug("meta_data_length: %d, frame_length: %d\n",
+ output_meta_data.meta_data_length,
+ output_meta_data.frame_size);
+ pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+ output_meta_data.timestamp_msw,
+ output_meta_data.timestamp_lsw);
+
+ param.paddr = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)
+ + output_meta_data.meta_data_length;
+ param.len = buffer_length;
+ param.msw_ts = output_meta_data.timestamp_msw;
+ param.lsw_ts = output_meta_data.timestamp_lsw;
+ param.flags = time_stamp_flag;
+ param.uid = prtd->session_id;
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1) & (runtime->periods - 1);
+
+ runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
+ return 0;
+ }
+ return 0;
+}
+
+static int msm_compr_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+ int volume = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: volume : %x\n", __func__, volume);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ rc = compressed_set_volume(prtd, volume);
+
+ return rc;
+}
+
+static int msm_compr_volume_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s\n", __func__);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->volume;
+ return 0;
+}
+
+static int msm_compr_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+
+ dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0)
+ return ret;
+ kctl = volume_info->kctl;
+ kctl->put = msm_compr_volume_ctl_put;
+ kctl->get = msm_compr_volume_ctl_get;
+ kctl->tlv.p = compr_rx_vol_gain;
+ return 0;
+}
+
+static struct snd_pcm_ops msm_compr_ops = {
+ .open = msm_compr_open,
+ .hw_params = msm_compr_hw_params,
+ .close = msm_compr_close,
+ .ioctl = msm_compr_ioctl,
+ .prepare = msm_compr_prepare,
+ .trigger = msm_compr_trigger,
+ .pointer = msm_compr_pointer,
+ .mmap = msm_compr_mmap,
+ .restart = msm_compr_restart,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = msm_compr_compat_ioctl,
+#endif
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_compr_add_controls(rtd);
+ if (ret)
+ pr_err("%s, kctl add failed\n", __func__);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_compr_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static int msm_compr_probe(struct platform_device *pdev)
+{
+
+ dev_info(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_compr_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_compr_dt_match[] = {
+ {.compatible = "qcom,msm-compr-dsp"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_compr_dt_match);
+
+static struct platform_driver msm_compr_driver = {
+ .driver = {
+ .name = "msm-compr-dsp",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_compr_dt_match,
+ },
+ .probe = msm_compr_probe,
+ .remove = msm_compr_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ init_waitqueue_head(&the_locks.enable_wait);
+ init_waitqueue_head(&the_locks.eos_wait);
+ init_waitqueue_head(&the_locks.write_wait);
+ init_waitqueue_head(&the_locks.read_wait);
+ init_waitqueue_head(&the_locks.flush_wait);
+
+ return platform_driver_register(&msm_compr_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_compr_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
new file mode 100644
index 0000000..d6e3ec6
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_COMPR_H
+#define _MSM_COMPR_H
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+
+#include "msm-pcm-q6-v2.h"
+
+struct compr_info {
+ struct snd_compr_caps compr_cap;
+ struct snd_compr_codec_caps codec_caps;
+ struct snd_compr_params codec_param;
+};
+
+struct compr_audio {
+ struct msm_audio prtd;
+ struct compr_info info;
+ uint32_t codec;
+};
+
+#endif /*_MSM_COMPR_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 1ceb006..61605df 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -55,6 +55,10 @@
#define DSP_NUM_OUTPUT_FRAME_BUFFERED 2
#define FLAC_BLK_SIZE_LIMIT 65535
+/* Timestamp mode payload offsets */
+#define TS_LSW_OFFSET 6
+#define TS_MSW_OFFSET 7
+
/* decoder parameter length */
#define DDP_DEC_MAX_NUM_PARAM 18
@@ -68,12 +72,6 @@
const DECLARE_TLV_DB_LINEAR(msm_compr_vol_gain, 0,
COMPRESSED_LR_VOL_MAX_STEPS);
-/*
- * LSB 8 bits is used as stream id for some DSP
- * commands for compressed playback.
- */
-#define STREAM_ID_FROM_TOKEN(i) (i & 0xFF)
-
/* Stream id switches between 1 and 2 */
#define NEXT_STREAM_ID(stream_id) ((stream_id & 1) + 1)
@@ -102,7 +100,7 @@
static unsigned int supported_sample_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000,
- 88200, 96000, 176400, 192000
+ 88200, 96000, 176400, 192000, 352800, 384000, 2822400, 5644800
};
struct msm_compr_pdata {
@@ -110,6 +108,7 @@
uint32_t volume[MSM_FRONTEND_DAI_MAX][2]; /* For both L & R */
struct msm_compr_audio_effects *audio_effects[MSM_FRONTEND_DAI_MAX];
bool use_dsp_gapless_mode;
+ bool use_legacy_api; /* indicates use older asm apis*/
struct msm_compr_dec_params *dec_params[MSM_FRONTEND_DAI_MAX];
struct msm_compr_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
};
@@ -132,6 +131,13 @@
uint64_t bytes_received; /* from userspace */
uint64_t bytes_sent; /* to DSP */
+ uint64_t received_total; /* bytes received from DSP */
+ uint64_t bytes_copied; /* to userspace */
+ uint64_t bytes_read; /* from DSP */
+ uint32_t bytes_read_offset; /* bytes read offset */
+
+ uint32_t ts_header_offset; /* holds the timestamp header offset */
+
int32_t first_buffer;
int32_t last_buffer;
int32_t partial_drain_delay;
@@ -174,7 +180,9 @@
spinlock_t lock;
};
-const u32 compr_codecs[] = {SND_AUDIOCODEC_AC3, SND_AUDIOCODEC_EAC3};
+const u32 compr_codecs[] = {
+ SND_AUDIOCODEC_AC3, SND_AUDIOCODEC_EAC3, SND_AUDIOCODEC_DTS,
+ SND_AUDIOCODEC_DSD};
struct query_audio_effect {
uint32_t mod_id;
@@ -211,7 +219,7 @@
uint32_t volume_l, uint32_t volume_r)
{
struct msm_compr_audio *prtd;
- int rc = 0, i;
+ int rc = 0;
uint32_t avg_vol, gain_list[VOLUME_CONTROL_MAX_CHANNELS];
uint32_t num_channels;
struct snd_soc_pcm_runtime *rtd;
@@ -255,9 +263,7 @@
*
*/
avg_vol = (volume_l + volume_r) / 2;
- for (i = 0; i < prtd->num_channels; i++)
- gain_list[i] = avg_vol;
-
+ rc = q6asm_set_volume(prtd->audio_client, avg_vol);
} else {
gain_list[0] = volume_l;
gain_list[1] = volume_r;
@@ -267,11 +273,10 @@
num_channels = 3;
use_default = true;
}
+ rc = q6asm_set_multich_gain(prtd->audio_client, num_channels,
+ gain_list, chmap, use_default);
}
- rc = q6asm_set_multich_gain(prtd->audio_client, num_channels,
- gain_list, chmap, use_default);
-
if (rc < 0)
pr_err("%s: Send vol gain command failed rc=%d\n",
__func__, rc);
@@ -370,6 +375,53 @@
return 0;
}
+static int msm_compr_read_buffer(struct msm_compr_audio *prtd)
+{
+ int buffer_length;
+ uint64_t bytes_available;
+ uint64_t buffer_sent;
+ struct audio_aio_read_param param;
+ int ret;
+
+ if (!atomic_read(&prtd->start)) {
+ pr_err("%s: stream is not in started state\n", __func__);
+ return -EINVAL;
+ }
+
+ buffer_length = prtd->codec_param.buffer.fragment_size -
+ prtd->ts_header_offset;
+ bytes_available = prtd->received_total - prtd->bytes_copied;
+ buffer_sent = prtd->bytes_read - prtd->bytes_copied;
+ if (buffer_sent + buffer_length + prtd->ts_header_offset
+ > prtd->buffer_size) {
+ pr_debug(" %s : Buffer is Full bytes_available: %llu\n",
+ __func__, bytes_available);
+ return 0;
+ }
+
+ memset(¶m, 0x0, sizeof(struct audio_aio_read_param));
+ param.paddr = prtd->buffer_paddr + prtd->bytes_read_offset +
+ prtd->ts_header_offset;
+ param.len = buffer_length;
+ param.uid = buffer_length;
+ param.flags = prtd->codec_param.codec.flags;
+
+ pr_debug("%s: reading %d bytes from DSP byte_offset = %llu\n",
+ __func__, buffer_length, prtd->bytes_read);
+ ret = q6asm_async_read(prtd->audio_client, ¶m);
+ if (ret < 0) {
+ pr_err("%s: q6asm_async_read failed - %d\n",
+ __func__, ret);
+ return ret;
+ }
+ prtd->bytes_read += buffer_length;
+ prtd->bytes_read_offset += buffer_length;
+ if (prtd->bytes_read_offset >= prtd->buffer_size)
+ prtd->bytes_read_offset -= prtd->buffer_size;
+
+ return 0;
+}
+
static void compr_event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -382,6 +434,8 @@
int stream_id;
uint32_t stream_index;
unsigned long flags;
+ uint64_t read_size;
+ uint32_t *buff_addr;
if (!prtd) {
pr_err("%s: prtd is NULL\n", __func__);
@@ -390,6 +444,12 @@
cstream = prtd->cstream;
ac = prtd->audio_client;
+ /*
+ * Token for rest of the compressed commands use to set
+ * session id, stream id, dir etc.
+ */
+ stream_id = q6asm_get_stream_id_from_token(token);
+
pr_debug("%s opcode =%08x\n", __func__, opcode);
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2:
@@ -417,6 +477,12 @@
prtd->byte_offset, token);
}
+ /*
+ * Token for WRITE command represents the amount of data
+ * written to ADSP in the last write, update offset and
+ * total copied data accordingly.
+ */
+
prtd->byte_offset += token;
prtd->copied_total += token;
if (prtd->byte_offset >= prtd->buffer_size)
@@ -455,11 +521,53 @@
spin_unlock_irqrestore(&prtd->lock, flags);
break;
+
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ pr_debug("ASM_DATA_EVENT_READ_DONE_V2 offset %d, length %d\n",
+ prtd->byte_offset, payload[4]);
+
+ if (prtd->ts_header_offset) {
+ /* Update the header for received buffer */
+ buff_addr = prtd->buffer + prtd->byte_offset;
+ /* Write the length of the buffer */
+ *buff_addr = prtd->codec_param.buffer.fragment_size
+ - prtd->ts_header_offset;
+ buff_addr++;
+ /* Write the offset */
+ *buff_addr = prtd->ts_header_offset;
+ buff_addr++;
+ /* Write the TS LSW */
+ *buff_addr = payload[TS_LSW_OFFSET];
+ buff_addr++;
+ /* Write the TS MSW */
+ *buff_addr = payload[TS_MSW_OFFSET];
+ }
+ /* Always assume read_size is same as fragment_size */
+ read_size = prtd->codec_param.buffer.fragment_size;
+ prtd->byte_offset += read_size;
+ prtd->received_total += read_size;
+ if (prtd->byte_offset >= prtd->buffer_size)
+ prtd->byte_offset -= prtd->buffer_size;
+
+ snd_compr_fragment_elapsed(cstream);
+
+ if (!atomic_read(&prtd->start)) {
+ pr_debug("read_done received while not started, treat as xrun");
+ atomic_set(&prtd->xrun, 1);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+ msm_compr_read_buffer(prtd);
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
case ASM_DATA_EVENT_RENDERED_EOS:
spin_lock_irqsave(&prtd->lock, flags);
pr_debug("%s: ASM_DATA_CMDRSP_EOS token 0x%x,stream id %d\n",
- __func__, token, STREAM_ID_FROM_TOKEN(token));
- stream_id = STREAM_ID_FROM_TOKEN(token);
+ __func__, token, stream_id);
if (atomic_read(&prtd->eos) &&
!prtd->gapless_state.set_next_stream_id) {
pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
@@ -509,6 +617,14 @@
/* FIXME: A state is a better way, dealing with this */
spin_lock_irqsave(&prtd->lock, flags);
+
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ atomic_set(&prtd->start, 1);
+ msm_compr_read_buffer(prtd);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
if (!prtd->bytes_sent) {
bytes_available = prtd->bytes_received -
prtd->copied_total;
@@ -547,25 +663,25 @@
case ASM_STREAM_CMD_FLUSH:
pr_debug("%s: ASM_STREAM_CMD_FLUSH:", __func__);
pr_debug("token 0x%x, stream id %d\n", token,
- STREAM_ID_FROM_TOKEN(token));
+ stream_id);
prtd->cmd_ack = 1;
break;
case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
pr_debug("%s: ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:",
__func__);
pr_debug("token 0x%x, stream id = %d\n", token,
- STREAM_ID_FROM_TOKEN(token));
+ stream_id);
break;
case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
pr_debug("%s: ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:",
__func__);
pr_debug("token = 0x%x, stream id = %d\n", token,
- STREAM_ID_FROM_TOKEN(token));
+ stream_id);
break;
case ASM_STREAM_CMD_CLOSE:
pr_debug("%s: ASM_DATA_CMD_CLOSE:", __func__);
pr_debug("token 0x%x, stream id %d\n", token,
- STREAM_ID_FROM_TOKEN(token));
+ stream_id);
/*
* wakeup wait for stream avail on stream 3
* after stream 1 ends.
@@ -597,8 +713,12 @@
pr_err("%s: Received reset events CB, move to error state",
__func__);
spin_lock_irqsave(&prtd->lock, flags);
- snd_compr_fragment_elapsed(cstream);
+ /*
+ * Since ADSP is down, let this driver pretend that it copied
+ * all the bytes received, so that next write will be triggered
+ */
prtd->copied_total = prtd->bytes_received;
+ snd_compr_fragment_elapsed(cstream);
atomic_set(&prtd->error, 1);
wake_up(&prtd->drain_wait);
if (atomic_cmpxchg(&prtd->eos, 1, 0)) {
@@ -623,7 +743,8 @@
delay_time_ms = delay_time_ms > PARTIAL_DRAIN_ACK_EARLY_BY_MSEC ?
delay_time_ms - PARTIAL_DRAIN_ACK_EARLY_BY_MSEC : 0;
- pr_debug("%s: partial drain delay %d\n", __func__, delay_time_ms);
+ pr_debug("%s: frame_sz %d, sample_rate %d, partial drain delay %d\n",
+ __func__, frame_sz, sample_rate, delay_time_ms);
return delay_time_ms;
}
@@ -639,7 +760,7 @@
COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
prtd->compr_cap.max_fragments =
COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
- prtd->compr_cap.num_codecs = 12;
+ prtd->compr_cap.num_codecs = 14;
prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
@@ -652,6 +773,8 @@
prtd->compr_cap.codecs[9] = SND_AUDIOCODEC_VORBIS;
prtd->compr_cap.codecs[10] = SND_AUDIOCODEC_ALAC;
prtd->compr_cap.codecs[11] = SND_AUDIOCODEC_APE;
+ prtd->compr_cap.codecs[12] = SND_AUDIOCODEC_DTS;
+ prtd->compr_cap.codecs[13] = SND_AUDIOCODEC_DSD;
}
static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -670,12 +793,14 @@
struct asm_vorbis_cfg vorbis_cfg;
struct asm_alac_cfg alac_cfg;
struct asm_ape_cfg ape_cfg;
+ struct asm_dsd_cfg dsd_cfg;
union snd_codec_options *codec_options;
int ret = 0;
- uint16_t bit_width = 16;
+ uint16_t bit_width;
bool use_default_chmap = true;
char *chmap = NULL;
+ uint16_t sample_word_size;
pr_debug("%s: use_gapless_codec_options %d\n",
__func__, use_gapless_codec_options);
@@ -699,15 +824,36 @@
chmap =
pdata->ch_map[rtd->dai_link->be_id]->channel_map;
}
- if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE)
+
+ switch (prtd->codec_param.codec.format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bit_width = 32;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
bit_width = 24;
- ret = q6asm_media_format_block_pcm_format_support_v2(
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bit_width = 24;
+ sample_word_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_width = 16;
+ sample_word_size = 16;
+ break;
+ }
+ ret = q6asm_media_format_block_pcm_format_support_v4(
prtd->audio_client,
prtd->sample_rate,
prtd->num_channels,
bit_width, stream_id,
use_default_chmap,
- chmap);
+ chmap,
+ sample_word_size,
+ ASM_LITTLE_ENDIAN,
+ DEFAULT_QF);
if (ret < 0)
pr_err("%s: CMD Format block failed\n", __func__);
@@ -861,7 +1007,24 @@
pr_err("%s: CMD Format block failed ret %d\n",
__func__, ret);
break;
-
+ case FORMAT_DTS:
+ pr_debug("SND_AUDIOCODEC_DTS\n");
+ /* no media format block needed */
+ break;
+ case FORMAT_DSD:
+ pr_debug("%s: SND_AUDIOCODEC_DSD\n", __func__);
+ memset(&dsd_cfg, 0x0, sizeof(struct asm_dsd_cfg));
+ dsd_cfg.num_channels = prtd->num_channels;
+ dsd_cfg.dsd_data_rate = prtd->sample_rate;
+ dsd_cfg.num_version = 0;
+ dsd_cfg.is_bitwise_big_endian = 1;
+ dsd_cfg.dsd_channel_block_size = 1;
+ ret = q6asm_media_format_block_dsd(prtd->audio_client,
+ &dsd_cfg, stream_id);
+ if (ret < 0)
+ pr_err("%s: CMD DSD Format block failed ret %d\n",
+ __func__, ret);
+ break;
default:
pr_debug("%s, unsupported format, skip", __func__);
break;
@@ -912,7 +1075,8 @@
return ret;
}
-static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
+static int msm_compr_configure_dsp_for_playback
+ (struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
@@ -934,7 +1098,14 @@
};
pr_debug("%s: stream_id %d\n", __func__, ac->stream_id);
- if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE)
+ stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
+ if (stream_index >= MAX_NUMBER_OF_STREAMS || stream_index < 0) {
+ pr_err("%s: Invalid stream index:%d", __func__, stream_index);
+ return -EINVAL;
+ }
+
+ if ((prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE) ||
+ (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_3LE))
bits_per_sample = 24;
else if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S32_LE)
bits_per_sample = 32;
@@ -947,6 +1118,8 @@
__func__, ret, prtd->compr_passthr);
return ret;
}
+ prtd->gapless_state.stream_opened[stream_index] = 1;
+
ret = msm_pcm_routing_reg_phy_compr_stream(
soc_prtd->dai_link->be_id,
ac->perf_mode,
@@ -961,7 +1134,7 @@
} else {
pr_debug("%s: stream_id %d bits_per_sample %d\n",
__func__, ac->stream_id, bits_per_sample);
- ret = q6asm_stream_open_write_v2(ac,
+ ret = q6asm_stream_open_write_v4(ac,
prtd->codec, bits_per_sample,
ac->stream_id,
prtd->gapless_state.use_dsp_gapless_mode);
@@ -970,6 +1143,7 @@
__func__, ret, prtd->compr_passthr);
return -ENOMEM;
}
+ prtd->gapless_state.stream_opened[stream_index] = 1;
pr_debug("%s: be_id %d\n", __func__, soc_prtd->dai_link->be_id);
ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
@@ -986,31 +1160,30 @@
if (ret < 0)
pr_err("%s : Set Volume failed : %d", __func__, ret);
- ret = q6asm_send_cal(ac);
- if (ret < 0)
- pr_debug("%s : Send cal failed : %d", __func__, ret);
+ if (prtd->compr_passthr != LEGACY_PCM) {
+ pr_debug("%s : Don't send cal and PP params for compress path",
+ __func__);
+ } else {
+ ret = q6asm_send_cal(ac);
+ if (ret < 0)
+ pr_debug("%s : Send cal failed : %d", __func__, ret);
- ret = q6asm_set_softpause(ac, &softpause);
- if (ret < 0)
- pr_err("%s: Send SoftPause Param failed ret=%d\n",
- __func__, ret);
- ret = q6asm_set_softvolume(ac, &softvol);
- if (ret < 0)
- pr_err("%s: Send SoftVolume Param failed ret=%d\n",
- __func__, ret);
+ ret = q6asm_set_softpause(ac, &softpause);
+ if (ret < 0)
+ pr_err("%s: Send SoftPause Param failed ret=%d\n",
+ __func__, ret);
+ ret = q6asm_set_softvolume(ac, &softvol);
+ if (ret < 0)
+ pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+ __func__, ret);
+ }
ret = q6asm_set_io_mode(ac, (COMPRESSED_STREAM_IO | ASYNC_IO_MODE));
if (ret < 0) {
pr_err("%s: Set IO mode failed\n", __func__);
return -EINVAL;
}
- stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
- if (stream_index >= MAX_NUMBER_OF_STREAMS || stream_index < 0) {
- pr_err("%s: Invalid stream index:%d", __func__, stream_index);
- return -EINVAL;
- }
- prtd->gapless_state.stream_opened[stream_index] = 1;
runtime->fragments = prtd->codec_param.buffer.fragments;
runtime->fragment_size = prtd->codec_param.buffer.fragment_size;
pr_debug("allocate %d buffers each of size %d\n",
@@ -1040,7 +1213,108 @@
return ret;
}
-static int msm_compr_open(struct snd_compr_stream *cstream)
+static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_compr_audio *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
+ uint16_t bits_per_sample;
+ uint16_t sample_word_size;
+ int dir = OUT, ret = 0;
+ struct audio_client *ac = prtd->audio_client;
+ uint32_t stream_index;
+
+ switch (prtd->codec_param.codec.format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bits_per_sample = 24;
+ sample_word_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bits_per_sample = 32;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bits_per_sample = 16;
+ sample_word_size = 16;
+ break;
+ }
+
+ pr_debug("%s: stream_id %d bits_per_sample %d\n",
+ __func__, ac->stream_id, bits_per_sample);
+
+ ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
+ bits_per_sample);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ ac->perf_mode,
+ prtd->session_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret) {
+ pr_err("%s: stream reg failed:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = q6asm_set_io_mode(ac, (COMPRESSED_STREAM_IO | ASYNC_IO_MODE));
+ if (ret < 0) {
+ pr_err("%s: Set IO mode failed\n", __func__);
+ return -EINVAL;
+ }
+
+ stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
+ if (stream_index >= MAX_NUMBER_OF_STREAMS || stream_index < 0) {
+ pr_err("%s: Invalid stream index:%d", __func__, stream_index);
+ return -EINVAL;
+ }
+
+ runtime->fragments = prtd->codec_param.buffer.fragments;
+ runtime->fragment_size = prtd->codec_param.buffer.fragment_size;
+ pr_debug("%s: allocate %d buffers each of size %d\n",
+ __func__, runtime->fragments,
+ runtime->fragment_size);
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac,
+ runtime->fragment_size,
+ runtime->fragments);
+ if (ret < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+ return -ENOMEM;
+ }
+
+ prtd->byte_offset = 0;
+ prtd->received_total = 0;
+ prtd->app_pointer = 0;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->buffer = ac->port[dir].buf[0].data;
+ prtd->buffer_paddr = ac->port[dir].buf[0].phys;
+ prtd->buffer_size = runtime->fragments * runtime->fragment_size;
+
+ /* Bit-0 of flags represent timestamp mode */
+ if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG)
+ prtd->ts_header_offset = sizeof(struct snd_codec_metadata);
+ else
+ prtd->ts_header_offset = 0;
+
+ pr_debug("%s: sample_rate = %d channels = %d bps = %d sample_word_size = %d\n",
+ __func__, prtd->sample_rate, prtd->num_channels,
+ bits_per_sample, sample_word_size);
+ ret = q6asm_enc_cfg_blk_pcm_format_support_v3(prtd->audio_client,
+ prtd->sample_rate, prtd->num_channels,
+ bits_per_sample, sample_word_size);
+
+ return ret;
+}
+
+static int msm_compr_playback_open(struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -1076,20 +1350,6 @@
kfree(prtd);
return -ENOMEM;
}
- prtd->audio_client = q6asm_audio_client_alloc(
- (app_cb)compr_event_handler, prtd);
- if (!prtd->audio_client) {
- pr_err("%s: Could not allocate memory for client\n", __func__);
- kfree(pdata->audio_effects[rtd->dai_link->be_id]);
- kfree(pdata->dec_params[rtd->dai_link->be_id]);
- pdata->cstream[rtd->dai_link->be_id] = NULL;
- kfree(prtd);
- return -ENOMEM;
- }
-
- pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
- prtd->audio_client->perf_mode = false;
- prtd->session_id = prtd->audio_client->session;
prtd->codec = FORMAT_MP3;
prtd->bytes_received = 0;
prtd->bytes_sent = 0;
@@ -1128,11 +1388,91 @@
runtime->private_data = prtd;
populate_codec_list(prtd);
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)compr_event_handler, prtd);
+ if (!prtd->audio_client) {
+ pr_err("%s: Could not allocate memory for client\n", __func__);
+ kfree(pdata->audio_effects[rtd->dai_link->be_id]);
+ kfree(pdata->dec_params[rtd->dai_link->be_id]);
+ pdata->cstream[rtd->dai_link->be_id] = NULL;
+ runtime->private_data = NULL;
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+ prtd->audio_client->perf_mode = false;
+ prtd->session_id = prtd->audio_client->session;
return 0;
}
-static int msm_compr_free(struct snd_compr_stream *cstream)
+static int msm_compr_capture_open(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct msm_compr_audio *prtd;
+ struct msm_compr_pdata *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+
+ pr_debug("%s\n", __func__);
+ prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL);
+ if (prtd == NULL) {
+ pr_err("Failed to allocate memory for msm_compr_audio\n");
+ return -ENOMEM;
+ }
+
+ runtime->private_data = NULL;
+ prtd->cstream = cstream;
+ pdata->cstream[rtd->dai_link->be_id] = cstream;
+
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)compr_event_handler, prtd);
+ if (!prtd->audio_client) {
+ pr_err("%s: Could not allocate memory for client\n", __func__);
+ pdata->cstream[rtd->dai_link->be_id] = NULL;
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+ prtd->audio_client->perf_mode = false;
+ prtd->session_id = prtd->audio_client->session;
+ prtd->codec = FORMAT_LINEAR_PCM;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->received_total = 0;
+ prtd->byte_offset = 0;
+ prtd->sample_rate = 48000;
+ prtd->num_channels = 2;
+ prtd->first_buffer = 0;
+
+ spin_lock_init(&prtd->lock);
+
+ atomic_set(&prtd->eos, 0);
+ atomic_set(&prtd->start, 0);
+ atomic_set(&prtd->drain, 0);
+ atomic_set(&prtd->xrun, 0);
+ atomic_set(&prtd->close, 0);
+ atomic_set(&prtd->wait_on_close, 0);
+ atomic_set(&prtd->error, 0);
+
+ runtime->private_data = prtd;
+
+ return 0;
+}
+
+static int msm_compr_open(struct snd_compr_stream *cstream)
+{
+ int ret = 0;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_open(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_open(cstream);
+ return ret;
+}
+
+static int msm_compr_playback_free(struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime;
struct msm_compr_audio *prtd;
@@ -1227,6 +1567,76 @@
return 0;
}
+static int msm_compr_capture_free(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime;
+ struct msm_compr_audio *prtd;
+ struct snd_soc_pcm_runtime *soc_prtd;
+ struct msm_compr_pdata *pdata;
+ struct audio_client *ac;
+ int dir = OUT, stream_id;
+ unsigned long flags;
+ uint32_t stream_index;
+
+ if (!cstream) {
+ pr_err("%s cstream is null\n", __func__);
+ return 0;
+ }
+ runtime = cstream->runtime;
+ soc_prtd = cstream->private_data;
+ if (!runtime || !soc_prtd || !(soc_prtd->platform)) {
+ pr_err("%s runtime or soc_prtd or platform is null\n",
+ __func__);
+ return 0;
+ }
+ prtd = runtime->private_data;
+ if (!prtd) {
+ pr_err("%s prtd is null\n", __func__);
+ return 0;
+ }
+ pdata = snd_soc_platform_get_drvdata(soc_prtd->platform);
+ ac = prtd->audio_client;
+ if (!pdata || !ac) {
+ pr_err("%s pdata or ac is null\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ stream_id = ac->stream_id;
+
+ stream_index = STREAM_ARRAY_INDEX(stream_id);
+ if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0)) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ pr_debug("close stream %d", stream_id);
+ q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
+ spin_lock_irqsave(&prtd->lock, flags);
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ pdata->cstream[soc_prtd->dai_link->be_id] = NULL;
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+
+ q6asm_audio_client_buf_free_contiguous(dir, ac);
+
+ q6asm_audio_client_free(ac);
+
+ kfree(prtd);
+
+ return 0;
+}
+
+static int msm_compr_free(struct snd_compr_stream *cstream)
+{
+ int ret = 0;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_free(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_free(cstream);
+ return ret;
+}
+
static bool msm_compr_validate_codec_compr(__u32 codec_id)
{
int32_t i;
@@ -1257,8 +1667,14 @@
if (i == num_rates)
return -EINVAL;
- if (prtd->codec_param.codec.compr_passthr >= 0 &&
- prtd->codec_param.codec.compr_passthr <= 2)
+ memcpy(&prtd->codec_param, params, sizeof(struct snd_compr_params));
+ /* ToDo: remove duplicates */
+ prtd->num_channels = prtd->codec_param.codec.ch_in;
+ prtd->sample_rate = prtd->codec_param.codec.sample_rate;
+ pr_debug("%s: sample_rate %d\n", __func__, prtd->sample_rate);
+
+ if (prtd->codec_param.codec.compr_passthr >= LEGACY_PCM &&
+ prtd->codec_param.codec.compr_passthr <= COMPRESSED_PASSTHROUGH_DSD)
prtd->compr_passthr = prtd->codec_param.codec.compr_passthr;
else
prtd->compr_passthr = LEGACY_PCM;
@@ -1363,6 +1779,18 @@
break;
}
+ case SND_AUDIOCODEC_DTS: {
+ pr_debug("%s: SND_AUDIOCODEC_DTS\n", __func__);
+ prtd->codec = FORMAT_DTS;
+ break;
+ }
+
+ case SND_AUDIOCODEC_DSD: {
+ pr_debug("%s: SND_AUDIOCODEC_DSD\n", __func__);
+ prtd->codec = FORMAT_DSD;
+ break;
+ }
+
default:
pr_err("codec not supported, id =%d\n", params->codec.id);
return -EINVAL;
@@ -1374,13 +1802,10 @@
prtd->partial_drain_delay =
msm_compr_get_partial_drain_delay(frame_sz, prtd->sample_rate);
- memcpy(&prtd->codec_param, params, sizeof(struct snd_compr_params));
-
- /* ToDo: remove duplicates */
- prtd->num_channels = prtd->codec_param.codec.ch_in;
- prtd->sample_rate = prtd->codec_param.codec.sample_rate;
- pr_debug("%s: sample_rate %d\n", __func__, prtd->sample_rate);
- ret = msm_compr_configure_dsp(cstream);
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_configure_dsp_for_playback(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_configure_dsp_for_capture(cstream);
return ret;
}
@@ -1471,11 +1896,6 @@
uint32_t stream_index;
uint16_t bits_per_sample = 16;
- if (cstream->direction != SND_COMPRESS_PLAYBACK) {
- pr_err("%s: Unsupported stream type\n", __func__);
- return -EINVAL;
- }
-
spin_lock_irqsave(&prtd->lock, flags);
if (atomic_read(&prtd->error)) {
pr_err("%s Got RESET EVENTS notification, return immediately",
@@ -1490,17 +1910,30 @@
pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
atomic_set(&prtd->start, 1);
- /* set volume for the stream before RUN */
- rc = msm_compr_set_volume(cstream, volume[0], volume[1]);
- if (rc)
- pr_err("%s : Set Volume failed : %d\n",
- __func__, rc);
+ /*
+ * compr_set_volume and compr_init_pp_params
+ * are used to configure ASM volume hence not
+ * needed for compress passthrough playback.
+ *
+ * compress passthrough volume is controlled in
+ * ADM by adm_send_compressed_device_mute()
+ */
+ if (prtd->compr_passthr == LEGACY_PCM &&
+ cstream->direction == SND_COMPRESS_PLAYBACK) {
+ /* set volume for the stream before RUN */
+ rc = msm_compr_set_volume(cstream,
+ volume[0], volume[1]);
+ if (rc)
+ pr_err("%s : Set Volume failed : %d\n",
+ __func__, rc);
- rc = msm_compr_init_pp_params(cstream, ac);
- if (rc)
- pr_err("%s : init PP params failed : %d\n",
- __func__, rc);
-
+ rc = msm_compr_init_pp_params(cstream, ac);
+ if (rc)
+ pr_err("%s : init PP params failed : %d\n",
+ __func__, rc);
+ } else {
+ msm_compr_read_buffer(prtd);
+ }
/* issue RUN command for the stream */
q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
break;
@@ -1510,6 +1943,18 @@
prtd->gapless_state.gapless_transition);
stream_id = ac->stream_id;
atomic_set(&prtd->start, 0);
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->xrun, 0);
+ prtd->received_total = 0;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->byte_offset = 0;
+ prtd->app_pointer = 0;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
if (prtd->next_stream) {
pr_debug("%s: interrupt next track wait queues\n",
__func__);
@@ -1519,8 +1964,15 @@
}
if (atomic_read(&prtd->eos)) {
pr_debug("%s: interrupt eos wait queues", __func__);
- prtd->cmd_interrupt = 1;
- wake_up(&prtd->eos_wait);
+ /*
+ * Gapless playback does not wait for eos, do not set
+ * cmd_int and do not wake up eos_wait during gapless
+ * transition
+ */
+ if (!prtd->gapless_state.gapless_transition) {
+ prtd->cmd_interrupt = 1;
+ wake_up(&prtd->eos_wait);
+ }
atomic_set(&prtd->eos, 0);
}
if (atomic_read(&prtd->drain)) {
@@ -1629,7 +2081,7 @@
if (prtd->last_buffer) {
pr_debug("%s: last buffer drain\n", __func__);
rc = msm_compr_drain_buffer(prtd, &flags);
- if (rc) {
+ if (rc || !atomic_read(&prtd->start)) {
spin_unlock_irqrestore(&prtd->lock,
flags);
break;
@@ -1649,7 +2101,7 @@
/* wait for the zero length buffer to be returned */
pr_debug("%s: zero length buffer drain\n", __func__);
rc = msm_compr_drain_buffer(prtd, &flags);
- if (rc) {
+ if (rc || !atomic_read(&prtd->start)) {
spin_unlock_irqrestore(&prtd->lock, flags);
break;
}
@@ -1683,7 +2135,12 @@
prtd->app_pointer = 0;
prtd->first_buffer = 1;
prtd->last_buffer = 0;
- prtd->gapless_state.gapless_transition = 1;
+ /*
+ * Set gapless transition flag only if EOS hasn't been
+ * acknowledged already.
+ */
+ if (atomic_read(&prtd->eos))
+ prtd->gapless_state.gapless_transition = 1;
prtd->marker_timestamp = 0;
/*
@@ -1707,6 +2164,7 @@
* stream can be used for gapless playback
*/
prtd->gapless_state.set_next_stream_id = false;
+ prtd->gapless_state.gapless_transition = 0;
pr_debug("%s:CMD_EOS stream_id %d\n", __func__, ac->stream_id);
prtd->eos_ack = 0;
@@ -1754,8 +2212,14 @@
/*
* Cache this time as last known time
*/
- q6asm_get_session_time(prtd->audio_client,
- &prtd->marker_timestamp);
+ if (pdata->use_legacy_api)
+ q6asm_get_session_time_legacy(
+ prtd->audio_client,
+ &prtd->marker_timestamp);
+ else
+ q6asm_get_session_time(prtd->audio_client,
+ &prtd->marker_timestamp);
+
spin_lock_irqsave(&prtd->lock, flags);
/*
* Don't reset these as these vars map to
@@ -1851,7 +2315,7 @@
pr_debug("%s: open_write stream_id %d bits_per_sample %d",
__func__, stream_id, bits_per_sample);
- rc = q6asm_stream_open_write_v2(prtd->audio_client,
+ rc = q6asm_stream_open_write_v4(prtd->audio_client,
prtd->codec, bits_per_sample,
stream_id,
prtd->gapless_state.use_dsp_gapless_mode);
@@ -1882,57 +2346,77 @@
}
static int msm_compr_pointer(struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *arg)
+ struct snd_compr_tstamp *arg)
{
struct snd_compr_runtime *runtime = cstream->runtime;
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct msm_compr_audio *prtd = runtime->private_data;
+ struct msm_compr_pdata *pdata = NULL;
struct snd_compr_tstamp tstamp;
uint64_t timestamp = 0;
int rc = 0, first_buffer;
unsigned long flags;
uint32_t gapless_transition;
+ pdata = snd_soc_platform_get_drvdata(rtd->platform);
pr_debug("%s\n", __func__);
memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
spin_lock_irqsave(&prtd->lock, flags);
tstamp.sampling_rate = prtd->sample_rate;
tstamp.byte_offset = prtd->byte_offset;
- tstamp.copied_total = prtd->copied_total;
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ tstamp.copied_total = prtd->copied_total;
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ tstamp.copied_total = prtd->received_total;
first_buffer = prtd->first_buffer;
if (atomic_read(&prtd->error)) {
- pr_err("%s Got RESET EVENTS notification, return error",
+ pr_err("%s Got RESET EVENTS notification, return error\n",
__func__);
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ runtime->total_bytes_transferred = tstamp.copied_total;
+ else
+ runtime->total_bytes_available = tstamp.copied_total;
tstamp.pcm_io_frames = 0;
memcpy(arg, &tstamp, sizeof(struct snd_compr_tstamp));
spin_unlock_irqrestore(&prtd->lock, flags);
return -ENETRESET;
}
+ if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- gapless_transition = prtd->gapless_state.gapless_transition;
- spin_unlock_irqrestore(&prtd->lock, flags);
-
- /*
- * Query timestamp from DSP if some data is with it.
- * This prevents timeouts.
- */
- if (!first_buffer || gapless_transition) {
+ gapless_transition = prtd->gapless_state.gapless_transition;
+ spin_unlock_irqrestore(&prtd->lock, flags);
if (gapless_transition)
pr_debug("%s session time in gapless transition",
- __func__);
+ __func__);
+ /*
+ *- Do not query if no buffer has been given.
+ *- Do not query on a gapless transition.
+ * Playback for the 2nd stream can start (thus returning time
+ * starting from 0) before the driver knows about EOS of first
+ * stream.
+ */
+ if (!first_buffer || gapless_transition) {
- rc = q6asm_get_session_time(prtd->audio_client, ×tamp);
- if (rc < 0) {
- pr_err("%s: Get Session Time return value =%lld\n",
- __func__, timestamp);
- if (atomic_read(&prtd->error))
- return -ENETRESET;
+ if (pdata->use_legacy_api)
+ rc = q6asm_get_session_time_legacy(
+ prtd->audio_client, &prtd->marker_timestamp);
else
- return -EAGAIN;
+ rc = q6asm_get_session_time(
+ prtd->audio_client, &prtd->marker_timestamp);
+ if (rc < 0) {
+ pr_err("%s: Get Session Time return =%lld\n",
+ __func__, timestamp);
+ if (atomic_read(&prtd->error))
+ return -ENETRESET;
+ else
+ return -EAGAIN;
+ }
}
} else {
- timestamp = prtd->marker_timestamp;
+ spin_unlock_irqrestore(&prtd->lock, flags);
}
+ timestamp = prtd->marker_timestamp;
/* DSP returns timestamp in usec */
pr_debug("%s: timestamp = %lld usec\n", __func__, timestamp);
@@ -1991,8 +2475,8 @@
return 0;
}
-static int msm_compr_copy(struct snd_compr_stream *cstream,
- char __user *buf, size_t count)
+static int msm_compr_playback_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
@@ -2055,6 +2539,60 @@
return count;
}
+static int msm_compr_capture_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_compr_audio *prtd = runtime->private_data;
+ void *source;
+ unsigned long flags;
+
+ pr_debug("%s: count = %zd\n", __func__, count);
+ if (!prtd->buffer) {
+ pr_err("%s: Buffer is not allocated yet ??", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (atomic_read(&prtd->error)) {
+ pr_err("%s Got RESET EVENTS notification", __func__);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return -ENETRESET;
+ }
+
+ source = prtd->buffer + prtd->app_pointer;
+ /* check if we have requested amount of data to copy to user*/
+ if (count <= prtd->received_total - prtd->bytes_copied) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ if (copy_to_user(buf, source, count)) {
+ pr_err("copy_to_user failed");
+ return -EFAULT;
+ }
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->app_pointer += count;
+ if (prtd->app_pointer >= prtd->buffer_size)
+ prtd->app_pointer -= prtd->buffer_size;
+ prtd->bytes_copied += count;
+ }
+ msm_compr_read_buffer(prtd);
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return count;
+}
+
+static int msm_compr_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
+{
+ int ret = 0;
+
+ pr_debug(" In %s\n", __func__);
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_copy(cstream, buf, count);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_copy(cstream, buf, count);
+ return ret;
+}
+
static int msm_compr_get_caps(struct snd_compr_stream *cstream,
struct snd_compr_caps *arg)
{
@@ -2067,7 +2605,7 @@
memcpy(arg, &prtd->compr_cap, sizeof(struct snd_compr_caps));
} else {
ret = -EINVAL;
- pr_err("%s: arg (0x%p), prtd (0x%p)\n", __func__, arg, prtd);
+ pr_err("%s: arg (0x%pK), prtd (0x%pK)\n", __func__, arg, prtd);
}
return ret;
@@ -2123,6 +2661,10 @@
break;
case SND_AUDIOCODEC_APE:
break;
+ case SND_AUDIOCODEC_DTS:
+ break;
+ case SND_AUDIOCODEC_DSD:
+ break;
default:
pr_err("%s: Unsupported audio codec %d\n",
__func__, codec->codec);
@@ -2600,6 +3142,8 @@
case FORMAT_VORBIS:
case FORMAT_ALAC:
case FORMAT_APE:
+ case FORMAT_DTS:
+ case FORMAT_DSD:
pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
prtd->codec);
break;
@@ -2646,7 +3190,7 @@
return 0;
}
-static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol,
+static int msm_compr_playback_app_type_cfg_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
@@ -2665,20 +3209,111 @@
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate);
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate);
+ acdb_dev_id, sample_rate, SESSION_TYPE_RX);
return 0;
}
-static int msm_compr_app_type_cfg_get(struct snd_kcontrol *kcontrol,
+static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_RX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_compr_capture_app_type_cfg_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+
return 0;
}
+static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_TX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
static int msm_compr_channel_map_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2773,6 +3408,8 @@
{
struct msm_compr_pdata *pdata;
int i;
+ int rc;
+ const char *qdsp_version;
pr_debug("%s\n", __func__);
pdata = (struct msm_compr_pdata *)
@@ -2794,6 +3431,17 @@
snd_soc_add_platform_controls(platform, msm_compr_gapless_controls,
ARRAY_SIZE(msm_compr_gapless_controls));
+ rc = of_property_read_string(platform->dev->of_node,
+ "qcom,adsp-version", &qdsp_version);
+ if (!rc) {
+ if (!strcmp(qdsp_version, "MDSP 1.2"))
+ pdata->use_legacy_api = true;
+ else
+ pdata->use_legacy_api = false;
+ } else
+ pdata->use_legacy_api = false;
+
+ pr_debug("%s: use legacy api %d\n", __func__, pdata->use_legacy_api);
/*
* use_dsp_gapless_mode part of platform data(pdata) is updated from HAL
* through a mixer control before compress driver is opened. The mixer
@@ -2818,7 +3466,7 @@
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 128;
+ uinfo->count = MAX_PP_PARAMS_SZ;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0xFFFFFFFF;
return 0;
@@ -3049,7 +3697,8 @@
static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd)
{
- const char *mixer_ctl_name = "Audio Stream";
+ const char *playback_mixer_ctl_name = "Audio Stream";
+ const char *capture_mixer_ctl_name = "Audio Stream Capture";
const char *deviceNo = "NN";
const char *suffix = "App Type Cfg";
char *mixer_str = NULL;
@@ -3060,8 +3709,8 @@
.name = "?",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = msm_compr_app_type_cfg_info,
- .put = msm_compr_app_type_cfg_put,
- .get = msm_compr_app_type_cfg_get,
+ .put = msm_compr_playback_app_type_cfg_put,
+ .get = msm_compr_playback_app_type_cfg_get,
.private_value = 0,
}
};
@@ -3072,24 +3721,45 @@
}
pr_debug("%s: added new compr FE ctl with name %s, id %d, cpu dai %s, device no %d\n",
- __func__, rtd->dai_link->name, rtd->dai_link->be_id,
- rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+ __func__, rtd->dai_link->name, rtd->dai_link->be_id,
+ rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+ if (rtd->compr->direction == SND_COMPRESS_PLAYBACK)
+ ctl_len = strlen(playback_mixer_ctl_name) + 1 + strlen(deviceNo)
+ + 1 + strlen(suffix) + 1;
+ else
+ ctl_len = strlen(capture_mixer_ctl_name) + 1 + strlen(deviceNo)
+ + 1 + strlen(suffix) + 1;
- ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
- strlen(suffix) + 1;
mixer_str = kzalloc(ctl_len, GFP_KERNEL);
if (!mixer_str)
return 0;
- snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
- rtd->pcm->device, suffix);
+ if (rtd->compr->direction == SND_COMPRESS_PLAYBACK)
+ snprintf(mixer_str, ctl_len, "%s %d %s",
+ playback_mixer_ctl_name, rtd->pcm->device, suffix);
+ else
+ snprintf(mixer_str, ctl_len, "%s %d %s",
+ capture_mixer_ctl_name, rtd->pcm->device, suffix);
+
fe_app_type_cfg_control[0].name = mixer_str;
fe_app_type_cfg_control[0].private_value = rtd->dai_link->be_id;
+
+ if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) {
+ fe_app_type_cfg_control[0].put =
+ msm_compr_playback_app_type_cfg_put;
+ fe_app_type_cfg_control[0].get =
+ msm_compr_playback_app_type_cfg_get;
+ } else {
+ fe_app_type_cfg_control[0].put =
+ msm_compr_capture_app_type_cfg_put;
+ fe_app_type_cfg_control[0].get =
+ msm_compr_capture_app_type_cfg_get;
+ }
pr_debug("Registering new mixer ctl %s", mixer_str);
snd_soc_add_platform_controls(rtd->platform,
- fe_app_type_cfg_control,
- ARRAY_SIZE(fe_app_type_cfg_control));
+ fe_app_type_cfg_control,
+ ARRAY_SIZE(fe_app_type_cfg_control));
kfree(mixer_str);
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
new file mode 100644
index 0000000..d4118b0
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -0,0 +1,488 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/msm-dai-q6-v2.h>
+#include <sound/pcm_params.h>
+
+#define HDMI_RX_CA_MAX 0x32
+
+enum {
+ STATUS_PORT_STARTED, /* track if AFE port has started */
+ STATUS_MAX
+};
+
+struct msm_ext_disp_ca {
+ bool set_ca;
+ u32 ca;
+};
+
+struct msm_dai_q6_hdmi_dai_data {
+ DECLARE_BITMAP(status_mask, STATUS_MAX);
+ u32 rate;
+ u32 channels;
+ struct msm_ext_disp_ca ca;
+ union afe_port_config port_config;
+};
+
+static int msm_dai_q6_ext_disp_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+ int value = ucontrol->value.integer.value[0];
+
+ if (!dai_data) {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dai_data->port_config.hdmi_multi_ch.datatype = value;
+ pr_debug("%s: value = %d\n", __func__, value);
+
+ return 0;
+}
+
+static int msm_dai_q6_ext_disp_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+
+ if (!dai_data) {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] =
+ dai_data->port_config.hdmi_multi_ch.datatype;
+ pr_debug("%s: value = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_dai_q6_ext_disp_ca_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+
+ if (!dai_data) {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dai_data->ca.ca = ucontrol->value.integer.value[0];
+ dai_data->ca.set_ca = true;
+ pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca);
+ return 0;
+}
+
+static int msm_dai_q6_ext_disp_ca_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+
+ if (!dai_data) {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] = dai_data->ca.ca;
+ pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca);
+ return 0;
+}
+
+/* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
+ * 0: linear PCM
+ * 1: non-linear PCM
+ */
+static const char * const hdmi_format[] = {
+ "LPCM",
+ "Compr"
+};
+
+static const struct soc_enum hdmi_config_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, hdmi_format),
+};
+
+static const struct snd_kcontrol_new hdmi_config_controls[] = {
+ SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
+ msm_dai_q6_ext_disp_format_get,
+ msm_dai_q6_ext_disp_format_put),
+ SOC_SINGLE_MULTI_EXT("HDMI RX CA", SND_SOC_NOPM, 0,
+ HDMI_RX_CA_MAX, 0, 1,
+ msm_dai_q6_ext_disp_ca_get,
+ msm_dai_q6_ext_disp_ca_put),
+};
+
+static const struct snd_kcontrol_new display_port_config_controls[] = {
+ SOC_ENUM_EXT("Display Port RX Format", hdmi_config_enum[0],
+ msm_dai_q6_ext_disp_format_get,
+ msm_dai_q6_ext_disp_format_put),
+ SOC_SINGLE_MULTI_EXT("Display Port RX CA", SND_SOC_NOPM, 0,
+ HDMI_RX_CA_MAX, 0, 1,
+ msm_dai_q6_ext_disp_ca_get,
+ msm_dai_q6_ext_disp_ca_put),
+};
+
+/* Current implementation assumes hw_param is called once
+ * This may not be the case but what to do when ADM and AFE
+ * port are already opened and parameter changes
+ */
+static int msm_dai_q6_hdmi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai_data->channels = params_channels(params);
+ dai_data->rate = params_rate(params);
+ dai_data->port_config.hdmi_multi_ch.reserved = 0;
+ dai_data->port_config.hdmi_multi_ch.hdmi_cfg_minor_version = 1;
+ dai_data->port_config.hdmi_multi_ch.sample_rate = dai_data->rate;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dai_data->port_config.hdmi_multi_ch.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dai_data->port_config.hdmi_multi_ch.bit_width = 24;
+ break;
+ }
+
+ /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
+ switch (dai_data->channels) {
+ case 2:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0;
+ break;
+ case 3:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x02;
+ break;
+ case 4:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x06;
+ break;
+ case 5:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x0A;
+ break;
+ case 6:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x0B;
+ break;
+ case 7:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x12;
+ break;
+ case 8:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x13;
+ break;
+ default:
+ dev_err(dai->dev, "invalid Channels = %u\n",
+ dai_data->channels);
+ return -EINVAL;
+ }
+ dev_dbg(dai->dev, "%s() minor version: %u samplerate: %u bitwidth: %u\n"
+ "num_ch = %u channel_allocation = %u datatype = %d\n", __func__,
+ dai_data->port_config.hdmi_multi_ch.hdmi_cfg_minor_version,
+ dai_data->port_config.hdmi_multi_ch.sample_rate,
+ dai_data->port_config.hdmi_multi_ch.bit_width,
+ dai_data->channels,
+ dai_data->port_config.hdmi_multi_ch.channel_allocation,
+ dai_data->port_config.hdmi_multi_ch.datatype);
+
+ return 0;
+}
+
+
+static void msm_dai_q6_hdmi_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int rc = 0;
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ pr_info("%s: afe port not started. dai_data->status_mask = %ld\n",
+ __func__, *dai_data->status_mask);
+ return;
+ }
+
+ rc = afe_close(dai->id); /* can block */
+
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AFE port\n");
+
+ pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
+ *dai_data->status_mask);
+
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+}
+
+
+static int msm_dai_q6_hdmi_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int rc = 0;
+
+ if (dai_data->ca.set_ca)
+ dai_data->port_config.hdmi_multi_ch.channel_allocation =
+ dai_data->ca.ca;
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ rc = afe_port_start(dai->id, &dai_data->port_config,
+ dai_data->rate);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to open AFE port %x\n",
+ dai->id);
+ else
+ set_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ }
+
+ return rc;
+}
+
+static inline void msm_dai_q6_hdmi_set_dai_id(struct snd_soc_dai *dai)
+{
+ if (!dai->driver->id) {
+ dev_warn(dai->dev, "DAI driver id is not set\n");
+ return;
+ }
+ dai->id = dai->driver->id;
+}
+
+static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data;
+ const struct snd_kcontrol_new *kcontrol;
+ int rc = 0;
+ struct snd_soc_dapm_route intercon;
+ struct snd_soc_dapm_context *dapm;
+
+ if (!dai || !dai->driver) {
+ pr_err("%s: dai or dai->driver is NULL\n", __func__);
+ return -EINVAL;
+ }
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data),
+ GFP_KERNEL);
+
+ if (!dai_data) {
+ dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+ dai->id);
+ rc = -ENOMEM;
+ } else
+ dev_set_drvdata(dai->dev, dai_data);
+
+ msm_dai_q6_hdmi_set_dai_id(dai);
+
+ if (dai->driver->id == HDMI_RX) {
+ kcontrol = &hdmi_config_controls[0];
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai_data));
+
+ kcontrol = &hdmi_config_controls[1];
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai_data));
+ } else if (dai->driver->id == DISPLAY_PORT_RX) {
+ kcontrol = &display_port_config_controls[0];
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai_data));
+
+ kcontrol = &display_port_config_controls[1];
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai_data));
+ } else {
+ dev_err(dai->dev, "%s: Invalid id:%d\n",
+ __func__, dai->driver->id);
+ kfree(dai_data);
+ dev_set_drvdata(dai->dev, NULL);
+ return -EINVAL;
+ }
+
+ dapm = snd_soc_component_get_dapm(dai->component);
+ memset(&intercon, 0, sizeof(intercon));
+ if (!rc) {
+ if (dai->driver->playback.stream_name &&
+ dai->driver->playback.aif_name) {
+ dev_dbg(dai->dev, "%s add route for widget %s",
+ __func__, dai->driver->playback.stream_name);
+ intercon.source = dai->driver->playback.aif_name;
+ intercon.sink = dai->driver->playback.stream_name;
+ dev_dbg(dai->dev, "%s src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ }
+ if (dai->driver->capture.stream_name &&
+ dai->driver->capture.aif_name) {
+ dev_dbg(dai->dev, "%s add route for widget %s",
+ __func__, dai->driver->capture.stream_name);
+ intercon.sink = dai->driver->capture.aif_name;
+ intercon.source = dai->driver->capture.stream_name;
+ dev_dbg(dai->dev, "%s src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ }
+ }
+ return rc;
+}
+
+static int msm_dai_q6_hdmi_dai_remove(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_hdmi_dai_data *dai_data;
+ int rc;
+
+ dai_data = dev_get_drvdata(dai->dev);
+
+ /* If AFE port is still up, close it */
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ rc = afe_close(dai->id); /* can block */
+
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AFE port\n");
+
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+ }
+ kfree(dai_data);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_hdmi_ops = {
+ .prepare = msm_dai_q6_hdmi_prepare,
+ .hw_params = msm_dai_q6_hdmi_hw_params,
+ .shutdown = msm_dai_q6_hdmi_shutdown,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
+ .playback = {
+ .stream_name = "HDMI Playback",
+ .aif_name = "HDMI",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_max = 192000,
+ .rate_min = 48000,
+ },
+ .ops = &msm_dai_q6_hdmi_ops,
+ .id = HDMI_RX,
+ .probe = msm_dai_q6_hdmi_dai_probe,
+ .remove = msm_dai_q6_hdmi_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_display_port_rx_dai[] = {
+ {
+ .playback = {
+ .stream_name = "Display Port Playback",
+ .aif_name = "DISPLAY_PORT",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_max = 192000,
+ .rate_min = 48000,
+ },
+ .ops = &msm_dai_q6_hdmi_ops,
+ .id = DISPLAY_PORT_RX,
+ .probe = msm_dai_q6_hdmi_dai_probe,
+ .remove = msm_dai_q6_hdmi_dai_remove,
+ },
+};
+
+static const struct snd_soc_component_driver msm_dai_hdmi_q6_component = {
+ .name = "msm-dai-q6-hdmi",
+};
+
+/* To do: change to register DAIs as batch */
+static int msm_dai_q6_hdmi_dev_probe(struct platform_device *pdev)
+{
+ int rc, id;
+ const char *q6_dev_id = "qcom,msm-dai-q6-dev-id";
+
+ rc = of_property_read_u32(pdev->dev.of_node, q6_dev_id, &id);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: missing %s in dt node\n", __func__, q6_dev_id);
+ return rc;
+ }
+
+ pdev->id = id;
+
+ pr_debug("%s: dev name %s, id:%d\n", __func__,
+ dev_name(&pdev->dev), pdev->id);
+
+ switch (pdev->id) {
+ case HDMI_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_hdmi_q6_component,
+ &msm_dai_q6_hdmi_hdmi_rx_dai, 1);
+ break;
+ case DISPLAY_PORT_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_hdmi_q6_component,
+ &msm_dai_q6_display_port_rx_dai[0],
+ ARRAY_SIZE(msm_dai_q6_display_port_rx_dai));
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid device ID %d\n", pdev->id);
+ rc = -ENODEV;
+ break;
+ }
+ return rc;
+}
+
+static int msm_dai_q6_hdmi_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_dai_q6_hdmi_dt_match[] = {
+ {.compatible = "qcom,msm-dai-q6-hdmi"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_dai_q6_hdmi_dt_match);
+
+static struct platform_driver msm_dai_q6_hdmi_driver = {
+ .probe = msm_dai_q6_hdmi_dev_probe,
+ .remove = msm_dai_q6_hdmi_dev_remove,
+ .driver = {
+ .name = "msm-dai-q6-hdmi",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_q6_hdmi_dt_match,
+ },
+};
+
+static int __init msm_dai_q6_hdmi_init(void)
+{
+ return platform_driver_register(&msm_dai_q6_hdmi_driver);
+}
+module_init(msm_dai_q6_hdmi_init);
+
+static void __exit msm_dai_q6_hdmi_exit(void)
+{
+ platform_driver_unregister(&msm_dai_q6_hdmi_driver);
+}
+module_exit(msm_dai_q6_hdmi_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM DSP HDMI DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
new file mode 100644
index 0000000..e3e2e7e
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -0,0 +1,7895 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/clk/msm-clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/msm-dai-q6-v2.h>
+#include <sound/pcm_params.h>
+
+#define MSM_DAI_PRI_AUXPCM_DT_DEV_ID 1
+#define MSM_DAI_SEC_AUXPCM_DT_DEV_ID 2
+#define MSM_DAI_TERT_AUXPCM_DT_DEV_ID 3
+#define MSM_DAI_QUAT_AUXPCM_DT_DEV_ID 4
+
+
+#define spdif_clock_value(rate) (2*rate*32*2)
+#define CHANNEL_STATUS_SIZE 24
+#define CHANNEL_STATUS_MASK_INIT 0x0
+#define CHANNEL_STATUS_MASK 0x4
+#define AFE_API_VERSION_CLOCK_SET 1
+
+#define DAI_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+enum {
+ ENC_FMT_NONE,
+ ENC_FMT_SBC = ASM_MEDIA_FMT_SBC,
+ ENC_FMT_AAC_V2 = ASM_MEDIA_FMT_AAC_V2,
+ ENC_FMT_APTX = ASM_MEDIA_FMT_APTX,
+ ENC_FMT_APTX_HD = ASM_MEDIA_FMT_APTX_HD,
+};
+
+static const struct afe_clk_set lpass_clk_set_default = {
+ AFE_API_VERSION_CLOCK_SET,
+ Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT,
+ Q6AFE_LPASS_OSR_CLK_2_P048_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+};
+
+static const struct afe_clk_cfg lpass_clk_cfg_default = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_OSR_CLK_2_P048_MHZ,
+ 0,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_CLK1_VALID,
+ 0,
+};
+enum {
+ STATUS_PORT_STARTED, /* track if AFE port has started */
+ /* track AFE Tx port status for bi-directional transfers */
+ STATUS_TX_PORT,
+ /* track AFE Rx port status for bi-directional transfers */
+ STATUS_RX_PORT,
+ STATUS_MAX
+};
+
+enum {
+ RATE_8KHZ,
+ RATE_16KHZ,
+ RATE_MAX_NUM_OF_AUX_PCM_RATES,
+};
+
+enum {
+ IDX_PRIMARY_TDM_RX_0,
+ IDX_PRIMARY_TDM_RX_1,
+ IDX_PRIMARY_TDM_RX_2,
+ IDX_PRIMARY_TDM_RX_3,
+ IDX_PRIMARY_TDM_RX_4,
+ IDX_PRIMARY_TDM_RX_5,
+ IDX_PRIMARY_TDM_RX_6,
+ IDX_PRIMARY_TDM_RX_7,
+ IDX_PRIMARY_TDM_TX_0,
+ IDX_PRIMARY_TDM_TX_1,
+ IDX_PRIMARY_TDM_TX_2,
+ IDX_PRIMARY_TDM_TX_3,
+ IDX_PRIMARY_TDM_TX_4,
+ IDX_PRIMARY_TDM_TX_5,
+ IDX_PRIMARY_TDM_TX_6,
+ IDX_PRIMARY_TDM_TX_7,
+ IDX_SECONDARY_TDM_RX_0,
+ IDX_SECONDARY_TDM_RX_1,
+ IDX_SECONDARY_TDM_RX_2,
+ IDX_SECONDARY_TDM_RX_3,
+ IDX_SECONDARY_TDM_RX_4,
+ IDX_SECONDARY_TDM_RX_5,
+ IDX_SECONDARY_TDM_RX_6,
+ IDX_SECONDARY_TDM_RX_7,
+ IDX_SECONDARY_TDM_TX_0,
+ IDX_SECONDARY_TDM_TX_1,
+ IDX_SECONDARY_TDM_TX_2,
+ IDX_SECONDARY_TDM_TX_3,
+ IDX_SECONDARY_TDM_TX_4,
+ IDX_SECONDARY_TDM_TX_5,
+ IDX_SECONDARY_TDM_TX_6,
+ IDX_SECONDARY_TDM_TX_7,
+ IDX_TERTIARY_TDM_RX_0,
+ IDX_TERTIARY_TDM_RX_1,
+ IDX_TERTIARY_TDM_RX_2,
+ IDX_TERTIARY_TDM_RX_3,
+ IDX_TERTIARY_TDM_RX_4,
+ IDX_TERTIARY_TDM_RX_5,
+ IDX_TERTIARY_TDM_RX_6,
+ IDX_TERTIARY_TDM_RX_7,
+ IDX_TERTIARY_TDM_TX_0,
+ IDX_TERTIARY_TDM_TX_1,
+ IDX_TERTIARY_TDM_TX_2,
+ IDX_TERTIARY_TDM_TX_3,
+ IDX_TERTIARY_TDM_TX_4,
+ IDX_TERTIARY_TDM_TX_5,
+ IDX_TERTIARY_TDM_TX_6,
+ IDX_TERTIARY_TDM_TX_7,
+ IDX_QUATERNARY_TDM_RX_0,
+ IDX_QUATERNARY_TDM_RX_1,
+ IDX_QUATERNARY_TDM_RX_2,
+ IDX_QUATERNARY_TDM_RX_3,
+ IDX_QUATERNARY_TDM_RX_4,
+ IDX_QUATERNARY_TDM_RX_5,
+ IDX_QUATERNARY_TDM_RX_6,
+ IDX_QUATERNARY_TDM_RX_7,
+ IDX_QUATERNARY_TDM_TX_0,
+ IDX_QUATERNARY_TDM_TX_1,
+ IDX_QUATERNARY_TDM_TX_2,
+ IDX_QUATERNARY_TDM_TX_3,
+ IDX_QUATERNARY_TDM_TX_4,
+ IDX_QUATERNARY_TDM_TX_5,
+ IDX_QUATERNARY_TDM_TX_6,
+ IDX_QUATERNARY_TDM_TX_7,
+ IDX_TDM_MAX,
+};
+
+enum {
+ IDX_GROUP_PRIMARY_TDM_RX,
+ IDX_GROUP_PRIMARY_TDM_TX,
+ IDX_GROUP_SECONDARY_TDM_RX,
+ IDX_GROUP_SECONDARY_TDM_TX,
+ IDX_GROUP_TERTIARY_TDM_RX,
+ IDX_GROUP_TERTIARY_TDM_TX,
+ IDX_GROUP_QUATERNARY_TDM_RX,
+ IDX_GROUP_QUATERNARY_TDM_TX,
+ IDX_GROUP_TDM_MAX,
+};
+
+struct msm_dai_q6_dai_data {
+ DECLARE_BITMAP(status_mask, STATUS_MAX);
+ DECLARE_BITMAP(hwfree_status, STATUS_MAX);
+ u32 rate;
+ u32 channels;
+ u32 bitwidth;
+ u32 cal_mode;
+ u32 afe_in_channels;
+ u16 afe_in_bitformat;
+ struct afe_enc_config enc_config;
+ union afe_port_config port_config;
+};
+
+struct msm_dai_q6_spdif_dai_data {
+ DECLARE_BITMAP(status_mask, STATUS_MAX);
+ u32 rate;
+ u32 channels;
+ u32 bitwidth;
+ struct afe_spdif_port_config spdif_port;
+};
+
+struct msm_dai_q6_mi2s_dai_config {
+ u16 pdata_mi2s_lines;
+ struct msm_dai_q6_dai_data mi2s_dai_data;
+};
+
+struct msm_dai_q6_mi2s_dai_data {
+ struct msm_dai_q6_mi2s_dai_config tx_dai;
+ struct msm_dai_q6_mi2s_dai_config rx_dai;
+};
+
+struct msm_dai_q6_auxpcm_dai_data {
+ /* BITMAP to track Rx and Tx port usage count */
+ DECLARE_BITMAP(auxpcm_port_status, STATUS_MAX);
+ struct mutex rlock; /* auxpcm dev resource lock */
+ u16 rx_pid; /* AUXPCM RX AFE port ID */
+ u16 tx_pid; /* AUXPCM TX AFE port ID */
+ u16 afe_clk_ver;
+ struct afe_clk_cfg clk_cfg; /* hold LPASS clock configuration */
+ struct afe_clk_set clk_set; /* hold LPASS clock configuration */
+ struct msm_dai_q6_dai_data bdai_data; /* incoporate base DAI data */
+};
+
+struct msm_dai_q6_tdm_dai_data {
+ DECLARE_BITMAP(status_mask, STATUS_MAX);
+ u32 rate;
+ u32 channels;
+ u32 bitwidth;
+ struct afe_clk_set clk_set; /* hold LPASS clock config. */
+ union afe_port_group_config group_cfg; /* hold tdm group config */
+ struct afe_tdm_port_config port_cfg; /* hold tdm config */
+};
+
+/* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
+ * 0: linear PCM
+ * 1: non-linear PCM
+ * 2: PCM data in IEC 60968 container
+ * 3: compressed data in IEC 60958 container
+ */
+static const char *const mi2s_format[] = {
+ "LPCM",
+ "Compr",
+ "LPCM-60958",
+ "Compr-60958"
+};
+
+static const struct soc_enum mi2s_config_enum[] = {
+ SOC_ENUM_SINGLE_EXT(4, mi2s_format),
+};
+
+static const char *const sb_format[] = {
+ "UNPACKED",
+ "PACKED_16B",
+ "DSD_DOP",
+};
+
+static const struct soc_enum sb_config_enum[] = {
+ SOC_ENUM_SINGLE_EXT(3, sb_format),
+};
+
+static const char *const tdm_data_format[] = {
+ "LPCM",
+ "Compr",
+};
+
+static const char *const tdm_header_type[] = {
+ "Invalid",
+ "Default",
+ "Entertainment",
+};
+
+static const struct soc_enum tdm_config_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, tdm_data_format),
+ SOC_ENUM_SINGLE_EXT(3, tdm_header_type),
+};
+
+static DEFINE_MUTEX(tdm_mutex);
+
+static atomic_t tdm_group_ref[IDX_GROUP_TDM_MAX];
+
+/* cache of group cfg per parent node */
+static struct afe_param_id_group_device_tdm_cfg tdm_group_cfg = {
+ AFE_API_VERSION_GROUP_DEVICE_TDM_CONFIG,
+ AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX,
+ 0,
+ {AFE_PORT_ID_QUATERNARY_TDM_RX,
+ AFE_PORT_ID_QUATERNARY_TDM_RX_1,
+ AFE_PORT_ID_QUATERNARY_TDM_RX_2,
+ AFE_PORT_ID_QUATERNARY_TDM_RX_3,
+ AFE_PORT_ID_QUATERNARY_TDM_RX_4,
+ AFE_PORT_ID_QUATERNARY_TDM_RX_5,
+ AFE_PORT_ID_QUATERNARY_TDM_RX_6,
+ AFE_PORT_ID_QUATERNARY_TDM_RX_7},
+ 8,
+ 48000,
+ 32,
+ 8,
+ 32,
+ 0xFF,
+};
+
+static struct afe_clk_set tdm_clk_set = {
+ AFE_API_VERSION_CLOCK_SET,
+ Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT,
+ Q6AFE_LPASS_IBIT_CLK_DISABLE,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+};
+
+int msm_dai_q6_get_group_idx(u16 id)
+{
+ switch (id) {
+ case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ return IDX_GROUP_PRIMARY_TDM_RX;
+ case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ return IDX_GROUP_PRIMARY_TDM_TX;
+ case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ return IDX_GROUP_SECONDARY_TDM_RX;
+ case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ return IDX_GROUP_SECONDARY_TDM_TX;
+ case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ return IDX_GROUP_TERTIARY_TDM_RX;
+ case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ return IDX_GROUP_TERTIARY_TDM_TX;
+ case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ return IDX_GROUP_QUATERNARY_TDM_RX;
+ case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ return IDX_GROUP_QUATERNARY_TDM_TX;
+ default: return -EINVAL;
+ }
+}
+
+int msm_dai_q6_get_port_idx(u16 id)
+{
+ switch (id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ return IDX_PRIMARY_TDM_RX_0;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ return IDX_PRIMARY_TDM_TX_0;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ return IDX_PRIMARY_TDM_RX_1;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ return IDX_PRIMARY_TDM_TX_1;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ return IDX_PRIMARY_TDM_RX_2;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ return IDX_PRIMARY_TDM_TX_2;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ return IDX_PRIMARY_TDM_RX_3;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ return IDX_PRIMARY_TDM_TX_3;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ return IDX_PRIMARY_TDM_RX_4;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ return IDX_PRIMARY_TDM_TX_4;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ return IDX_PRIMARY_TDM_RX_5;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ return IDX_PRIMARY_TDM_TX_5;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ return IDX_PRIMARY_TDM_RX_6;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ return IDX_PRIMARY_TDM_TX_6;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ return IDX_PRIMARY_TDM_RX_7;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ return IDX_PRIMARY_TDM_TX_7;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ return IDX_SECONDARY_TDM_RX_0;
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ return IDX_SECONDARY_TDM_TX_0;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ return IDX_SECONDARY_TDM_RX_1;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ return IDX_SECONDARY_TDM_TX_1;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ return IDX_SECONDARY_TDM_RX_2;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ return IDX_SECONDARY_TDM_TX_2;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ return IDX_SECONDARY_TDM_RX_3;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ return IDX_SECONDARY_TDM_TX_3;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ return IDX_SECONDARY_TDM_RX_4;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ return IDX_SECONDARY_TDM_TX_4;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ return IDX_SECONDARY_TDM_RX_5;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ return IDX_SECONDARY_TDM_TX_5;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ return IDX_SECONDARY_TDM_RX_6;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ return IDX_SECONDARY_TDM_TX_6;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ return IDX_SECONDARY_TDM_RX_7;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ return IDX_SECONDARY_TDM_TX_7;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ return IDX_TERTIARY_TDM_RX_0;
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ return IDX_TERTIARY_TDM_TX_0;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ return IDX_TERTIARY_TDM_RX_1;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ return IDX_TERTIARY_TDM_TX_1;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ return IDX_TERTIARY_TDM_RX_2;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ return IDX_TERTIARY_TDM_TX_2;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ return IDX_TERTIARY_TDM_RX_3;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ return IDX_TERTIARY_TDM_TX_3;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ return IDX_TERTIARY_TDM_RX_4;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ return IDX_TERTIARY_TDM_TX_4;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ return IDX_TERTIARY_TDM_RX_5;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ return IDX_TERTIARY_TDM_TX_5;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ return IDX_TERTIARY_TDM_RX_6;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ return IDX_TERTIARY_TDM_TX_6;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ return IDX_TERTIARY_TDM_RX_7;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ return IDX_TERTIARY_TDM_TX_7;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ return IDX_QUATERNARY_TDM_RX_0;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ return IDX_QUATERNARY_TDM_TX_0;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ return IDX_QUATERNARY_TDM_RX_1;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ return IDX_QUATERNARY_TDM_TX_1;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ return IDX_QUATERNARY_TDM_RX_2;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ return IDX_QUATERNARY_TDM_TX_2;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ return IDX_QUATERNARY_TDM_RX_3;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ return IDX_QUATERNARY_TDM_TX_3;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ return IDX_QUATERNARY_TDM_RX_4;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ return IDX_QUATERNARY_TDM_TX_4;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ return IDX_QUATERNARY_TDM_RX_5;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ return IDX_QUATERNARY_TDM_TX_5;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ return IDX_QUATERNARY_TDM_RX_6;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ return IDX_QUATERNARY_TDM_TX_6;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ return IDX_QUATERNARY_TDM_RX_7;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ return IDX_QUATERNARY_TDM_TX_7;
+ default: return -EINVAL;
+ }
+}
+
+static u16 msm_dai_q6_max_num_slot(int frame_rate)
+{
+ /* Max num of slots is bits per frame divided
+ * by bits per sample which is 16
+ */
+ switch (frame_rate) {
+ case AFE_PORT_PCM_BITS_PER_FRAME_8:
+ return 0;
+ case AFE_PORT_PCM_BITS_PER_FRAME_16:
+ return 1;
+ case AFE_PORT_PCM_BITS_PER_FRAME_32:
+ return 2;
+ case AFE_PORT_PCM_BITS_PER_FRAME_64:
+ return 4;
+ case AFE_PORT_PCM_BITS_PER_FRAME_128:
+ return 8;
+ case AFE_PORT_PCM_BITS_PER_FRAME_256:
+ return 16;
+ default:
+ pr_err("%s Invalid bits per frame %d\n",
+ __func__, frame_rate);
+ return 0;
+ }
+}
+
+static int msm_dai_q6_dai_add_route(struct snd_soc_dai *dai)
+{
+ struct snd_soc_dapm_route intercon;
+ struct snd_soc_dapm_context *dapm;
+
+ if (!dai) {
+ pr_err("%s: Invalid params dai\n", __func__);
+ return -EINVAL;
+ }
+ if (!dai->driver) {
+ pr_err("%s: Invalid params dai driver\n", __func__);
+ return -EINVAL;
+ }
+ dapm = snd_soc_component_get_dapm(dai->component);
+ memset(&intercon, 0, sizeof(intercon));
+ if (dai->driver->playback.stream_name &&
+ dai->driver->playback.aif_name) {
+ dev_dbg(dai->dev, "%s: add route for widget %s",
+ __func__, dai->driver->playback.stream_name);
+ intercon.source = dai->driver->playback.aif_name;
+ intercon.sink = dai->driver->playback.stream_name;
+ dev_dbg(dai->dev, "%s: src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ }
+ if (dai->driver->capture.stream_name &&
+ dai->driver->capture.aif_name) {
+ dev_dbg(dai->dev, "%s: add route for widget %s",
+ __func__, dai->driver->capture.stream_name);
+ intercon.sink = dai->driver->capture.aif_name;
+ intercon.source = dai->driver->capture.stream_name;
+ dev_dbg(dai->dev, "%s: src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ }
+ return 0;
+}
+
+static int msm_dai_q6_auxpcm_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data = &aux_dai_data->bdai_data;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+ (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+ int rc = 0, slot_mapping_copy_len = 0;
+
+ if (params_channels(params) != 1 || (params_rate(params) != 8000 &&
+ params_rate(params) != 16000)) {
+ dev_err(dai->dev, "%s: invalid param chan %d rate %d\n",
+ __func__, params_channels(params), params_rate(params));
+ return -EINVAL;
+ }
+
+ mutex_lock(&aux_dai_data->rlock);
+
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) ||
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status)) {
+ /* AUXPCM DAI in use */
+ if (dai_data->rate != params_rate(params)) {
+ dev_err(dai->dev, "%s: rate mismatch of running DAI\n",
+ __func__);
+ rc = -EINVAL;
+ }
+ mutex_unlock(&aux_dai_data->rlock);
+ return rc;
+ }
+
+ dai_data->channels = params_channels(params);
+ dai_data->rate = params_rate(params);
+
+ if (dai_data->rate == 8000) {
+ dai_data->port_config.pcm.pcm_cfg_minor_version =
+ AFE_API_VERSION_PCM_CONFIG;
+ dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode_8k.mode;
+ dai_data->port_config.pcm.sync_src = auxpcm_pdata->mode_8k.sync;
+ dai_data->port_config.pcm.frame_setting =
+ auxpcm_pdata->mode_8k.frame;
+ dai_data->port_config.pcm.quantype =
+ auxpcm_pdata->mode_8k.quant;
+ dai_data->port_config.pcm.ctrl_data_out_enable =
+ auxpcm_pdata->mode_8k.data;
+ dai_data->port_config.pcm.sample_rate = dai_data->rate;
+ dai_data->port_config.pcm.num_channels = dai_data->channels;
+ dai_data->port_config.pcm.bit_width = 16;
+ if (ARRAY_SIZE(dai_data->port_config.pcm.slot_number_mapping) <=
+ auxpcm_pdata->mode_8k.num_slots)
+ slot_mapping_copy_len =
+ ARRAY_SIZE(
+ dai_data->port_config.pcm.slot_number_mapping)
+ * sizeof(uint16_t);
+ else
+ slot_mapping_copy_len = auxpcm_pdata->mode_8k.num_slots
+ * sizeof(uint16_t);
+
+ if (auxpcm_pdata->mode_8k.slot_mapping) {
+ memcpy(dai_data->port_config.pcm.slot_number_mapping,
+ auxpcm_pdata->mode_8k.slot_mapping,
+ slot_mapping_copy_len);
+ } else {
+ dev_err(dai->dev, "%s 8khz slot mapping is NULL\n",
+ __func__);
+ mutex_unlock(&aux_dai_data->rlock);
+ return -EINVAL;
+ }
+ } else {
+ dai_data->port_config.pcm.pcm_cfg_minor_version =
+ AFE_API_VERSION_PCM_CONFIG;
+ dai_data->port_config.pcm.aux_mode =
+ auxpcm_pdata->mode_16k.mode;
+ dai_data->port_config.pcm.sync_src =
+ auxpcm_pdata->mode_16k.sync;
+ dai_data->port_config.pcm.frame_setting =
+ auxpcm_pdata->mode_16k.frame;
+ dai_data->port_config.pcm.quantype =
+ auxpcm_pdata->mode_16k.quant;
+ dai_data->port_config.pcm.ctrl_data_out_enable =
+ auxpcm_pdata->mode_16k.data;
+ dai_data->port_config.pcm.sample_rate = dai_data->rate;
+ dai_data->port_config.pcm.num_channels = dai_data->channels;
+ dai_data->port_config.pcm.bit_width = 16;
+ if (ARRAY_SIZE(dai_data->port_config.pcm.slot_number_mapping) <=
+ auxpcm_pdata->mode_16k.num_slots)
+ slot_mapping_copy_len =
+ ARRAY_SIZE(
+ dai_data->port_config.pcm.slot_number_mapping)
+ * sizeof(uint16_t);
+ else
+ slot_mapping_copy_len = auxpcm_pdata->mode_16k.num_slots
+ * sizeof(uint16_t);
+
+ if (auxpcm_pdata->mode_16k.slot_mapping) {
+ memcpy(dai_data->port_config.pcm.slot_number_mapping,
+ auxpcm_pdata->mode_16k.slot_mapping,
+ slot_mapping_copy_len);
+ } else {
+ dev_err(dai->dev, "%s 16khz slot mapping is NULL\n",
+ __func__);
+ mutex_unlock(&aux_dai_data->rlock);
+ return -EINVAL;
+ }
+ }
+
+ dev_dbg(dai->dev, "%s: aux_mode 0x%x sync_src 0x%x frame_setting 0x%x\n",
+ __func__, dai_data->port_config.pcm.aux_mode,
+ dai_data->port_config.pcm.sync_src,
+ dai_data->port_config.pcm.frame_setting);
+ dev_dbg(dai->dev, "%s: qtype 0x%x dout 0x%x num_map[0] 0x%x\n"
+ "num_map[1] 0x%x num_map[2] 0x%x num_map[3] 0x%x\n",
+ __func__, dai_data->port_config.pcm.quantype,
+ dai_data->port_config.pcm.ctrl_data_out_enable,
+ dai_data->port_config.pcm.slot_number_mapping[0],
+ dai_data->port_config.pcm.slot_number_mapping[1],
+ dai_data->port_config.pcm.slot_number_mapping[2],
+ dai_data->port_config.pcm.slot_number_mapping[3]);
+
+ mutex_unlock(&aux_dai_data->rlock);
+ return rc;
+}
+
+static int msm_dai_q6_auxpcm_set_clk(
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data,
+ u16 port_id, bool enable)
+{
+ int rc;
+
+ pr_debug("%s: afe_clk_ver: %d, port_id: %d, enable: %d\n", __func__,
+ aux_dai_data->afe_clk_ver, port_id, enable);
+ if (aux_dai_data->afe_clk_ver == AFE_CLK_VERSION_V2) {
+ aux_dai_data->clk_set.enable = enable;
+ rc = afe_set_lpass_clock_v2(port_id,
+ &aux_dai_data->clk_set);
+ } else {
+ if (!enable)
+ aux_dai_data->clk_cfg.clk_val1 = 0;
+ rc = afe_set_lpass_clock(port_id,
+ &aux_dai_data->clk_cfg);
+ }
+ return rc;
+}
+
+static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int rc = 0;
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data =
+ dev_get_drvdata(dai->dev);
+
+ mutex_lock(&aux_dai_data->rlock);
+
+ if (!(test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) ||
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status))) {
+ dev_dbg(dai->dev, "%s(): dai->id %d PCM ports already closed\n",
+ __func__, dai->id);
+ goto exit;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status))
+ clear_bit(STATUS_TX_PORT,
+ aux_dai_data->auxpcm_port_status);
+ else {
+ dev_dbg(dai->dev, "%s: PCM_TX port already closed\n",
+ __func__);
+ goto exit;
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status))
+ clear_bit(STATUS_RX_PORT,
+ aux_dai_data->auxpcm_port_status);
+ else {
+ dev_dbg(dai->dev, "%s: PCM_RX port already closed\n",
+ __func__);
+ goto exit;
+ }
+ }
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) ||
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status)) {
+ dev_dbg(dai->dev, "%s: cannot shutdown PCM ports\n",
+ __func__);
+ goto exit;
+ }
+
+ dev_dbg(dai->dev, "%s: dai->id = %d closing PCM AFE ports\n",
+ __func__, dai->id);
+
+ rc = afe_close(aux_dai_data->rx_pid); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
+
+ rc = afe_close(aux_dai_data->tx_pid);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUX PCM TX port\n");
+
+ msm_dai_q6_auxpcm_set_clk(aux_dai_data, aux_dai_data->rx_pid, false);
+ msm_dai_q6_auxpcm_set_clk(aux_dai_data, aux_dai_data->tx_pid, false);
+exit:
+ mutex_unlock(&aux_dai_data->rlock);
+}
+
+static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data = &aux_dai_data->bdai_data;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
+ int rc = 0;
+ u32 pcm_clk_rate;
+
+ auxpcm_pdata = dai->dev->platform_data;
+ mutex_lock(&aux_dai_data->rlock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (test_bit(STATUS_TX_PORT,
+ aux_dai_data->auxpcm_port_status)) {
+ dev_dbg(dai->dev, "%s: PCM_TX port already ON\n",
+ __func__);
+ goto exit;
+ } else
+ set_bit(STATUS_TX_PORT,
+ aux_dai_data->auxpcm_port_status);
+ } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (test_bit(STATUS_RX_PORT,
+ aux_dai_data->auxpcm_port_status)) {
+ dev_dbg(dai->dev, "%s: PCM_RX port already ON\n",
+ __func__);
+ goto exit;
+ } else
+ set_bit(STATUS_RX_PORT,
+ aux_dai_data->auxpcm_port_status);
+ }
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) &&
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status)) {
+ dev_dbg(dai->dev, "%s: PCM ports already set\n", __func__);
+ goto exit;
+ }
+
+ dev_dbg(dai->dev, "%s: dai->id:%d opening afe ports\n",
+ __func__, dai->id);
+
+ rc = afe_q6_interface_prepare();
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "fail to open AFE APR\n");
+ goto fail;
+ }
+
+ /*
+ * For AUX PCM Interface the below sequence of clk
+ * settings and afe_open is a strict requirement.
+ *
+ * Also using afe_open instead of afe_port_start_nowait
+ * to make sure the port is open before deasserting the
+ * clock line. This is required because pcm register is
+ * not written before clock deassert. Hence the hw does
+ * not get updated with new setting if the below clock
+ * assert/deasset and afe_open sequence is not followed.
+ */
+
+ if (dai_data->rate == 8000) {
+ pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ } else if (dai_data->rate == 16000) {
+ pcm_clk_rate = (auxpcm_pdata->mode_16k.pcm_clk_rate);
+ } else {
+ dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
+ dai_data->rate);
+ rc = -EINVAL;
+ goto fail;
+ }
+ if (aux_dai_data->afe_clk_ver == AFE_CLK_VERSION_V2) {
+ memcpy(&aux_dai_data->clk_set, &lpass_clk_set_default,
+ sizeof(struct afe_clk_set));
+ aux_dai_data->clk_set.clk_freq_in_hz = pcm_clk_rate;
+
+ switch (dai->id) {
+ case MSM_DAI_PRI_AUXPCM_DT_DEV_ID:
+ if (pcm_clk_rate)
+ aux_dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT;
+ else
+ aux_dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_PRI_PCM_EBIT;
+ break;
+ case MSM_DAI_SEC_AUXPCM_DT_DEV_ID:
+ if (pcm_clk_rate)
+ aux_dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_SEC_PCM_IBIT;
+ else
+ aux_dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_SEC_PCM_EBIT;
+ break;
+ case MSM_DAI_TERT_AUXPCM_DT_DEV_ID:
+ if (pcm_clk_rate)
+ aux_dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_TER_PCM_IBIT;
+ else
+ aux_dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_TER_PCM_EBIT;
+ break;
+ case MSM_DAI_QUAT_AUXPCM_DT_DEV_ID:
+ if (pcm_clk_rate)
+ aux_dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT;
+ else
+ aux_dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_QUAD_PCM_EBIT;
+ break;
+ default:
+ dev_err(dai->dev, "%s: AUXPCM id: %d not supported\n",
+ __func__, dai->id);
+ break;
+ }
+ } else {
+ memcpy(&aux_dai_data->clk_cfg, &lpass_clk_cfg_default,
+ sizeof(struct afe_clk_cfg));
+ aux_dai_data->clk_cfg.clk_val1 = pcm_clk_rate;
+ }
+
+ rc = msm_dai_q6_auxpcm_set_clk(aux_dai_data,
+ aux_dai_data->rx_pid, true);
+ if (rc < 0) {
+ dev_err(dai->dev,
+ "%s:afe_set_lpass_clock on RX pcm_src_clk failed\n",
+ __func__);
+ goto fail;
+ }
+
+ rc = msm_dai_q6_auxpcm_set_clk(aux_dai_data,
+ aux_dai_data->tx_pid, true);
+ if (rc < 0) {
+ dev_err(dai->dev,
+ "%s:afe_set_lpass_clock on TX pcm_src_clk failed\n",
+ __func__);
+ goto fail;
+ }
+
+ afe_open(aux_dai_data->rx_pid, &dai_data->port_config, dai_data->rate);
+ afe_open(aux_dai_data->tx_pid, &dai_data->port_config, dai_data->rate);
+ goto exit;
+
+fail:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ clear_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status);
+ else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ clear_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status);
+
+exit:
+ mutex_unlock(&aux_dai_data->rlock);
+ return rc;
+}
+
+static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ int rc = 0;
+
+ pr_debug("%s:port:%d cmd:%d\n",
+ __func__, dai->id, cmd);
+
+ switch (cmd) {
+
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ /* afe_open will be called from prepare */
+ return 0;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ return 0;
+
+ default:
+ pr_err("%s: cmd %d\n", __func__, cmd);
+ rc = -EINVAL;
+ }
+
+ return rc;
+
+}
+
+static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data;
+ int rc;
+
+ aux_dai_data = dev_get_drvdata(dai->dev);
+
+ dev_dbg(dai->dev, "%s: dai->id %d closing afe\n",
+ __func__, dai->id);
+
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) ||
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status)) {
+ rc = afe_close(aux_dai_data->rx_pid); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUXPCM RX AFE port\n");
+ rc = afe_close(aux_dai_data->tx_pid);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUXPCM TX AFE port\n");
+ clear_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status);
+ clear_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status);
+ }
+ msm_dai_q6_auxpcm_set_clk(aux_dai_data, aux_dai_data->rx_pid, false);
+ msm_dai_q6_auxpcm_set_clk(aux_dai_data, aux_dai_data->tx_pid, false);
+ return 0;
+}
+
+static int msm_dai_q6_aux_pcm_probe(struct snd_soc_dai *dai)
+{
+ int rc = 0;
+
+ if (!dai) {
+ pr_err("%s: Invalid params dai\n", __func__);
+ return -EINVAL;
+ }
+ if (!dai->dev) {
+ pr_err("%s: Invalid params dai dev\n", __func__);
+ return -EINVAL;
+ }
+ if (!dai->driver->id) {
+ dev_warn(dai->dev, "DAI driver id is not set\n");
+ return -EINVAL;
+ }
+ dai->id = dai->driver->id;
+ rc = msm_dai_q6_dai_add_route(dai);
+ return rc;
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
+ .prepare = msm_dai_q6_auxpcm_prepare,
+ .trigger = msm_dai_q6_auxpcm_trigger,
+ .hw_params = msm_dai_q6_auxpcm_hw_params,
+ .shutdown = msm_dai_q6_auxpcm_shutdown,
+};
+
+static const struct snd_soc_component_driver
+ msm_dai_q6_aux_pcm_dai_component = {
+ .name = "msm-auxpcm-dev",
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_dai[] = {
+ {
+ .playback = {
+ .stream_name = "AUX PCM Playback",
+ .aif_name = "AUX_PCM_RX",
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .capture = {
+ .stream_name = "AUX PCM Capture",
+ .aif_name = "AUX_PCM_TX",
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .id = MSM_DAI_PRI_AUXPCM_DT_DEV_ID,
+ .ops = &msm_dai_q6_auxpcm_ops,
+ .probe = msm_dai_q6_aux_pcm_probe,
+ .remove = msm_dai_q6_dai_auxpcm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Sec AUX PCM Playback",
+ .aif_name = "SEC_AUX_PCM_RX",
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .capture = {
+ .stream_name = "Sec AUX PCM Capture",
+ .aif_name = "SEC_AUX_PCM_TX",
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .id = MSM_DAI_SEC_AUXPCM_DT_DEV_ID,
+ .ops = &msm_dai_q6_auxpcm_ops,
+ .probe = msm_dai_q6_aux_pcm_probe,
+ .remove = msm_dai_q6_dai_auxpcm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tert AUX PCM Playback",
+ .aif_name = "TERT_AUX_PCM_RX",
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .capture = {
+ .stream_name = "Tert AUX PCM Capture",
+ .aif_name = "TERT_AUX_PCM_TX",
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .id = MSM_DAI_TERT_AUXPCM_DT_DEV_ID,
+ .ops = &msm_dai_q6_auxpcm_ops,
+ .probe = msm_dai_q6_aux_pcm_probe,
+ .remove = msm_dai_q6_dai_auxpcm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quat AUX PCM Playback",
+ .aif_name = "QUAT_AUX_PCM_RX",
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .capture = {
+ .stream_name = "Quat AUX PCM Capture",
+ .aif_name = "QUAT_AUX_PCM_TX",
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .id = MSM_DAI_QUAT_AUXPCM_DT_DEV_ID,
+ .ops = &msm_dai_q6_auxpcm_ops,
+ .probe = msm_dai_q6_aux_pcm_probe,
+ .remove = msm_dai_q6_dai_auxpcm_remove,
+ },
+};
+
+static int msm_dai_q6_spdif_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data;
+ int value = ucontrol->value.integer.value[0];
+
+ dai_data->spdif_port.cfg.data_format = value;
+ pr_debug("%s: value = %d\n", __func__, value);
+ return 0;
+}
+
+static int msm_dai_q6_spdif_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data;
+
+ ucontrol->value.integer.value[0] =
+ dai_data->spdif_port.cfg.data_format;
+ return 0;
+}
+
+static const char * const spdif_format[] = {
+ "LPCM",
+ "Compr"
+};
+
+static const struct soc_enum spdif_config_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, spdif_format),
+};
+
+static int msm_dai_q6_spdif_chstatus_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data;
+ int ret = 0;
+
+ dai_data->spdif_port.ch_status.status_type =
+ AFE_API_VERSION_SPDIF_CH_STATUS_CONFIG;
+ memset(dai_data->spdif_port.ch_status.status_mask,
+ CHANNEL_STATUS_MASK_INIT, CHANNEL_STATUS_SIZE);
+ dai_data->spdif_port.ch_status.status_mask[0] =
+ CHANNEL_STATUS_MASK;
+
+ memcpy(dai_data->spdif_port.ch_status.status_bits,
+ ucontrol->value.iec958.status, CHANNEL_STATUS_SIZE);
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ pr_debug("%s: Port already started. Dynamic update\n",
+ __func__);
+ ret = afe_send_spdif_ch_status_cfg(
+ &dai_data->spdif_port.ch_status,
+ AFE_PORT_ID_SPDIF_RX);
+ }
+ return ret;
+}
+
+static int msm_dai_q6_spdif_chstatus_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data;
+
+ memcpy(ucontrol->value.iec958.status,
+ dai_data->spdif_port.ch_status.status_bits,
+ CHANNEL_STATUS_SIZE);
+ return 0;
+}
+
+static int msm_dai_q6_spdif_chstatus_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static const struct snd_kcontrol_new spdif_config_controls[] = {
+ {
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE),
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
+ .info = msm_dai_q6_spdif_chstatus_info,
+ .get = msm_dai_q6_spdif_chstatus_get,
+ .put = msm_dai_q6_spdif_chstatus_put,
+ },
+ SOC_ENUM_EXT("SPDIF RX Format", spdif_config_enum[0],
+ msm_dai_q6_spdif_format_get,
+ msm_dai_q6_spdif_format_put)
+};
+
+
+static int msm_dai_q6_spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_spdif_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai->id = AFE_PORT_ID_SPDIF_RX;
+ dai_data->channels = params_channels(params);
+ dai_data->spdif_port.cfg.num_channels = dai_data->channels;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dai_data->spdif_port.cfg.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ dai_data->spdif_port.cfg.bit_width = 24;
+ break;
+ default:
+ pr_err("%s: format %d\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ dai_data->rate = params_rate(params);
+ dai_data->bitwidth = dai_data->spdif_port.cfg.bit_width;
+ dai_data->spdif_port.cfg.sample_rate = dai_data->rate;
+ dai_data->spdif_port.cfg.spdif_cfg_minor_version =
+ AFE_API_VERSION_SPDIF_CONFIG;
+ dev_dbg(dai->dev, " channel %d sample rate %d bit width %d\n",
+ dai_data->channels, dai_data->rate,
+ dai_data->spdif_port.cfg.bit_width);
+ dai_data->spdif_port.cfg.reserved = 0;
+ return 0;
+}
+
+static void msm_dai_q6_spdif_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_spdif_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int rc = 0;
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ pr_info("%s: afe port not started. dai_data->status_mask = %ld\n",
+ __func__, *dai_data->status_mask);
+ return;
+ }
+
+ rc = afe_close(dai->id);
+
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AFE port\n");
+
+ pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
+ *dai_data->status_mask);
+
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+}
+
+
+static int msm_dai_q6_spdif_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_spdif_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int rc = 0;
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: clk_config failed", __func__);
+ return rc;
+ }
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ rc = afe_spdif_port_start(dai->id, &dai_data->spdif_port,
+ dai_data->rate);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to open AFE port 0x%x\n",
+ dai->id);
+ else
+ set_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ }
+
+ return rc;
+}
+
+static int msm_dai_q6_spdif_dai_probe(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_spdif_dai_data *dai_data;
+ const struct snd_kcontrol_new *kcontrol;
+ int rc = 0;
+ struct snd_soc_dapm_route intercon;
+ struct snd_soc_dapm_context *dapm;
+
+ if (!dai) {
+ pr_err("%s: dai not found!!\n", __func__);
+ return -EINVAL;
+ }
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_spdif_dai_data),
+ GFP_KERNEL);
+
+ if (!dai_data) {
+ dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+ AFE_PORT_ID_SPDIF_RX);
+ rc = -ENOMEM;
+ } else
+ dev_set_drvdata(dai->dev, dai_data);
+
+ kcontrol = &spdif_config_controls[1];
+ dapm = snd_soc_component_get_dapm(dai->component);
+
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai_data));
+
+ memset(&intercon, 0, sizeof(intercon));
+ if (!rc && dai && dai->driver) {
+ if (dai->driver->playback.stream_name &&
+ dai->driver->playback.aif_name) {
+ dev_dbg(dai->dev, "%s: add route for widget %s",
+ __func__, dai->driver->playback.stream_name);
+ intercon.source = dai->driver->playback.aif_name;
+ intercon.sink = dai->driver->playback.stream_name;
+ dev_dbg(dai->dev, "%s: src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ }
+ if (dai->driver->capture.stream_name &&
+ dai->driver->capture.aif_name) {
+ dev_dbg(dai->dev, "%s: add route for widget %s",
+ __func__, dai->driver->capture.stream_name);
+ intercon.sink = dai->driver->capture.aif_name;
+ intercon.source = dai->driver->capture.stream_name;
+ dev_dbg(dai->dev, "%s: src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ }
+ }
+ return rc;
+}
+
+static int msm_dai_q6_spdif_dai_remove(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_spdif_dai_data *dai_data;
+ int rc;
+
+ dai_data = dev_get_drvdata(dai->dev);
+
+ /* If AFE port is still up, close it */
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ rc = afe_close(dai->id); /* can block */
+
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AFE port\n");
+
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+ }
+ kfree(dai_data);
+
+ return 0;
+}
+
+
+static struct snd_soc_dai_ops msm_dai_q6_spdif_ops = {
+ .prepare = msm_dai_q6_spdif_prepare,
+ .hw_params = msm_dai_q6_spdif_hw_params,
+ .shutdown = msm_dai_q6_spdif_shutdown,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_spdif_spdif_rx_dai = {
+ .playback = {
+ .stream_name = "SPDIF Playback",
+ .aif_name = "SPDIF_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_spdif_ops,
+ .probe = msm_dai_q6_spdif_dai_probe,
+ .remove = msm_dai_q6_spdif_dai_remove,
+};
+
+static const struct snd_soc_component_driver msm_dai_spdif_q6_component = {
+ .name = "msm-dai-q6-spdif",
+};
+
+static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int rc = 0;
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ if (dai_data->enc_config.format != ENC_FMT_NONE) {
+ int bitwidth = 0;
+
+ if (dai_data->afe_in_bitformat ==
+ SNDRV_PCM_FORMAT_S24_LE)
+ bitwidth = 24;
+ else if (dai_data->afe_in_bitformat ==
+ SNDRV_PCM_FORMAT_S16_LE)
+ bitwidth = 16;
+ pr_debug("%s: calling AFE_PORT_START_V2 with enc_format: %d\n",
+ __func__, dai_data->enc_config.format);
+ rc = afe_port_start_v2(dai->id, &dai_data->port_config,
+ dai_data->rate,
+ dai_data->afe_in_channels,
+ bitwidth,
+ &dai_data->enc_config);
+ if (rc < 0)
+ pr_err("%s: afe_port_start_v2 failed error: %d\n",
+ __func__, rc);
+ } else {
+ rc = afe_port_start(dai->id, &dai_data->port_config,
+ dai_data->rate);
+ }
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to open AFE port 0x%x\n",
+ dai->id);
+ else
+ set_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ }
+ return rc;
+}
+
+static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai_data->channels = params_channels(params);
+ switch (dai_data->channels) {
+ case 2:
+ dai_data->port_config.i2s.mono_stereo = MSM_AFE_STEREO;
+ break;
+ case 1:
+ dai_data->port_config.i2s.mono_stereo = MSM_AFE_MONO;
+ break;
+ default:
+ return -EINVAL;
+ pr_err("%s: err channels %d\n",
+ __func__, dai_data->channels);
+ break;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_SPECIAL:
+ dai_data->port_config.i2s.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ dai_data->port_config.i2s.bit_width = 24;
+ break;
+ default:
+ pr_err("%s: format %d\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ dai_data->rate = params_rate(params);
+ dai_data->port_config.i2s.sample_rate = dai_data->rate;
+ dai_data->port_config.i2s.i2s_cfg_minor_version =
+ AFE_API_VERSION_I2S_CONFIG;
+ dai_data->port_config.i2s.data_format = AFE_LINEAR_PCM_DATA;
+ dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
+ dai_data->channels, dai_data->rate);
+
+ dai_data->port_config.i2s.channel_mode = 1;
+ return 0;
+}
+
+static u8 num_of_bits_set(u8 sd_line_mask)
+{
+ u8 num_bits_set = 0;
+
+ while (sd_line_mask) {
+ num_bits_set++;
+ sd_line_mask = sd_line_mask & (sd_line_mask - 1);
+ }
+ return num_bits_set;
+}
+
+static int msm_dai_q6_i2s_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct msm_i2s_data *i2s_pdata =
+ (struct msm_i2s_data *) dai->dev->platform_data;
+
+ dai_data->channels = params_channels(params);
+ if (num_of_bits_set(i2s_pdata->sd_lines) == 1) {
+ switch (dai_data->channels) {
+ case 2:
+ dai_data->port_config.i2s.mono_stereo = MSM_AFE_STEREO;
+ break;
+ case 1:
+ dai_data->port_config.i2s.mono_stereo = MSM_AFE_MONO;
+ break;
+ default:
+ pr_warn("%s: greater than stereo has not been validated %d",
+ __func__, dai_data->channels);
+ break;
+ }
+ }
+ dai_data->rate = params_rate(params);
+ dai_data->port_config.i2s.sample_rate = dai_data->rate;
+ dai_data->port_config.i2s.i2s_cfg_minor_version =
+ AFE_API_VERSION_I2S_CONFIG;
+ dai_data->port_config.i2s.data_format = AFE_LINEAR_PCM_DATA;
+ /* Q6 only supports 16 as now */
+ dai_data->port_config.i2s.bit_width = 16;
+ dai_data->port_config.i2s.channel_mode = 1;
+
+ return 0;
+}
+
+static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai_data->channels = params_channels(params);
+ dai_data->rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_SPECIAL:
+ dai_data->port_config.slim_sch.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ dai_data->port_config.slim_sch.bit_width = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dai_data->port_config.slim_sch.bit_width = 32;
+ break;
+ default:
+ pr_err("%s: format %d\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ dai_data->port_config.slim_sch.sb_cfg_minor_version =
+ AFE_API_VERSION_SLIMBUS_CONFIG;
+ dai_data->port_config.slim_sch.sample_rate = dai_data->rate;
+ dai_data->port_config.slim_sch.num_channels = dai_data->channels;
+
+ switch (dai->id) {
+ case SLIMBUS_7_RX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_RX:
+ case SLIMBUS_8_TX:
+ dai_data->port_config.slim_sch.slimbus_dev_id =
+ AFE_SLIMBUS_DEVICE_2;
+ break;
+ default:
+ dai_data->port_config.slim_sch.slimbus_dev_id =
+ AFE_SLIMBUS_DEVICE_1;
+ break;
+ }
+
+ dev_dbg(dai->dev, "%s:slimbus_dev_id[%hu] bit_wd[%hu] format[%hu]\n"
+ "num_channel %hu shared_ch_mapping[0] %hu\n"
+ "slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
+ "sample_rate %d\n", __func__,
+ dai_data->port_config.slim_sch.slimbus_dev_id,
+ dai_data->port_config.slim_sch.bit_width,
+ dai_data->port_config.slim_sch.data_format,
+ dai_data->port_config.slim_sch.num_channels,
+ dai_data->port_config.slim_sch.shared_ch_mapping[0],
+ dai_data->port_config.slim_sch.shared_ch_mapping[1],
+ dai_data->port_config.slim_sch.shared_ch_mapping[2],
+ dai_data->rate);
+
+ return 0;
+}
+
+static int msm_dai_q6_usb_audio_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai_data->channels = params_channels(params);
+ dai_data->rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_SPECIAL:
+ dai_data->port_config.usb_audio.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ dai_data->port_config.usb_audio.bit_width = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dai_data->port_config.usb_audio.bit_width = 32;
+ break;
+
+ default:
+ dev_err(dai->dev, "%s: invalid format %d\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+ dai_data->port_config.usb_audio.cfg_minor_version =
+ AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG;
+ dai_data->port_config.usb_audio.num_channels = dai_data->channels;
+ dai_data->port_config.usb_audio.sample_rate = dai_data->rate;
+
+ dev_dbg(dai->dev, "%s: dev_id[0x%x] bit_wd[%hu] format[%hu]\n"
+ "num_channel %hu sample_rate %d\n", __func__,
+ dai_data->port_config.usb_audio.dev_token,
+ dai_data->port_config.usb_audio.bit_width,
+ dai_data->port_config.usb_audio.data_format,
+ dai_data->port_config.usb_audio.num_channels,
+ dai_data->port_config.usb_audio.sample_rate);
+
+ return 0;
+}
+
+static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai_data->channels = params_channels(params);
+ dai_data->rate = params_rate(params);
+
+ dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
+ dai_data->channels, dai_data->rate);
+
+ memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
+
+ pr_debug("%s: setting bt_fm parameters\n", __func__);
+
+ dai_data->port_config.int_bt_fm.bt_fm_cfg_minor_version =
+ AFE_API_VERSION_INTERNAL_BT_FM_CONFIG;
+ dai_data->port_config.int_bt_fm.num_channels = dai_data->channels;
+ dai_data->port_config.int_bt_fm.sample_rate = dai_data->rate;
+ dai_data->port_config.int_bt_fm.bit_width = 16;
+
+ return 0;
+}
+
+static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai_data->rate = params_rate(params);
+ dai_data->port_config.rtproxy.num_channels = params_channels(params);
+ dai_data->port_config.rtproxy.sample_rate = params_rate(params);
+
+ pr_debug("channel %d entered,dai_id: %d,rate: %d\n",
+ dai_data->port_config.rtproxy.num_channels, dai->id, dai_data->rate);
+
+ dai_data->port_config.rtproxy.rt_proxy_cfg_minor_version =
+ AFE_API_VERSION_RT_PROXY_CONFIG;
+ dai_data->port_config.rtproxy.bit_width = 16; /* Q6 only supports 16 */
+ dai_data->port_config.rtproxy.interleaved = 1;
+ dai_data->port_config.rtproxy.frame_size = params_period_bytes(params);
+ dai_data->port_config.rtproxy.jitter_allowance =
+ dai_data->port_config.rtproxy.frame_size/2;
+ dai_data->port_config.rtproxy.low_water_mark = 0;
+ dai_data->port_config.rtproxy.high_water_mark = 0;
+
+ return 0;
+}
+
+static int msm_dai_q6_pseudo_port_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai_data->channels = params_channels(params);
+ dai_data->rate = params_rate(params);
+
+ /* Q6 only supports 16 as now */
+ dai_data->port_config.pseudo_port.pseud_port_cfg_minor_version =
+ AFE_API_VERSION_PSEUDO_PORT_CONFIG;
+ dai_data->port_config.pseudo_port.num_channels =
+ params_channels(params);
+ dai_data->port_config.pseudo_port.bit_width = 16;
+ dai_data->port_config.pseudo_port.data_format = 0;
+ dai_data->port_config.pseudo_port.timing_mode =
+ AFE_PSEUDOPORT_TIMING_MODE_TIMER;
+ dai_data->port_config.pseudo_port.sample_rate = params_rate(params);
+
+ dev_dbg(dai->dev, "%s: bit_wd[%hu] num_channels [%hu] format[%hu]\n"
+ "timing Mode %hu sample_rate %d\n", __func__,
+ dai_data->port_config.pseudo_port.bit_width,
+ dai_data->port_config.pseudo_port.num_channels,
+ dai_data->port_config.pseudo_port.data_format,
+ dai_data->port_config.pseudo_port.timing_mode,
+ dai_data->port_config.pseudo_port.sample_rate);
+
+ return 0;
+}
+
+/* Current implementation assumes hw_param is called once
+ * This may not be the case but what to do when ADM and AFE
+ * port are already opened and parameter changes
+ */
+static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int rc = 0;
+
+ switch (dai->id) {
+ case PRIMARY_I2S_TX:
+ case PRIMARY_I2S_RX:
+ case SECONDARY_I2S_RX:
+ rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
+ break;
+ case MI2S_RX:
+ rc = msm_dai_q6_i2s_hw_params(params, dai, substream->stream);
+ break;
+ case SLIMBUS_0_RX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_5_RX:
+ case SLIMBUS_6_RX:
+ case SLIMBUS_7_RX:
+ case SLIMBUS_8_RX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
+ case SLIMBUS_6_TX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_TX:
+ rc = msm_dai_q6_slim_bus_hw_params(params, dai,
+ substream->stream);
+ break;
+ case INT_BT_SCO_RX:
+ case INT_BT_SCO_TX:
+ case INT_BT_A2DP_RX:
+ case INT_FM_RX:
+ case INT_FM_TX:
+ rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
+ break;
+ case AFE_PORT_ID_USB_RX:
+ case AFE_PORT_ID_USB_TX:
+ rc = msm_dai_q6_usb_audio_hw_params(params, dai,
+ substream->stream);
+ break;
+ case RT_PROXY_DAI_001_TX:
+ case RT_PROXY_DAI_001_RX:
+ case RT_PROXY_DAI_002_TX:
+ case RT_PROXY_DAI_002_RX:
+ rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
+ break;
+ case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ rc = msm_dai_q6_pseudo_port_hw_params(params,
+ dai, substream->stream);
+ break;
+ default:
+ dev_err(dai->dev, "invalid AFE port ID 0x%x\n", dai->id);
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int rc = 0;
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ pr_debug("%s: stop pseudo port:%d\n", __func__, dai->id);
+ rc = afe_close(dai->id); /* can block */
+
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AFE port\n");
+ pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
+ *dai_data->status_mask);
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+ }
+}
+
+static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ dai_data->port_config.i2s.ws_src = 1; /* CPU is master */
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ dai_data->port_config.i2s.ws_src = 0; /* CPU is slave */
+ break;
+ default:
+ pr_err("%s: fmt 0x%x\n",
+ __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ int rc = 0;
+
+ dev_dbg(dai->dev, "%s: id = %d fmt[%d]\n", __func__,
+ dai->id, fmt);
+ switch (dai->id) {
+ case PRIMARY_I2S_TX:
+ case PRIMARY_I2S_RX:
+ case MI2S_RX:
+ case SECONDARY_I2S_RX:
+ rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
+ break;
+ default:
+ dev_err(dai->dev, "invalid cpu_dai id 0x%x\n", dai->id);
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+
+{
+ int rc = 0;
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ unsigned int i = 0;
+
+ dev_dbg(dai->dev, "%s: id = %d\n", __func__, dai->id);
+ switch (dai->id) {
+ case SLIMBUS_0_RX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_5_RX:
+ case SLIMBUS_6_RX:
+ case SLIMBUS_7_RX:
+ case SLIMBUS_8_RX:
+ /*
+ * channel number to be between 128 and 255.
+ * For RX port use channel numbers
+ * from 138 to 144 for pre-Taiko
+ * from 144 to 159 for Taiko
+ */
+ if (!rx_slot) {
+ pr_err("%s: rx slot not found\n", __func__);
+ return -EINVAL;
+ }
+ for (i = 0; i < rx_num; i++) {
+ dai_data->port_config.slim_sch.shared_ch_mapping[i] =
+ rx_slot[i];
+ pr_debug("%s: find number of channels[%d] ch[%d]\n",
+ __func__, i, rx_slot[i]);
+ }
+ dai_data->port_config.slim_sch.num_channels = rx_num;
+ pr_debug("%s: SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
+ (dai->id - SLIMBUS_0_RX) / 2, rx_num,
+ dai_data->port_config.slim_sch.shared_ch_mapping[0],
+ dai_data->port_config.slim_sch.shared_ch_mapping[1]);
+
+ break;
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
+ case SLIMBUS_6_TX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_TX:
+ /*
+ * channel number to be between 128 and 255.
+ * For TX port use channel numbers
+ * from 128 to 137 for pre-Taiko
+ * from 128 to 143 for Taiko
+ */
+ if (!tx_slot) {
+ pr_err("%s: tx slot not found\n", __func__);
+ return -EINVAL;
+ }
+ for (i = 0; i < tx_num; i++) {
+ dai_data->port_config.slim_sch.shared_ch_mapping[i] =
+ tx_slot[i];
+ pr_debug("%s: find number of channels[%d] ch[%d]\n",
+ __func__, i, tx_slot[i]);
+ }
+ dai_data->port_config.slim_sch.num_channels = tx_num;
+ pr_debug("%s:SLIMBUS_%d_TX cnt[%d] ch[%d %d]\n", __func__,
+ (dai->id - SLIMBUS_0_TX) / 2, tx_num,
+ dai_data->port_config.slim_sch.shared_ch_mapping[0],
+ dai_data->port_config.slim_sch.shared_ch_mapping[1]);
+ break;
+ default:
+ dev_err(dai->dev, "invalid cpu_dai id 0x%x\n", dai->id);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_ops = {
+ .prepare = msm_dai_q6_prepare,
+ .hw_params = msm_dai_q6_hw_params,
+ .shutdown = msm_dai_q6_shutdown,
+ .set_fmt = msm_dai_q6_set_fmt,
+ .set_channel_map = msm_dai_q6_set_channel_map,
+};
+
+/*
+ * For single CPU DAI registration, the dai id needs to be
+ * set explicitly in the dai probe as ASoC does not read
+ * the cpu->driver->id field rather it assigns the dai id
+ * from the device name that is in the form %s.%d. This dai
+ * id should be assigned to back-end AFE port id and used
+ * during dai prepare. For multiple dai registration, it
+ * is not required to call this function, however the dai->
+ * driver->id field must be defined and set to corresponding
+ * AFE Port id.
+ */
+static inline void msm_dai_q6_set_dai_id(struct snd_soc_dai *dai)
+{
+ if (!dai->driver->id) {
+ dev_warn(dai->dev, "DAI driver id is not set\n");
+ return;
+ }
+ dai->id = dai->driver->id;
+}
+
+static int msm_dai_q6_cal_info_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+ u16 port_id = ((struct soc_enum *)
+ kcontrol->private_value)->reg;
+
+ dai_data->cal_mode = ucontrol->value.integer.value[0];
+ pr_debug("%s: setting cal_mode to %d\n",
+ __func__, dai_data->cal_mode);
+ afe_set_cal_mode(port_id, dai_data->cal_mode);
+
+ return 0;
+}
+
+static int msm_dai_q6_cal_info_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ ucontrol->value.integer.value[0] = dai_data->cal_mode;
+ return 0;
+}
+
+static int msm_dai_q6_sb_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+ int value = ucontrol->value.integer.value[0];
+
+ if (dai_data) {
+ dai_data->port_config.slim_sch.data_format = value;
+ pr_debug("%s: format = %d\n", __func__, value);
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_sb_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data)
+ ucontrol->value.integer.value[0] =
+ dai_data->port_config.slim_sch.data_format;
+
+ return 0;
+}
+
+static int msm_dai_q6_usb_audio_cfg_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+ u32 val = ucontrol->value.integer.value[0];
+
+ if (dai_data) {
+ dai_data->port_config.usb_audio.dev_token = val;
+ pr_debug("%s: dev_token = 0x%x\n", __func__,
+ dai_data->port_config.usb_audio.dev_token);
+ } else {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_usb_audio_cfg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data) {
+ ucontrol->value.integer.value[0] =
+ dai_data->port_config.usb_audio.dev_token;
+ pr_debug("%s: dev_token = 0x%x\n", __func__,
+ dai_data->port_config.usb_audio.dev_token);
+ } else {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_afe_enc_cfg_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(struct afe_enc_config);
+
+ return 0;
+}
+
+static int msm_dai_q6_afe_enc_cfg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data) {
+ int format_size = sizeof(dai_data->enc_config.format);
+
+ pr_debug("%s:encoder config for %d format\n",
+ __func__, dai_data->enc_config.format);
+ memcpy(ucontrol->value.bytes.data,
+ &dai_data->enc_config.format,
+ format_size);
+ switch (dai_data->enc_config.format) {
+ case ENC_FMT_SBC:
+ memcpy(ucontrol->value.bytes.data + format_size,
+ &dai_data->enc_config.data,
+ sizeof(struct asm_sbc_enc_cfg_t));
+ break;
+ case ENC_FMT_AAC_V2:
+ memcpy(ucontrol->value.bytes.data + format_size,
+ &dai_data->enc_config.data,
+ sizeof(struct asm_aac_enc_cfg_v2_t));
+ break;
+ case ENC_FMT_APTX:
+ case ENC_FMT_APTX_HD:
+ memcpy(ucontrol->value.bytes.data + format_size,
+ &dai_data->enc_config.data,
+ sizeof(struct asm_aac_enc_cfg_v2_t));
+ break;
+ default:
+ pr_debug("%s: unknown format = %d\n",
+ __func__, dai_data->enc_config.format);
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int msm_dai_q6_afe_enc_cfg_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data) {
+ int format_size = sizeof(dai_data->enc_config.format);
+
+ memset(&dai_data->enc_config, 0x0,
+ sizeof(struct afe_enc_config));
+ memcpy(&dai_data->enc_config.format,
+ ucontrol->value.bytes.data,
+ format_size);
+ pr_debug("%s: Received encoder config for %d format\n",
+ __func__, dai_data->enc_config.format);
+ switch (dai_data->enc_config.format) {
+ case ENC_FMT_SBC:
+ memcpy(&dai_data->enc_config.data,
+ ucontrol->value.bytes.data + format_size,
+ sizeof(struct asm_sbc_enc_cfg_t));
+ break;
+ case ENC_FMT_AAC_V2:
+ memcpy(&dai_data->enc_config.data,
+ ucontrol->value.bytes.data + format_size,
+ sizeof(struct asm_aac_enc_cfg_v2_t));
+ break;
+ case ENC_FMT_APTX:
+ case ENC_FMT_APTX_HD:
+ memcpy(&dai_data->enc_config.data,
+ ucontrol->value.bytes.data + format_size,
+ sizeof(struct asm_custom_enc_cfg_aptx_t));
+ break;
+ default:
+ pr_debug("%s: Ignore enc config for unknown format = %d\n",
+ __func__, dai_data->enc_config.format);
+ ret = -EINVAL;
+ break;
+ }
+ } else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static const char *const afe_input_chs_text[] = {"Zero", "One", "Two"};
+
+static const struct soc_enum afe_input_chs_enum[] = {
+ SOC_ENUM_SINGLE_EXT(3, afe_input_chs_text),
+};
+
+static const char *const afe_input_bit_format_text[] = {"S16_LE", "S24_LE"};
+
+static const struct soc_enum afe_input_bit_format_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, afe_input_bit_format_text),
+};
+
+static int msm_dai_q6_afe_input_channel_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data) {
+ ucontrol->value.integer.value[0] = dai_data->afe_in_channels;
+ pr_debug("%s:afe input channel = %d\n",
+ __func__, dai_data->afe_in_channels);
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_afe_input_channel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data) {
+ dai_data->afe_in_channels = ucontrol->value.integer.value[0];
+ pr_debug("%s: updating afe input channel : %d\n",
+ __func__, dai_data->afe_in_channels);
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_afe_input_bit_format_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (!dai_data) {
+ pr_err("%s: Invalid dai data\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (dai_data->afe_in_bitformat) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: afe input bit format : %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_dai_q6_afe_input_bit_format_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (!dai_data) {
+ pr_err("%s: Invalid dai data\n", __func__);
+ return -EINVAL;
+ }
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: updating afe input bit format : %d\n",
+ __func__, dai_data->afe_in_bitformat);
+
+ return 0;
+}
+
+
+static const struct snd_kcontrol_new afe_enc_config_controls[] = {
+ {
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE),
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SLIM_7_RX Encoder Config",
+ .info = msm_dai_q6_afe_enc_cfg_info,
+ .get = msm_dai_q6_afe_enc_cfg_get,
+ .put = msm_dai_q6_afe_enc_cfg_put,
+ },
+ SOC_ENUM_EXT("AFE Input Channels", afe_input_chs_enum[0],
+ msm_dai_q6_afe_input_channel_get,
+ msm_dai_q6_afe_input_channel_put),
+ SOC_ENUM_EXT("AFE Input Bit Format", afe_input_bit_format_enum[0],
+ msm_dai_q6_afe_input_bit_format_get,
+ msm_dai_q6_afe_input_bit_format_put),
+};
+
+static const char * const afe_cal_mode_text[] = {
+ "CAL_MODE_DEFAULT", "CAL_MODE_NONE"
+};
+
+static const struct soc_enum slim_2_rx_enum =
+ SOC_ENUM_SINGLE(SLIMBUS_2_RX, 0, ARRAY_SIZE(afe_cal_mode_text),
+ afe_cal_mode_text);
+
+static const struct soc_enum rt_proxy_1_rx_enum =
+ SOC_ENUM_SINGLE(RT_PROXY_PORT_001_RX, 0, ARRAY_SIZE(afe_cal_mode_text),
+ afe_cal_mode_text);
+
+static const struct soc_enum rt_proxy_1_tx_enum =
+ SOC_ENUM_SINGLE(RT_PROXY_PORT_001_TX, 0, ARRAY_SIZE(afe_cal_mode_text),
+ afe_cal_mode_text);
+
+static const struct snd_kcontrol_new sb_config_controls[] = {
+ SOC_ENUM_EXT("SLIM_4_TX Format", sb_config_enum[0],
+ msm_dai_q6_sb_format_get,
+ msm_dai_q6_sb_format_put),
+ SOC_ENUM_EXT("SLIM_2_RX SetCalMode", slim_2_rx_enum,
+ msm_dai_q6_cal_info_get,
+ msm_dai_q6_cal_info_put),
+ SOC_ENUM_EXT("SLIM_2_RX Format", sb_config_enum[0],
+ msm_dai_q6_sb_format_get,
+ msm_dai_q6_sb_format_put)
+};
+
+static const struct snd_kcontrol_new rt_proxy_config_controls[] = {
+ SOC_ENUM_EXT("RT_PROXY_1_RX SetCalMode", rt_proxy_1_rx_enum,
+ msm_dai_q6_cal_info_get,
+ msm_dai_q6_cal_info_put),
+ SOC_ENUM_EXT("RT_PROXY_1_TX SetCalMode", rt_proxy_1_tx_enum,
+ msm_dai_q6_cal_info_get,
+ msm_dai_q6_cal_info_put),
+};
+
+static const struct snd_kcontrol_new usb_audio_cfg_controls[] = {
+ SOC_SINGLE_EXT("USB_AUDIO_RX dev_token", 0, 0, UINT_MAX, 0,
+ msm_dai_q6_usb_audio_cfg_get,
+ msm_dai_q6_usb_audio_cfg_put),
+ SOC_SINGLE_EXT("USB_AUDIO_TX dev_token", 0, 0, UINT_MAX, 0,
+ msm_dai_q6_usb_audio_cfg_get,
+ msm_dai_q6_usb_audio_cfg_put),
+};
+
+static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data;
+ int rc = 0;
+
+ if (!dai) {
+ pr_err("%s: Invalid params dai\n", __func__);
+ return -EINVAL;
+ }
+ if (!dai->dev) {
+ pr_err("%s: Invalid params dai dev\n", __func__);
+ return -EINVAL;
+ }
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
+
+ if (!dai_data)
+ rc = -ENOMEM;
+ else
+ dev_set_drvdata(dai->dev, dai_data);
+
+ msm_dai_q6_set_dai_id(dai);
+
+ switch (dai->id) {
+ case SLIMBUS_4_TX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&sb_config_controls[0],
+ dai_data));
+ break;
+ case SLIMBUS_2_RX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&sb_config_controls[1],
+ dai_data));
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&sb_config_controls[2],
+ dai_data));
+ break;
+ case SLIMBUS_7_RX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&afe_enc_config_controls[0],
+ dai_data));
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&afe_enc_config_controls[1],
+ dai_data));
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&afe_enc_config_controls[2],
+ dai_data));
+ break;
+ case RT_PROXY_DAI_001_RX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&rt_proxy_config_controls[0],
+ dai_data));
+ break;
+ case RT_PROXY_DAI_001_TX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&rt_proxy_config_controls[1],
+ dai_data));
+ break;
+ case AFE_PORT_ID_USB_RX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&usb_audio_cfg_controls[0],
+ dai_data));
+ break;
+ case AFE_PORT_ID_USB_TX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&usb_audio_cfg_controls[1],
+ dai_data));
+ break;
+ }
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "%s: err add config ctl, DAI = %s\n",
+ __func__, dai->name);
+
+ rc = msm_dai_q6_dai_add_route(dai);
+ return rc;
+}
+
+static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data;
+ int rc;
+
+ dai_data = dev_get_drvdata(dai->dev);
+
+ /* If AFE port is still up, close it */
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ pr_debug("%s: stop pseudo port:%d\n", __func__, dai->id);
+ rc = afe_close(dai->id); /* can block */
+
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AFE port\n");
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+ }
+ kfree(dai_data);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai[] = {
+ {
+ .playback = {
+ .stream_name = "AFE Playback",
+ .aif_name = "PCM_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = RT_PROXY_DAI_001_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "AFE-PROXY RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = RT_PROXY_DAI_002_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai[] = {
+ {
+ .capture = {
+ .stream_name = "AFE Capture",
+ .aif_name = "PCM_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = RT_PROXY_DAI_002_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "AFE-PROXY TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = RT_PROXY_DAI_001_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
+ .playback = {
+ .stream_name = "Internal BT-SCO Playback",
+ .aif_name = "INT_BT_SCO_RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = INT_BT_SCO_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_bt_a2dp_rx_dai = {
+ .playback = {
+ .stream_name = "Internal BT-A2DP Playback",
+ .aif_name = "INT_BT_A2DP_RX",
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_max = 48000,
+ .rate_min = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = INT_BT_A2DP_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
+ .capture = {
+ .stream_name = "Internal BT-SCO Capture",
+ .aif_name = "INT_BT_SCO_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = INT_BT_SCO_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
+ .playback = {
+ .stream_name = "Internal FM Playback",
+ .aif_name = "INT_FM_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = INT_FM_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
+ .capture = {
+ .stream_name = "Internal FM Capture",
+ .aif_name = "INT_FM_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = INT_FM_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_voc_playback_dai[] = {
+ {
+ .playback = {
+ .stream_name = "Voice Farend Playback",
+ .aif_name = "VOICE_PLAYBACK_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = VOICE_PLAYBACK_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Voice2 Farend Playback",
+ .aif_name = "VOICE2_PLAYBACK_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = VOICE2_PLAYBACK_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai[] = {
+ {
+ .capture = {
+ .stream_name = "Voice Uplink Capture",
+ .aif_name = "INCALL_RECORD_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = VOICE_RECORD_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Voice Downlink Capture",
+ .aif_name = "INCALL_RECORD_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = VOICE_RECORD_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_usb_rx_dai = {
+ .playback = {
+ .stream_name = "USB Audio Playback",
+ .aif_name = "USB_AUDIO_RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+ SNDRV_PCM_RATE_384000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_max = 384000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = AFE_PORT_ID_USB_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_usb_tx_dai = {
+ .capture = {
+ .stream_name = "USB Audio Capture",
+ .aif_name = "USB_AUDIO_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+ SNDRV_PCM_RATE_384000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_max = 384000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = AFE_PORT_ID_USB_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static int msm_auxpcm_dev_probe(struct platform_device *pdev)
+{
+ struct msm_dai_q6_auxpcm_dai_data *dai_data;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata;
+ uint32_t val_array[RATE_MAX_NUM_OF_AUX_PCM_RATES];
+ uint32_t val = 0;
+ const char *intf_name;
+ int rc = 0, i = 0, len = 0;
+ const uint32_t *slot_mapping_array = NULL;
+ u32 array_length = 0;
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_auxpcm_dai_data),
+ GFP_KERNEL);
+ if (!dai_data)
+ return -ENOMEM;
+
+ auxpcm_pdata = kzalloc(sizeof(struct msm_dai_auxpcm_pdata),
+ GFP_KERNEL);
+
+ if (!auxpcm_pdata) {
+ dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+ goto fail_pdata_nomem;
+ }
+
+ dev_dbg(&pdev->dev, "%s: dev %pK, dai_data %pK, auxpcm_pdata %pK\n",
+ __func__, &pdev->dev, dai_data, auxpcm_pdata);
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-mode",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-mode missing in DT node\n",
+ __func__);
+ goto fail_invalid_dt;
+ }
+ auxpcm_pdata->mode_8k.mode = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.mode = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-sync",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-sync missing in DT node\n",
+ __func__);
+ goto fail_invalid_dt;
+ }
+ auxpcm_pdata->mode_8k.sync = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.sync = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-frame",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+
+ if (rc) {
+ dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-frame missing in DT node\n",
+ __func__);
+ goto fail_invalid_dt;
+ }
+ auxpcm_pdata->mode_8k.frame = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.frame = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-quant",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-quant missing in DT node\n",
+ __func__);
+ goto fail_invalid_dt;
+ }
+ auxpcm_pdata->mode_8k.quant = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.quant = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-num-slots",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-num-slots missing in DT node\n",
+ __func__);
+ goto fail_invalid_dt;
+ }
+ auxpcm_pdata->mode_8k.num_slots = (u16)val_array[RATE_8KHZ];
+
+ if (auxpcm_pdata->mode_8k.num_slots >
+ msm_dai_q6_max_num_slot(auxpcm_pdata->mode_8k.frame)) {
+ dev_err(&pdev->dev, "%s Max slots %d greater than DT node %d\n",
+ __func__,
+ msm_dai_q6_max_num_slot(auxpcm_pdata->mode_8k.frame),
+ auxpcm_pdata->mode_8k.num_slots);
+ rc = -EINVAL;
+ goto fail_invalid_dt;
+ }
+ auxpcm_pdata->mode_16k.num_slots = (u16)val_array[RATE_16KHZ];
+
+ if (auxpcm_pdata->mode_16k.num_slots >
+ msm_dai_q6_max_num_slot(auxpcm_pdata->mode_16k.frame)) {
+ dev_err(&pdev->dev, "%s Max slots %d greater than DT node %d\n",
+ __func__,
+ msm_dai_q6_max_num_slot(auxpcm_pdata->mode_16k.frame),
+ auxpcm_pdata->mode_16k.num_slots);
+ rc = -EINVAL;
+ goto fail_invalid_dt;
+ }
+
+ slot_mapping_array = of_get_property(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-slot-mapping", &len);
+
+ if (slot_mapping_array == NULL) {
+ dev_err(&pdev->dev, "%s slot_mapping_array is not valid\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_invalid_dt;
+ }
+
+ array_length = auxpcm_pdata->mode_8k.num_slots +
+ auxpcm_pdata->mode_16k.num_slots;
+
+ if (len != sizeof(uint32_t) * array_length) {
+ dev_err(&pdev->dev, "%s Length is %d and expected is %zd\n",
+ __func__, len, sizeof(uint32_t) * array_length);
+ rc = -EINVAL;
+ goto fail_invalid_dt;
+ }
+
+ auxpcm_pdata->mode_8k.slot_mapping =
+ kzalloc(sizeof(uint16_t) *
+ auxpcm_pdata->mode_8k.num_slots,
+ GFP_KERNEL);
+ if (!auxpcm_pdata->mode_8k.slot_mapping) {
+ dev_err(&pdev->dev, "%s No mem for mode_8k slot mapping\n",
+ __func__);
+ rc = -ENOMEM;
+ goto fail_invalid_dt;
+ }
+
+ for (i = 0; i < auxpcm_pdata->mode_8k.num_slots; i++)
+ auxpcm_pdata->mode_8k.slot_mapping[i] =
+ (u16)be32_to_cpu(slot_mapping_array[i]);
+
+ auxpcm_pdata->mode_16k.slot_mapping =
+ kzalloc(sizeof(uint16_t) *
+ auxpcm_pdata->mode_16k.num_slots,
+ GFP_KERNEL);
+
+ if (!auxpcm_pdata->mode_16k.slot_mapping) {
+ dev_err(&pdev->dev, "%s No mem for mode_16k slot mapping\n",
+ __func__);
+ rc = -ENOMEM;
+ goto fail_invalid_16k_slot_mapping;
+ }
+
+ for (i = 0; i < auxpcm_pdata->mode_16k.num_slots; i++)
+ auxpcm_pdata->mode_16k.slot_mapping[i] =
+ (u16)be32_to_cpu(slot_mapping_array[i +
+ auxpcm_pdata->mode_8k.num_slots]);
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-data",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-data missing in DT node\n",
+ __func__);
+ goto fail_invalid_dt1;
+ }
+ auxpcm_pdata->mode_8k.data = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.data = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-pcm-clk-rate",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: qcom,msm-cpudai-auxpcm-pcm-clk-rate missing in DT\n",
+ __func__);
+ goto fail_invalid_dt1;
+ }
+ auxpcm_pdata->mode_8k.pcm_clk_rate = (int)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.pcm_clk_rate = (int)val_array[RATE_16KHZ];
+
+ rc = of_property_read_string(pdev->dev.of_node,
+ "qcom,msm-auxpcm-interface", &intf_name);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: qcom,msm-auxpcm-interface missing in DT node\n",
+ __func__);
+ goto fail_nodev_intf;
+ }
+
+ if (!strcmp(intf_name, "primary")) {
+ dai_data->rx_pid = AFE_PORT_ID_PRIMARY_PCM_RX;
+ dai_data->tx_pid = AFE_PORT_ID_PRIMARY_PCM_TX;
+ pdev->id = MSM_DAI_PRI_AUXPCM_DT_DEV_ID;
+ i = 0;
+ } else if (!strcmp(intf_name, "secondary")) {
+ dai_data->rx_pid = AFE_PORT_ID_SECONDARY_PCM_RX;
+ dai_data->tx_pid = AFE_PORT_ID_SECONDARY_PCM_TX;
+ pdev->id = MSM_DAI_SEC_AUXPCM_DT_DEV_ID;
+ i = 1;
+ } else if (!strcmp(intf_name, "tertiary")) {
+ dai_data->rx_pid = AFE_PORT_ID_TERTIARY_PCM_RX;
+ dai_data->tx_pid = AFE_PORT_ID_TERTIARY_PCM_TX;
+ pdev->id = MSM_DAI_TERT_AUXPCM_DT_DEV_ID;
+ i = 2;
+ } else if (!strcmp(intf_name, "quaternary")) {
+ dai_data->rx_pid = AFE_PORT_ID_QUATERNARY_PCM_RX;
+ dai_data->tx_pid = AFE_PORT_ID_QUATERNARY_PCM_TX;
+ pdev->id = MSM_DAI_QUAT_AUXPCM_DT_DEV_ID;
+ i = 3;
+ } else {
+ dev_err(&pdev->dev, "%s: invalid DT intf name %s\n",
+ __func__, intf_name);
+ goto fail_invalid_intf;
+ }
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-afe-clk-ver", &val);
+ if (rc)
+ dai_data->afe_clk_ver = AFE_CLK_VERSION_V1;
+ else
+ dai_data->afe_clk_ver = val;
+
+ mutex_init(&dai_data->rlock);
+ dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+
+ dev_set_drvdata(&pdev->dev, dai_data);
+ pdev->dev.platform_data = (void *) auxpcm_pdata;
+
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_aux_pcm_dai_component,
+ &msm_dai_q6_aux_pcm_dai[i], 1);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: auxpcm dai reg failed, rc=%d\n",
+ __func__, rc);
+ goto fail_reg_dai;
+ }
+
+ return rc;
+
+fail_reg_dai:
+fail_invalid_intf:
+fail_nodev_intf:
+fail_invalid_dt1:
+ kfree(auxpcm_pdata->mode_16k.slot_mapping);
+fail_invalid_16k_slot_mapping:
+ kfree(auxpcm_pdata->mode_8k.slot_mapping);
+fail_invalid_dt:
+ kfree(auxpcm_pdata);
+fail_pdata_nomem:
+ kfree(dai_data);
+ return rc;
+}
+
+static int msm_auxpcm_dev_remove(struct platform_device *pdev)
+{
+ struct msm_dai_q6_auxpcm_dai_data *dai_data;
+
+ dai_data = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_component(&pdev->dev);
+
+ mutex_destroy(&dai_data->rlock);
+ kfree(dai_data);
+ kfree(pdev->dev.platform_data);
+
+ return 0;
+}
+
+static const struct of_device_id msm_auxpcm_dev_dt_match[] = {
+ { .compatible = "qcom,msm-auxpcm-dev", },
+ {}
+};
+
+
+static struct platform_driver msm_auxpcm_dev_driver = {
+ .probe = msm_auxpcm_dev_probe,
+ .remove = msm_auxpcm_dev_remove,
+ .driver = {
+ .name = "msm-auxpcm-dev",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_auxpcm_dev_dt_match,
+ },
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = {
+ {
+ .playback = {
+ .stream_name = "Slimbus Playback",
+ .aif_name = "SLIMBUS_0_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_0_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Slimbus1 Playback",
+ .aif_name = "SLIMBUS_1_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_1_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Slimbus2 Playback",
+ .aif_name = "SLIMBUS_2_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_2_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Slimbus3 Playback",
+ .aif_name = "SLIMBUS_3_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_3_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Slimbus4 Playback",
+ .aif_name = "SLIMBUS_4_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_4_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Slimbus6 Playback",
+ .aif_name = "SLIMBUS_6_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_6_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Slimbus5 Playback",
+ .aif_name = "SLIMBUS_5_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_5_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Slimbus7 Playback",
+ .aif_name = "SLIMBUS_7_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_7_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Slimbus8 Playback",
+ .aif_name = "SLIMBUS_8_RX",
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .formats = DAI_FORMATS_S16_S24_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_8_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai[] = {
+ {
+ .capture = {
+ .stream_name = "Slimbus Capture",
+ .aif_name = "SLIMBUS_0_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_0_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Slimbus1 Capture",
+ .aif_name = "SLIMBUS_1_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_1_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Slimbus2 Capture",
+ .aif_name = "SLIMBUS_2_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_2_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Slimbus3 Capture",
+ .aif_name = "SLIMBUS_3_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_3_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Slimbus4 Capture",
+ .aif_name = "SLIMBUS_4_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_4_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Slimbus5 Capture",
+ .aif_name = "SLIMBUS_5_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_5_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Slimbus6 Capture",
+ .aif_name = "SLIMBUS_6_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_6_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Slimbus7 Capture",
+ .aif_name = "SLIMBUS_7_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_7_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Slimbus8 Capture",
+ .aif_name = "SLIMBUS_8_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = SLIMBUS_8_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
+};
+
+static int msm_dai_q6_mi2s_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+ int value = ucontrol->value.integer.value[0];
+
+ dai_data->port_config.i2s.data_format = value;
+ pr_debug("%s: value = %d, channel = %d, line = %d\n",
+ __func__, value, dai_data->port_config.i2s.mono_stereo,
+ dai_data->port_config.i2s.channel_mode);
+ return 0;
+}
+
+static int msm_dai_q6_mi2s_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ ucontrol->value.integer.value[0] =
+ dai_data->port_config.i2s.data_format;
+ return 0;
+}
+
+static const struct snd_kcontrol_new mi2s_config_controls[] = {
+ SOC_ENUM_EXT("PRI MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("SEC MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("TERT MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("QUAT MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("QUIN MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("PRI MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("SEC MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("TERT MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("QUAT MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("QUIN MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("SENARY MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+};
+
+static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_mi2s_pdata *mi2s_pdata =
+ (struct msm_mi2s_pdata *) dai->dev->platform_data;
+ struct snd_kcontrol *kcontrol = NULL;
+ int rc = 0;
+ const struct snd_kcontrol_new *ctrl = NULL;
+
+ dai->id = mi2s_pdata->intf_id;
+
+ if (mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.i2s.channel_mode) {
+ if (dai->id == MSM_PRIM_MI2S)
+ ctrl = &mi2s_config_controls[0];
+ if (dai->id == MSM_SEC_MI2S)
+ ctrl = &mi2s_config_controls[1];
+ if (dai->id == MSM_TERT_MI2S)
+ ctrl = &mi2s_config_controls[2];
+ if (dai->id == MSM_QUAT_MI2S)
+ ctrl = &mi2s_config_controls[3];
+ if (dai->id == MSM_QUIN_MI2S)
+ ctrl = &mi2s_config_controls[4];
+ }
+
+ if (ctrl) {
+ kcontrol = snd_ctl_new1(ctrl,
+ &mi2s_dai_data->rx_dai.mi2s_dai_data);
+ rc = snd_ctl_add(dai->component->card->snd_card, kcontrol);
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: err add RX fmt ctl DAI = %s\n",
+ __func__, dai->name);
+ goto rtn;
+ }
+ }
+
+ ctrl = NULL;
+ if (mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode) {
+ if (dai->id == MSM_PRIM_MI2S)
+ ctrl = &mi2s_config_controls[4];
+ if (dai->id == MSM_SEC_MI2S)
+ ctrl = &mi2s_config_controls[5];
+ if (dai->id == MSM_TERT_MI2S)
+ ctrl = &mi2s_config_controls[6];
+ if (dai->id == MSM_QUAT_MI2S)
+ ctrl = &mi2s_config_controls[7];
+ if (dai->id == MSM_QUIN_MI2S)
+ ctrl = &mi2s_config_controls[9];
+ if (dai->id == MSM_SENARY_MI2S)
+ ctrl = &mi2s_config_controls[10];
+ }
+
+ if (ctrl) {
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(ctrl,
+ &mi2s_dai_data->tx_dai.mi2s_dai_data));
+
+ if (IS_ERR_VALUE(rc)) {
+ if (kcontrol)
+ snd_ctl_remove(dai->component->card->snd_card,
+ kcontrol);
+ dev_err(dai->dev, "%s: err add TX fmt ctl DAI = %s\n",
+ __func__, dai->name);
+ }
+ }
+ rc = msm_dai_q6_dai_add_route(dai);
+rtn:
+ return rc;
+}
+
+
+static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ int rc;
+
+ /* If AFE port is still up, close it */
+ if (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask)) {
+ rc = afe_close(MI2S_RX); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close MI2S_RX port\n");
+ clear_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask);
+ }
+ if (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
+ rc = afe_close(MI2S_TX); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close MI2S_TX port\n");
+ clear_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask);
+ }
+ kfree(mi2s_dai_data);
+ return 0;
+}
+
+static int msm_dai_q6_mi2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+
+ return 0;
+}
+
+
+static int msm_mi2s_get_port_id(u32 mi2s_id, int stream, u16 *port_id)
+{
+ int ret = 0;
+
+ switch (stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ switch (mi2s_id) {
+ case MSM_PRIM_MI2S:
+ *port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
+ break;
+ case MSM_SEC_MI2S:
+ *port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+ break;
+ case MSM_TERT_MI2S:
+ *port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+ break;
+ case MSM_QUAT_MI2S:
+ *port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ break;
+ case MSM_SEC_MI2S_SD1:
+ *port_id = AFE_PORT_ID_SECONDARY_MI2S_RX_SD1;
+ break;
+ case MSM_QUIN_MI2S:
+ *port_id = AFE_PORT_ID_QUINARY_MI2S_RX;
+ break;
+ case MSM_INT0_MI2S:
+ *port_id = AFE_PORT_ID_INT0_MI2S_RX;
+ break;
+ case MSM_INT1_MI2S:
+ *port_id = AFE_PORT_ID_INT1_MI2S_RX;
+ break;
+ case MSM_INT2_MI2S:
+ *port_id = AFE_PORT_ID_INT2_MI2S_RX;
+ break;
+ case MSM_INT3_MI2S:
+ *port_id = AFE_PORT_ID_INT3_MI2S_RX;
+ break;
+ case MSM_INT4_MI2S:
+ *port_id = AFE_PORT_ID_INT4_MI2S_RX;
+ break;
+ case MSM_INT5_MI2S:
+ *port_id = AFE_PORT_ID_INT5_MI2S_RX;
+ break;
+ case MSM_INT6_MI2S:
+ *port_id = AFE_PORT_ID_INT6_MI2S_RX;
+ break;
+ default:
+ pr_err("%s: playback err id 0x%x\n",
+ __func__, mi2s_id);
+ ret = -1;
+ break;
+ }
+ break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+ switch (mi2s_id) {
+ case MSM_PRIM_MI2S:
+ *port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ break;
+ case MSM_SEC_MI2S:
+ *port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case MSM_TERT_MI2S:
+ *port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case MSM_QUAT_MI2S:
+ *port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
+ case MSM_QUIN_MI2S:
+ *port_id = AFE_PORT_ID_QUINARY_MI2S_TX;
+ break;
+ case MSM_SENARY_MI2S:
+ *port_id = AFE_PORT_ID_SENARY_MI2S_TX;
+ break;
+ case MSM_INT0_MI2S:
+ *port_id = AFE_PORT_ID_INT0_MI2S_TX;
+ break;
+ case MSM_INT1_MI2S:
+ *port_id = AFE_PORT_ID_INT1_MI2S_TX;
+ break;
+ case MSM_INT2_MI2S:
+ *port_id = AFE_PORT_ID_INT2_MI2S_TX;
+ break;
+ case MSM_INT3_MI2S:
+ *port_id = AFE_PORT_ID_INT3_MI2S_TX;
+ break;
+ case MSM_INT4_MI2S:
+ *port_id = AFE_PORT_ID_INT4_MI2S_TX;
+ break;
+ case MSM_INT5_MI2S:
+ *port_id = AFE_PORT_ID_INT5_MI2S_TX;
+ break;
+ case MSM_INT6_MI2S:
+ *port_id = AFE_PORT_ID_INT6_MI2S_TX;
+ break;
+ default:
+ pr_err("%s: capture err id 0x%x\n", __func__, mi2s_id);
+ ret = -1;
+ break;
+ }
+ break;
+ default:
+ pr_err("%s: default err %d\n", __func__, stream);
+ ret = -1;
+ break;
+ }
+ pr_debug("%s: port_id = 0x%x\n", __func__, *port_id);
+ return ret;
+}
+
+static int msm_dai_q6_mi2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai.mi2s_dai_data :
+ &mi2s_dai_data->tx_dai.mi2s_dai_data);
+ u16 port_id = 0;
+ int rc = 0;
+
+ if (msm_mi2s_get_port_id(dai->id, substream->stream,
+ &port_id) != 0) {
+ dev_err(dai->dev, "%s: Invalid Port ID 0x%x\n",
+ __func__, port_id);
+ return -EINVAL;
+ }
+
+ dev_dbg(dai->dev, "%s: dai id %d, afe port id = 0x%x\n"
+ "dai_data->channels = %u sample_rate = %u\n", __func__,
+ dai->id, port_id, dai_data->channels, dai_data->rate);
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ /* PORT START should be set if prepare called
+ * in active state.
+ */
+ rc = afe_port_start(port_id, &dai_data->port_config,
+ dai_data->rate);
+
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to open AFE port 0x%x\n",
+ dai->id);
+ else
+ set_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ }
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status)) {
+ set_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
+ dev_dbg(dai->dev, "%s: set hwfree_status to started\n",
+ __func__);
+ }
+ return rc;
+}
+
+static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_mi2s_dai_config *mi2s_dai_config =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+ struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
+ struct afe_param_id_i2s_cfg *i2s = &dai_data->port_config.i2s;
+
+ dai_data->channels = params_channels(params);
+ switch (dai_data->channels) {
+ case 8:
+ case 7:
+ if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_8CHS)
+ goto error_invalid_data;
+ dai_data->port_config.i2s.channel_mode = AFE_PORT_I2S_8CHS;
+ break;
+ case 6:
+ case 5:
+ if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_6CHS)
+ goto error_invalid_data;
+ dai_data->port_config.i2s.channel_mode = AFE_PORT_I2S_6CHS;
+ break;
+ case 4:
+ case 3:
+ if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_QUAD01)
+ goto error_invalid_data;
+ if (mi2s_dai_config->pdata_mi2s_lines == AFE_PORT_I2S_QUAD23)
+ dai_data->port_config.i2s.channel_mode =
+ mi2s_dai_config->pdata_mi2s_lines;
+ else
+ dai_data->port_config.i2s.channel_mode =
+ AFE_PORT_I2S_QUAD01;
+ break;
+ case 2:
+ case 1:
+ if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_SD0)
+ goto error_invalid_data;
+ switch (mi2s_dai_config->pdata_mi2s_lines) {
+ case AFE_PORT_I2S_SD0:
+ case AFE_PORT_I2S_SD1:
+ case AFE_PORT_I2S_SD2:
+ case AFE_PORT_I2S_SD3:
+ dai_data->port_config.i2s.channel_mode =
+ mi2s_dai_config->pdata_mi2s_lines;
+ break;
+ case AFE_PORT_I2S_QUAD01:
+ case AFE_PORT_I2S_6CHS:
+ case AFE_PORT_I2S_8CHS:
+ dai_data->port_config.i2s.channel_mode =
+ AFE_PORT_I2S_SD0;
+ break;
+ case AFE_PORT_I2S_QUAD23:
+ dai_data->port_config.i2s.channel_mode =
+ AFE_PORT_I2S_SD2;
+ break;
+ }
+ if (dai_data->channels == 2)
+ dai_data->port_config.i2s.mono_stereo =
+ MSM_AFE_CH_STEREO;
+ else
+ dai_data->port_config.i2s.mono_stereo = MSM_AFE_MONO;
+ break;
+ default:
+ pr_err("%s: default err channels %d\n",
+ __func__, dai_data->channels);
+ goto error_invalid_data;
+ }
+ dai_data->rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_SPECIAL:
+ dai_data->port_config.i2s.bit_width = 16;
+ dai_data->bitwidth = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ dai_data->port_config.i2s.bit_width = 24;
+ dai_data->bitwidth = 24;
+ break;
+ default:
+ pr_err("%s: format %d\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ dai_data->port_config.i2s.i2s_cfg_minor_version =
+ AFE_API_VERSION_I2S_CONFIG;
+ dai_data->port_config.i2s.sample_rate = dai_data->rate;
+ if ((test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) &&
+ test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.hwfree_status)) ||
+ (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask) &&
+ test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.hwfree_status))) {
+ if ((mi2s_dai_data->tx_dai.mi2s_dai_data.rate !=
+ mi2s_dai_data->rx_dai.mi2s_dai_data.rate) ||
+ (mi2s_dai_data->rx_dai.mi2s_dai_data.bitwidth !=
+ mi2s_dai_data->tx_dai.mi2s_dai_data.bitwidth)) {
+ dev_err(dai->dev, "%s: Error mismatch in HW params\n"
+ "Tx sample_rate = %u bit_width = %hu\n"
+ "Rx sample_rate = %u bit_width = %hu\n"
+ , __func__,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.rate,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.bitwidth,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.rate,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.bitwidth);
+ return -EINVAL;
+ }
+ }
+ dev_dbg(dai->dev, "%s: dai id %d dai_data->channels = %d\n"
+ "sample_rate = %u i2s_cfg_minor_version = 0x%x\n"
+ "bit_width = %hu channel_mode = 0x%x mono_stereo = %#x\n"
+ "ws_src = 0x%x sample_rate = %u data_format = 0x%x\n"
+ "reserved = %u\n", __func__, dai->id, dai_data->channels,
+ dai_data->rate, i2s->i2s_cfg_minor_version, i2s->bit_width,
+ i2s->channel_mode, i2s->mono_stereo, i2s->ws_src,
+ i2s->sample_rate, i2s->data_format, i2s->reserved);
+
+ return 0;
+
+error_invalid_data:
+ pr_err("%s: dai_data->channels = %d channel_mode = %d\n", __func__,
+ dai_data->channels, dai_data->port_config.i2s.channel_mode);
+ return -EINVAL;
+}
+
+
+static int msm_dai_q6_mi2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+
+ if (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) ||
+ test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
+ dev_err(dai->dev, "%s: err chg i2s mode while dai running",
+ __func__);
+ return -EPERM;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.i2s.ws_src = 1;
+ mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.ws_src = 1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.i2s.ws_src = 0;
+ mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.ws_src = 0;
+ break;
+ default:
+ pr_err("%s: fmt %d\n",
+ __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_mi2s_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai.mi2s_dai_data :
+ &mi2s_dai_data->tx_dai.mi2s_dai_data);
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status)) {
+ clear_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
+ dev_dbg(dai->dev, "%s: clear hwfree_status\n", __func__);
+ }
+ return 0;
+}
+
+static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai.mi2s_dai_data :
+ &mi2s_dai_data->tx_dai.mi2s_dai_data);
+ u16 port_id = 0;
+ int rc = 0;
+
+ if (msm_mi2s_get_port_id(dai->id, substream->stream,
+ &port_id) != 0) {
+ dev_err(dai->dev, "%s: Invalid Port ID 0x%x\n",
+ __func__, port_id);
+ }
+
+ dev_dbg(dai->dev, "%s: closing afe port id = 0x%x\n",
+ __func__, port_id);
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ rc = afe_close(port_id);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AFE port\n");
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+ }
+ if (test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status))
+ clear_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
+ .startup = msm_dai_q6_mi2s_startup,
+ .prepare = msm_dai_q6_mi2s_prepare,
+ .hw_params = msm_dai_q6_mi2s_hw_params,
+ .hw_free = msm_dai_q6_mi2s_hw_free,
+ .set_fmt = msm_dai_q6_mi2s_set_fmt,
+ .shutdown = msm_dai_q6_mi2s_shutdown,
+};
+
+/* Channel min and max are initialized base on platform data */
+static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = {
+ {
+ .playback = {
+ .stream_name = "Primary MI2S Playback",
+ .aif_name = "PRI_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "Primary MI2S Capture",
+ .aif_name = "PRI_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_PRIM_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary MI2S Playback",
+ .aif_name = "SEC_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "Secondary MI2S Capture",
+ .aif_name = "SEC_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_SEC_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary MI2S Playback",
+ .aif_name = "TERT_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "Tertiary MI2S Capture",
+ .aif_name = "TERT_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_TERT_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary MI2S Playback",
+ .aif_name = "QUAT_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "Quaternary MI2S Capture",
+ .aif_name = "QUAT_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_QUAT_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary MI2S Playback SD1",
+ .aif_name = "SEC_MI2S_RX_SD1",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .id = MSM_SEC_MI2S_SD1,
+ },
+ {
+ .playback = {
+ .stream_name = "Quinary MI2S Playback",
+ .aif_name = "QUIN_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "Quinary MI2S Capture",
+ .aif_name = "QUIN_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_QUIN_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Senary_mi2s Capture",
+ .aif_name = "SENARY_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_SENARY_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT0 MI2S Playback",
+ .aif_name = "INT0_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT0 MI2S Capture",
+ .aif_name = "INT0_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT0_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT1 MI2S Playback",
+ .aif_name = "INT1_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT1 MI2S Capture",
+ .aif_name = "INT1_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT1_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT2 MI2S Playback",
+ .aif_name = "INT2_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT2 MI2S Capture",
+ .aif_name = "INT2_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT2_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT3 MI2S Playback",
+ .aif_name = "INT3_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT3 MI2S Capture",
+ .aif_name = "INT3_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT3_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT4 MI2S Playback",
+ .aif_name = "INT4_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT4 MI2S Capture",
+ .aif_name = "INT4_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT4_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT5 MI2S Playback",
+ .aif_name = "INT5_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT5 MI2S Capture",
+ .aif_name = "INT5_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT5_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT6 MI2S Playback",
+ .aif_name = "INT6_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT6 MI2S Capture",
+ .aif_name = "INT6_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT6_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+};
+
+
+static int msm_dai_q6_mi2s_get_lineconfig(u16 sd_lines, u16 *config_ptr,
+ unsigned int *ch_cnt)
+{
+ u8 num_of_sd_lines;
+
+ num_of_sd_lines = num_of_bits_set(sd_lines);
+ switch (num_of_sd_lines) {
+ case 0:
+ pr_debug("%s: no line is assigned\n", __func__);
+ break;
+ case 1:
+ switch (sd_lines) {
+ case MSM_MI2S_SD0:
+ *config_ptr = AFE_PORT_I2S_SD0;
+ break;
+ case MSM_MI2S_SD1:
+ *config_ptr = AFE_PORT_I2S_SD1;
+ break;
+ case MSM_MI2S_SD2:
+ *config_ptr = AFE_PORT_I2S_SD2;
+ break;
+ case MSM_MI2S_SD3:
+ *config_ptr = AFE_PORT_I2S_SD3;
+ break;
+ default:
+ pr_err("%s: invalid SD lines %d\n",
+ __func__, sd_lines);
+ goto error_invalid_data;
+ }
+ break;
+ case 2:
+ switch (sd_lines) {
+ case MSM_MI2S_SD0 | MSM_MI2S_SD1:
+ *config_ptr = AFE_PORT_I2S_QUAD01;
+ break;
+ case MSM_MI2S_SD2 | MSM_MI2S_SD3:
+ *config_ptr = AFE_PORT_I2S_QUAD23;
+ break;
+ default:
+ pr_err("%s: invalid SD lines %d\n",
+ __func__, sd_lines);
+ goto error_invalid_data;
+ }
+ break;
+ case 3:
+ switch (sd_lines) {
+ case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
+ *config_ptr = AFE_PORT_I2S_6CHS;
+ break;
+ default:
+ pr_err("%s: invalid SD lines %d\n",
+ __func__, sd_lines);
+ goto error_invalid_data;
+ }
+ break;
+ case 4:
+ switch (sd_lines) {
+ case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
+ *config_ptr = AFE_PORT_I2S_8CHS;
+ break;
+ default:
+ pr_err("%s: invalid SD lines %d\n",
+ __func__, sd_lines);
+ goto error_invalid_data;
+ }
+ break;
+ default:
+ pr_err("%s: invalid SD lines %d\n", __func__, num_of_sd_lines);
+ goto error_invalid_data;
+ }
+ *ch_cnt = num_of_sd_lines;
+ return 0;
+
+error_invalid_data:
+ pr_err("%s: invalid data\n", __func__);
+ return -EINVAL;
+}
+
+static int msm_dai_q6_mi2s_platform_data_validation(
+ struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
+{
+ struct msm_dai_q6_mi2s_dai_data *dai_data = dev_get_drvdata(&pdev->dev);
+ struct msm_mi2s_pdata *mi2s_pdata =
+ (struct msm_mi2s_pdata *) pdev->dev.platform_data;
+ unsigned int ch_cnt;
+ int rc = 0;
+ u16 sd_line;
+
+ if (mi2s_pdata == NULL) {
+ pr_err("%s: mi2s_pdata NULL", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->rx_sd_lines,
+ &sd_line, &ch_cnt);
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&pdev->dev, "invalid MI2S RX sd line config\n");
+ goto rtn;
+ }
+
+ if (ch_cnt) {
+ dai_data->rx_dai.mi2s_dai_data.port_config.i2s.channel_mode =
+ sd_line;
+ dai_data->rx_dai.pdata_mi2s_lines = sd_line;
+ dai_driver->playback.channels_min = 1;
+ dai_driver->playback.channels_max = ch_cnt << 1;
+ } else {
+ dai_driver->playback.channels_min = 0;
+ dai_driver->playback.channels_max = 0;
+ }
+ rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->tx_sd_lines,
+ &sd_line, &ch_cnt);
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&pdev->dev, "invalid MI2S TX sd line config\n");
+ goto rtn;
+ }
+
+ if (ch_cnt) {
+ dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode =
+ sd_line;
+ dai_data->tx_dai.pdata_mi2s_lines = sd_line;
+ dai_driver->capture.channels_min = 1;
+ dai_driver->capture.channels_max = ch_cnt << 1;
+ } else {
+ dai_driver->capture.channels_min = 0;
+ dai_driver->capture.channels_max = 0;
+ }
+
+ dev_dbg(&pdev->dev, "%s: playback sdline 0x%x capture sdline 0x%x\n",
+ __func__, dai_data->rx_dai.pdata_mi2s_lines,
+ dai_data->tx_dai.pdata_mi2s_lines);
+ dev_dbg(&pdev->dev, "%s: playback ch_max %d capture ch_mx %d\n",
+ __func__, dai_driver->playback.channels_max,
+ dai_driver->capture.channels_max);
+rtn:
+ return rc;
+}
+
+static const struct snd_soc_component_driver msm_q6_mi2s_dai_component = {
+ .name = "msm-dai-q6-mi2s",
+};
+static int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
+{
+ struct msm_dai_q6_mi2s_dai_data *dai_data;
+ const char *q6_mi2s_dev_id = "qcom,msm-dai-q6-mi2s-dev-id";
+ u32 tx_line = 0;
+ u32 rx_line = 0;
+ u32 mi2s_intf = 0;
+ struct msm_mi2s_pdata *mi2s_pdata;
+ int rc;
+
+ rc = of_property_read_u32(pdev->dev.of_node, q6_mi2s_dev_id,
+ &mi2s_intf);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: missing 0x%x in dt node\n", __func__, mi2s_intf);
+ goto rtn;
+ }
+
+ dev_dbg(&pdev->dev, "dev name %s dev id 0x%x\n", dev_name(&pdev->dev),
+ mi2s_intf);
+
+ if ((mi2s_intf < MSM_MI2S_MIN || mi2s_intf > MSM_MI2S_MAX)
+ || (mi2s_intf >= ARRAY_SIZE(msm_dai_q6_mi2s_dai))) {
+ dev_err(&pdev->dev,
+ "%s: Invalid MI2S ID %u from Device Tree\n",
+ __func__, mi2s_intf);
+ rc = -ENXIO;
+ goto rtn;
+ }
+
+ pdev->id = mi2s_intf;
+
+ mi2s_pdata = kzalloc(sizeof(struct msm_mi2s_pdata), GFP_KERNEL);
+ if (!mi2s_pdata) {
+ rc = -ENOMEM;
+ goto rtn;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-rx-lines",
+ &rx_line);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Rx line from DT file %s\n", __func__,
+ "qcom,msm-mi2s-rx-lines");
+ goto free_pdata;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-tx-lines",
+ &tx_line);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Tx line from DT file %s\n", __func__,
+ "qcom,msm-mi2s-tx-lines");
+ goto free_pdata;
+ }
+ dev_dbg(&pdev->dev, "dev name %s Rx line 0x%x , Tx ine 0x%x\n",
+ dev_name(&pdev->dev), rx_line, tx_line);
+ mi2s_pdata->rx_sd_lines = rx_line;
+ mi2s_pdata->tx_sd_lines = tx_line;
+ mi2s_pdata->intf_id = mi2s_intf;
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_mi2s_dai_data),
+ GFP_KERNEL);
+ if (!dai_data) {
+ rc = -ENOMEM;
+ goto free_pdata;
+ } else
+ dev_set_drvdata(&pdev->dev, dai_data);
+
+ pdev->dev.platform_data = mi2s_pdata;
+
+ rc = msm_dai_q6_mi2s_platform_data_validation(pdev,
+ &msm_dai_q6_mi2s_dai[mi2s_intf]);
+ if (IS_ERR_VALUE(rc))
+ goto free_dai_data;
+
+ rc = snd_soc_register_component(&pdev->dev, &msm_q6_mi2s_dai_component,
+ &msm_dai_q6_mi2s_dai[mi2s_intf], 1);
+
+ if (IS_ERR_VALUE(rc))
+ goto err_register;
+ return 0;
+
+err_register:
+ dev_err(&pdev->dev, "fail to msm_dai_q6_mi2s_dev_probe\n");
+free_dai_data:
+ kfree(dai_data);
+free_pdata:
+ kfree(mi2s_pdata);
+rtn:
+ return rc;
+}
+
+static int msm_dai_q6_mi2s_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
+static const struct snd_soc_component_driver msm_dai_q6_component = {
+ .name = "msm-dai-q6-dev",
+};
+
+static int msm_dai_q6_dev_probe(struct platform_device *pdev)
+{
+ int rc, id, i, len;
+ const char *q6_dev_id = "qcom,msm-dai-q6-dev-id";
+ char stream_name[80];
+
+ rc = of_property_read_u32(pdev->dev.of_node, q6_dev_id, &id);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: missing %s in dt node\n", __func__, q6_dev_id);
+ return rc;
+ }
+
+ pdev->id = id;
+
+ pr_debug("%s: dev name %s, id:%d\n", __func__,
+ dev_name(&pdev->dev), pdev->id);
+
+ switch (id) {
+ case SLIMBUS_0_RX:
+ strlcpy(stream_name, "Slimbus Playback", 80);
+ goto register_slim_playback;
+ case SLIMBUS_2_RX:
+ strlcpy(stream_name, "Slimbus2 Playback", 80);
+ goto register_slim_playback;
+ case SLIMBUS_1_RX:
+ strlcpy(stream_name, "Slimbus1 Playback", 80);
+ goto register_slim_playback;
+ case SLIMBUS_3_RX:
+ strlcpy(stream_name, "Slimbus3 Playback", 80);
+ goto register_slim_playback;
+ case SLIMBUS_4_RX:
+ strlcpy(stream_name, "Slimbus4 Playback", 80);
+ goto register_slim_playback;
+ case SLIMBUS_5_RX:
+ strlcpy(stream_name, "Slimbus5 Playback", 80);
+ goto register_slim_playback;
+ case SLIMBUS_6_RX:
+ strlcpy(stream_name, "Slimbus6 Playback", 80);
+ goto register_slim_playback;
+ case SLIMBUS_7_RX:
+ strlcpy(stream_name, "Slimbus7 Playback", sizeof(stream_name));
+ goto register_slim_playback;
+ case SLIMBUS_8_RX:
+ strlcpy(stream_name, "Slimbus8 Playback", sizeof(stream_name));
+ goto register_slim_playback;
+register_slim_playback:
+ rc = -ENODEV;
+ len = strnlen(stream_name, 80);
+ for (i = 0; i < ARRAY_SIZE(msm_dai_q6_slimbus_rx_dai); i++) {
+ if (msm_dai_q6_slimbus_rx_dai[i].playback.stream_name &&
+ !strcmp(stream_name,
+ msm_dai_q6_slimbus_rx_dai[i]
+ .playback.stream_name)) {
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component,
+ &msm_dai_q6_slimbus_rx_dai[i], 1);
+ break;
+ }
+ }
+ if (rc)
+ pr_err("%s: Device not found stream name %s\n",
+ __func__, stream_name);
+ break;
+ case SLIMBUS_0_TX:
+ strlcpy(stream_name, "Slimbus Capture", 80);
+ goto register_slim_capture;
+ case SLIMBUS_1_TX:
+ strlcpy(stream_name, "Slimbus1 Capture", 80);
+ goto register_slim_capture;
+ case SLIMBUS_2_TX:
+ strlcpy(stream_name, "Slimbus2 Capture", 80);
+ goto register_slim_capture;
+ case SLIMBUS_3_TX:
+ strlcpy(stream_name, "Slimbus3 Capture", 80);
+ goto register_slim_capture;
+ case SLIMBUS_4_TX:
+ strlcpy(stream_name, "Slimbus4 Capture", 80);
+ goto register_slim_capture;
+ case SLIMBUS_5_TX:
+ strlcpy(stream_name, "Slimbus5 Capture", 80);
+ goto register_slim_capture;
+ case SLIMBUS_6_TX:
+ strlcpy(stream_name, "Slimbus6 Capture", 80);
+ goto register_slim_capture;
+ case SLIMBUS_7_TX:
+ strlcpy(stream_name, "Slimbus7 Capture", sizeof(stream_name));
+ goto register_slim_capture;
+ case SLIMBUS_8_TX:
+ strlcpy(stream_name, "Slimbus8 Capture", sizeof(stream_name));
+ goto register_slim_capture;
+register_slim_capture:
+ rc = -ENODEV;
+ len = strnlen(stream_name, 80);
+ for (i = 0; i < ARRAY_SIZE(msm_dai_q6_slimbus_tx_dai); i++) {
+ if (msm_dai_q6_slimbus_tx_dai[i].capture.stream_name &&
+ !strcmp(stream_name,
+ msm_dai_q6_slimbus_tx_dai[i]
+ .capture.stream_name)) {
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component,
+ &msm_dai_q6_slimbus_tx_dai[i], 1);
+ break;
+ }
+ }
+ if (rc)
+ pr_err("%s: Device not found stream name %s\n",
+ __func__, stream_name);
+ break;
+ case INT_BT_SCO_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_bt_sco_rx_dai, 1);
+ break;
+ case INT_BT_SCO_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_bt_sco_tx_dai, 1);
+ break;
+ case INT_BT_A2DP_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_bt_a2dp_rx_dai, 1);
+ break;
+ case INT_FM_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_fm_rx_dai, 1);
+ break;
+ case INT_FM_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_fm_tx_dai, 1);
+ break;
+ case AFE_PORT_ID_USB_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_usb_rx_dai, 1);
+ break;
+ case AFE_PORT_ID_USB_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_usb_tx_dai, 1);
+ break;
+ case RT_PROXY_DAI_001_RX:
+ strlcpy(stream_name, "AFE Playback", 80);
+ goto register_afe_playback;
+ case RT_PROXY_DAI_002_RX:
+ strlcpy(stream_name, "AFE-PROXY RX", 80);
+register_afe_playback:
+ rc = -ENODEV;
+ len = strnlen(stream_name, 80);
+ for (i = 0; i < ARRAY_SIZE(msm_dai_q6_afe_rx_dai); i++) {
+ if (msm_dai_q6_afe_rx_dai[i].playback.stream_name &&
+ !strcmp(stream_name,
+ msm_dai_q6_afe_rx_dai[i].playback.stream_name)) {
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component,
+ &msm_dai_q6_afe_rx_dai[i], 1);
+ break;
+ }
+ }
+ if (rc)
+ pr_err("%s: Device not found stream name %s\n",
+ __func__, stream_name);
+ break;
+ case RT_PROXY_DAI_001_TX:
+ strlcpy(stream_name, "AFE-PROXY TX", 80);
+ goto register_afe_capture;
+ case RT_PROXY_DAI_002_TX:
+ strlcpy(stream_name, "AFE Capture", 80);
+register_afe_capture:
+ rc = -ENODEV;
+ len = strnlen(stream_name, 80);
+ for (i = 0; i < ARRAY_SIZE(msm_dai_q6_afe_tx_dai); i++) {
+ if (msm_dai_q6_afe_tx_dai[i].capture.stream_name &&
+ !strcmp(stream_name,
+ msm_dai_q6_afe_tx_dai[i].capture.stream_name)) {
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component,
+ &msm_dai_q6_afe_tx_dai[i], 1);
+ break;
+ }
+ }
+ if (rc)
+ pr_err("%s: Device not found stream name %s\n",
+ __func__, stream_name);
+ break;
+ case VOICE_PLAYBACK_TX:
+ strlcpy(stream_name, "Voice Farend Playback", 80);
+ goto register_voice_playback;
+ case VOICE2_PLAYBACK_TX:
+ strlcpy(stream_name, "Voice2 Farend Playback", 80);
+register_voice_playback:
+ rc = -ENODEV;
+ len = strnlen(stream_name, 80);
+ for (i = 0; i < ARRAY_SIZE(msm_dai_q6_voc_playback_dai); i++) {
+ if (msm_dai_q6_voc_playback_dai[i].playback.stream_name
+ && !strcmp(stream_name,
+ msm_dai_q6_voc_playback_dai[i].playback.stream_name)) {
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component,
+ &msm_dai_q6_voc_playback_dai[i], 1);
+ break;
+ }
+ }
+ if (rc)
+ pr_err("%s Device not found stream name %s\n",
+ __func__, stream_name);
+ break;
+ case VOICE_RECORD_RX:
+ strlcpy(stream_name, "Voice Downlink Capture", 80);
+ goto register_uplink_capture;
+ case VOICE_RECORD_TX:
+ strlcpy(stream_name, "Voice Uplink Capture", 80);
+register_uplink_capture:
+ rc = -ENODEV;
+ len = strnlen(stream_name, 80);
+ for (i = 0; i < ARRAY_SIZE(msm_dai_q6_incall_record_dai); i++) {
+ if (msm_dai_q6_incall_record_dai[i].capture.stream_name
+ && !strcmp(stream_name,
+ msm_dai_q6_incall_record_dai[i].
+ capture.stream_name)) {
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component,
+ &msm_dai_q6_incall_record_dai[i], 1);
+ break;
+ }
+ }
+ if (rc)
+ pr_err("%s: Device not found stream name %s\n",
+ __func__, stream_name);
+ break;
+
+ default:
+ rc = -ENODEV;
+ break;
+ }
+
+ return rc;
+}
+
+static int msm_dai_q6_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_dai_q6_dev_dt_match[] = {
+ { .compatible = "qcom,msm-dai-q6-dev", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, msm_dai_q6_dev_dt_match);
+
+static struct platform_driver msm_dai_q6_dev = {
+ .probe = msm_dai_q6_dev_probe,
+ .remove = msm_dai_q6_dev_remove,
+ .driver = {
+ .name = "msm-dai-q6-dev",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_q6_dev_dt_match,
+ },
+};
+
+static int msm_dai_q6_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ pr_debug("%s: dev name %s, id:%d\n", __func__,
+ dev_name(&pdev->dev), pdev->id);
+ rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
+ __func__, rc);
+ } else
+ dev_dbg(&pdev->dev, "%s: added child node\n", __func__);
+
+ return rc;
+}
+
+static int msm_dai_q6_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id msm_dai_q6_dt_match[] = {
+ { .compatible = "qcom,msm-dai-q6", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, msm_dai_q6_dt_match);
+static struct platform_driver msm_dai_q6 = {
+ .probe = msm_dai_q6_probe,
+ .remove = msm_dai_q6_remove,
+ .driver = {
+ .name = "msm-dai-q6",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_q6_dt_match,
+ },
+};
+
+static int msm_dai_mi2s_q6_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
+ __func__, rc);
+ } else
+ dev_dbg(&pdev->dev, "%s: added child node\n", __func__);
+ return rc;
+}
+
+static int msm_dai_mi2s_q6_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id msm_dai_mi2s_dt_match[] = {
+ { .compatible = "qcom,msm-dai-mi2s", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_mi2s_dt_match);
+
+static struct platform_driver msm_dai_mi2s_q6 = {
+ .probe = msm_dai_mi2s_q6_probe,
+ .remove = msm_dai_mi2s_q6_remove,
+ .driver = {
+ .name = "msm-dai-mi2s",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_mi2s_dt_match,
+ },
+};
+
+static const struct of_device_id msm_dai_q6_mi2s_dev_dt_match[] = {
+ { .compatible = "qcom,msm-dai-q6-mi2s", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_q6_mi2s_dev_dt_match);
+
+static struct platform_driver msm_dai_q6_mi2s_driver = {
+ .probe = msm_dai_q6_mi2s_dev_probe,
+ .remove = msm_dai_q6_mi2s_dev_remove,
+ .driver = {
+ .name = "msm-dai-q6-mi2s",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_q6_mi2s_dev_dt_match,
+ },
+};
+
+static int msm_dai_q6_spdif_dev_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ pdev->id = AFE_PORT_ID_SPDIF_RX;
+
+ pr_debug("%s: dev name %s, id:%d\n", __func__,
+ dev_name(&pdev->dev), pdev->id);
+
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_spdif_q6_component,
+ &msm_dai_q6_spdif_spdif_rx_dai, 1);
+ return rc;
+}
+
+static int msm_dai_q6_spdif_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_dai_q6_spdif_dt_match[] = {
+ {.compatible = "qcom,msm-dai-q6-spdif"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_dai_q6_spdif_dt_match);
+
+static struct platform_driver msm_dai_q6_spdif_driver = {
+ .probe = msm_dai_q6_spdif_dev_probe,
+ .remove = msm_dai_q6_spdif_dev_remove,
+ .driver = {
+ .name = "msm-dai-q6-spdif",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_q6_spdif_dt_match,
+ },
+};
+
+static int msm_dai_tdm_q6_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ u32 num_ports = 0;
+ const uint32_t *port_id_array = NULL;
+ uint32_t array_length = 0;
+ int i = 0;
+ int group_idx = 0;
+
+ /* extract tdm group info into static */
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-group-id",
+ (u32 *)&tdm_group_cfg.group_id);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Group ID from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-group-id");
+ goto rtn;
+ }
+ dev_dbg(&pdev->dev, "%s: Group ID from DT file 0x%x\n",
+ __func__, tdm_group_cfg.group_id);
+
+ dev_info(&pdev->dev, "%s: dev_name: %s group_id: 0x%x\n",
+ __func__, dev_name(&pdev->dev), tdm_group_cfg.group_id);
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-group-num-ports",
+ &num_ports);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Group Num Ports from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-group-num-ports");
+ goto rtn;
+ }
+ dev_dbg(&pdev->dev, "%s: Group Num Ports from DT file 0x%x\n",
+ __func__, num_ports);
+
+ if (num_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
+ dev_err(&pdev->dev, "%s Group Num Ports %d greater than Max %d\n",
+ __func__, num_ports, AFE_GROUP_DEVICE_NUM_PORTS);
+ rc = -EINVAL;
+ goto rtn;
+ }
+
+ port_id_array = of_get_property(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-group-port-id",
+ &array_length);
+ if (port_id_array == NULL) {
+ dev_err(&pdev->dev, "%s port_id_array is not valid\n",
+ __func__);
+ rc = -EINVAL;
+ goto rtn;
+ }
+ if (array_length != sizeof(uint32_t) * num_ports) {
+ dev_err(&pdev->dev, "%s array_length is %d, expected is %zd\n",
+ __func__, array_length, sizeof(uint32_t) * num_ports);
+ rc = -EINVAL;
+ goto rtn;
+ }
+
+ for (i = 0; i < num_ports; i++)
+ tdm_group_cfg.port_id[i] =
+ (u16)be32_to_cpu(port_id_array[i]);
+ /* Unused index should be filled with 0 or AFE_PORT_INVALID */
+ for (i = num_ports; i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
+ tdm_group_cfg.port_id[i] =
+ AFE_PORT_INVALID;
+
+ /* extract tdm clk info into static */
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-clk-rate",
+ &tdm_clk_set.clk_freq_in_hz);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Clk Rate from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-clk-rate");
+ goto rtn;
+ }
+ dev_dbg(&pdev->dev, "%s: Clk Rate from DT file %d\n",
+ __func__, tdm_clk_set.clk_freq_in_hz);
+
+ /* other initializations within device group */
+ group_idx = msm_dai_q6_get_group_idx(tdm_group_cfg.group_id);
+ if (group_idx < 0) {
+ dev_err(&pdev->dev, "%s: group id 0x%x not supported\n",
+ __func__, tdm_group_cfg.group_id);
+ rc = -EINVAL;
+ goto rtn;
+ }
+ atomic_set(&tdm_group_ref[group_idx], 0);
+
+ /* probe child node info */
+ rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
+ __func__, rc);
+ goto rtn;
+ } else
+ dev_dbg(&pdev->dev, "%s: added child node\n", __func__);
+
+rtn:
+ return rc;
+}
+
+static int msm_dai_tdm_q6_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id msm_dai_tdm_dt_match[] = {
+ { .compatible = "qcom,msm-dai-tdm", },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_tdm_dt_match);
+
+static struct platform_driver msm_dai_tdm_q6 = {
+ .probe = msm_dai_tdm_q6_probe,
+ .remove = msm_dai_tdm_q6_remove,
+ .driver = {
+ .name = "msm-dai-tdm",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_tdm_dt_match,
+ },
+};
+
+static int msm_dai_q6_tdm_data_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
+ int value = ucontrol->value.integer.value[0];
+
+ dai_data->port_cfg.tdm.data_format = value;
+ pr_debug("%s: data_format = %d\n",
+ __func__, dai_data->port_cfg.tdm.data_format);
+ return 0;
+}
+
+static int msm_dai_q6_tdm_data_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
+
+ ucontrol->value.integer.value[0] =
+ dai_data->port_cfg.tdm.data_format;
+ pr_debug("%s: data_format = %d\n",
+ __func__, dai_data->port_cfg.tdm.data_format);
+ return 0;
+}
+
+static int msm_dai_q6_tdm_header_type_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
+ int value = ucontrol->value.integer.value[0];
+
+ dai_data->port_cfg.custom_tdm_header.header_type = value;
+ pr_debug("%s: header_type = %d\n",
+ __func__,
+ dai_data->port_cfg.custom_tdm_header.header_type);
+ return 0;
+}
+
+static int msm_dai_q6_tdm_header_type_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
+
+ ucontrol->value.integer.value[0] =
+ dai_data->port_cfg.custom_tdm_header.header_type;
+ pr_debug("%s: header_type = %d\n",
+ __func__,
+ dai_data->port_cfg.custom_tdm_header.header_type);
+ return 0;
+}
+
+static int msm_dai_q6_tdm_header_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
+ int i = 0;
+
+ for (i = 0; i < AFE_CUSTOM_TDM_HEADER_MAX_CNT; i++) {
+ dai_data->port_cfg.custom_tdm_header.header[i] =
+ (u16)ucontrol->value.integer.value[i];
+ pr_debug("%s: header #%d = 0x%x\n",
+ __func__, i,
+ dai_data->port_cfg.custom_tdm_header.header[i]);
+ }
+ return 0;
+}
+
+static int msm_dai_q6_tdm_header_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
+ int i = 0;
+
+ for (i = 0; i < AFE_CUSTOM_TDM_HEADER_MAX_CNT; i++) {
+ ucontrol->value.integer.value[i] =
+ dai_data->port_cfg.custom_tdm_header.header[i];
+ pr_debug("%s: header #%d = 0x%x\n",
+ __func__, i,
+ dai_data->port_cfg.custom_tdm_header.header[i]);
+ }
+ return 0;
+}
+
+static const struct snd_kcontrol_new tdm_config_controls_data_format[] = {
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_1 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_2 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_3 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_4 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_5 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_6 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_7 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_1 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_2 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_3 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_4 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_5 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_6 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_7 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_1 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_2 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_3 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_4 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_5 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_6 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_7 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_1 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_2 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_3 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_4 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_5 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_6 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_7 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_1 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_2 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_3 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_4 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_5 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_6 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_7 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_1 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_2 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_3 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_4 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_5 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_6 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_7 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_1 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_2 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_3 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_4 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_5 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_6 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_7 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_1 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_2 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_3 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_4 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_5 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_6 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_7 Data Format", tdm_config_enum[0],
+ msm_dai_q6_tdm_data_format_get,
+ msm_dai_q6_tdm_data_format_put),
+};
+
+static const struct snd_kcontrol_new tdm_config_controls_header_type[] = {
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_1 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_2 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_3 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_4 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_5 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_6 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_7 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_1 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_2 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_3 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_4 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_5 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_6 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_7 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_1 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_2 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_3 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_4 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_5 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_6 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_7 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_1 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_2 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_3 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_4 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_5 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_6 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_7 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_1 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_2 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_3 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_4 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_5 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_6 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_7 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_1 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_2 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_3 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_4 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_5 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_6 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_7 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_1 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_2 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_3 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_4 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_5 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_6 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_7 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_1 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_2 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_3 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_4 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_5 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_6 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_7 Header Type", tdm_config_enum[1],
+ msm_dai_q6_tdm_header_type_get,
+ msm_dai_q6_tdm_header_type_put),
+};
+
+static const struct snd_kcontrol_new tdm_config_controls_header[] = {
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_0 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_1 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_2 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_3 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_4 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_5 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_6 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_7 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_0 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_1 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_2 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_3 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_4 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_5 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_6 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_7 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_0 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_1 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_2 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_3 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_4 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_5 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_6 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_7 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_0 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_1 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_2 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_3 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_4 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_5 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_6 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_7 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_0 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_1 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_2 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_3 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_4 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_5 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_6 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_7 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_0 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_1 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_2 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_3 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_4 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_5 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_6 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_7 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_0 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_1 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_2 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_3 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_4 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_5 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_6 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_7 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_0 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_1 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_2 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_3 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_4 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_5 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_6 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_7 Header",
+ SND_SOC_NOPM, 0, 0xFFFFFFFF, 0, 8,
+ msm_dai_q6_tdm_header_get,
+ msm_dai_q6_tdm_header_put),
+};
+
+static int msm_dai_q6_tdm_set_clk(
+ struct msm_dai_q6_tdm_dai_data *dai_data,
+ u16 port_id, bool enable)
+{
+ int rc = 0;
+
+ switch (dai_data->group_cfg.tdm_cfg.group_id) {
+ case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX:
+ case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX:
+ if (dai_data->clk_set.clk_freq_in_hz) {
+ dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT;
+ } else
+ dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT;
+ break;
+ case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX:
+ case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX:
+ if (dai_data->clk_set.clk_freq_in_hz) {
+ dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT;
+ } else
+ dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT;
+ break;
+ case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX:
+ case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX:
+ if (dai_data->clk_set.clk_freq_in_hz) {
+ dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT;
+ } else
+ dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT;
+ break;
+ case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX:
+ case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX:
+ if (dai_data->clk_set.clk_freq_in_hz) {
+ dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT;
+ } else
+ dai_data->clk_set.clk_id =
+ Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT;
+ break;
+ default:
+ pr_err("%s: port id 0x%x not supported\n",
+ __func__, port_id);
+ return -EINVAL;
+ }
+ dai_data->clk_set.enable = enable;
+
+ rc = afe_set_lpass_clock_v2(port_id,
+ &dai_data->clk_set);
+ if (rc < 0)
+ pr_err("%s: afe lpass clock failed, err:%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static int msm_dai_q6_dai_tdm_probe(struct snd_soc_dai *dai)
+{
+ int rc = 0;
+ struct msm_dai_q6_tdm_dai_data *tdm_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct snd_kcontrol *data_format_kcontrol = NULL;
+ struct snd_kcontrol *header_type_kcontrol = NULL;
+ struct snd_kcontrol *header_kcontrol = NULL;
+ int port_idx = 0;
+ const struct snd_kcontrol_new *data_format_ctrl = NULL;
+ const struct snd_kcontrol_new *header_type_ctrl = NULL;
+ const struct snd_kcontrol_new *header_ctrl = NULL;
+
+ msm_dai_q6_set_dai_id(dai);
+
+ port_idx = msm_dai_q6_get_port_idx(dai->id);
+ if (port_idx < 0) {
+ dev_err(dai->dev, "%s port id 0x%x not supported\n",
+ __func__, dai->id);
+ rc = -EINVAL;
+ goto rtn;
+ }
+
+ data_format_ctrl =
+ &tdm_config_controls_data_format[port_idx];
+ header_type_ctrl =
+ &tdm_config_controls_header_type[port_idx];
+ header_ctrl =
+ &tdm_config_controls_header[port_idx];
+
+ if (data_format_ctrl) {
+ data_format_kcontrol = snd_ctl_new1(data_format_ctrl,
+ tdm_dai_data);
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ data_format_kcontrol);
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: err add data format ctrl DAI = %s\n",
+ __func__, dai->name);
+ goto rtn;
+ }
+ }
+
+ if (header_type_ctrl) {
+ header_type_kcontrol = snd_ctl_new1(header_type_ctrl,
+ tdm_dai_data);
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ header_type_kcontrol);
+
+ if (IS_ERR_VALUE(rc)) {
+ if (data_format_kcontrol)
+ snd_ctl_remove(dai->component->card->snd_card,
+ data_format_kcontrol);
+ dev_err(dai->dev, "%s: err add header type ctrl DAI = %s\n",
+ __func__, dai->name);
+ goto rtn;
+ }
+ }
+
+ if (header_ctrl) {
+ header_kcontrol = snd_ctl_new1(header_ctrl,
+ tdm_dai_data);
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ header_kcontrol);
+
+ if (IS_ERR_VALUE(rc)) {
+ if (header_type_kcontrol)
+ snd_ctl_remove(dai->component->card->snd_card,
+ header_type_kcontrol);
+ if (data_format_kcontrol)
+ snd_ctl_remove(dai->component->card->snd_card,
+ data_format_kcontrol);
+ dev_err(dai->dev, "%s: err add header ctrl DAI = %s\n",
+ __func__, dai->name);
+ goto rtn;
+ }
+ }
+
+ rc = msm_dai_q6_dai_add_route(dai);
+
+rtn:
+ return rc;
+}
+
+
+static int msm_dai_q6_dai_tdm_remove(struct snd_soc_dai *dai)
+{
+ int rc = 0;
+ struct msm_dai_q6_tdm_dai_data *tdm_dai_data =
+ dev_get_drvdata(dai->dev);
+ u16 group_id = tdm_dai_data->group_cfg.tdm_cfg.group_id;
+ int group_idx = 0;
+ atomic_t *group_ref = NULL;
+
+ group_idx = msm_dai_q6_get_group_idx(dai->id);
+ if (group_idx < 0) {
+ dev_err(dai->dev, "%s port id 0x%x not supported\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ group_ref = &tdm_group_ref[group_idx];
+
+ /* If AFE port is still up, close it */
+ if (test_bit(STATUS_PORT_STARTED, tdm_dai_data->status_mask)) {
+ rc = afe_close(dai->id); /* can block */
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: fail to close AFE port 0x%x\n",
+ __func__, dai->id);
+ }
+ atomic_dec(group_ref);
+ clear_bit(STATUS_PORT_STARTED,
+ tdm_dai_data->status_mask);
+
+ if (atomic_read(group_ref) == 0) {
+ rc = afe_port_group_enable(group_id,
+ NULL, false);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "fail to disable AFE group 0x%x\n",
+ group_id);
+ }
+ rc = msm_dai_q6_tdm_set_clk(tdm_dai_data,
+ dai->id, false);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: fail to disable AFE clk 0x%x\n",
+ __func__, dai->id);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_tdm_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ int rc = 0;
+ struct msm_dai_q6_tdm_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+ struct afe_param_id_group_device_tdm_cfg *tdm_group =
+ &dai_data->group_cfg.tdm_cfg;
+ unsigned int cap_mask;
+
+ dev_dbg(dai->dev, "%s: dai id = 0x%x\n", __func__, dai->id);
+
+ /* HW only supports 16 and 32 bit slot width configuration */
+ if ((slot_width != 16) && (slot_width != 32)) {
+ dev_err(dai->dev, "%s: invalid slot_width %d\n",
+ __func__, slot_width);
+ return -EINVAL;
+ }
+
+ /* HW only supports 16 and 8 slots configuration */
+ switch (slots) {
+ case 8:
+ cap_mask = 0xFF;
+ break;
+ case 16:
+ cap_mask = 0xFFFF;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid slots %d\n",
+ __func__, slots);
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ tdm_group->nslots_per_frame = slots;
+ tdm_group->slot_width = slot_width;
+ tdm_group->slot_mask = rx_mask & cap_mask;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ tdm_group->nslots_per_frame = slots;
+ tdm_group->slot_width = slot_width;
+ tdm_group->slot_mask = tx_mask & cap_mask;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int msm_dai_q6_tdm_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ int rc = 0;
+ struct msm_dai_q6_tdm_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+ struct afe_param_id_slot_mapping_cfg *slot_mapping =
+ &dai_data->port_cfg.slot_mapping;
+ int i = 0;
+
+ dev_dbg(dai->dev, "%s: dai id = 0x%x\n", __func__, dai->id);
+
+ switch (dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ if (!rx_slot) {
+ dev_err(dai->dev, "%s: rx slot not found\n", __func__);
+ return -EINVAL;
+ }
+ if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+ dev_err(dai->dev, "%s: invalid rx num %d\n", __func__,
+ rx_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rx_num; i++)
+ slot_mapping->offset[i] = rx_slot[i];
+ for (i = rx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
+ slot_mapping->offset[i] =
+ AFE_SLOT_MAPPING_OFFSET_INVALID;
+
+ slot_mapping->num_channel = rx_num;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ if (!tx_slot) {
+ dev_err(dai->dev, "%s: tx slot not found\n", __func__);
+ return -EINVAL;
+ }
+ if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+ dev_err(dai->dev, "%s: invalid tx num %d\n", __func__,
+ tx_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < tx_num; i++)
+ slot_mapping->offset[i] = tx_slot[i];
+ for (i = tx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
+ slot_mapping->offset[i] =
+ AFE_SLOT_MAPPING_OFFSET_INVALID;
+
+ slot_mapping->num_channel = tx_num;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+
+ struct afe_param_id_group_device_tdm_cfg *tdm_group =
+ &dai_data->group_cfg.tdm_cfg;
+ struct afe_param_id_tdm_cfg *tdm =
+ &dai_data->port_cfg.tdm;
+ struct afe_param_id_slot_mapping_cfg *slot_mapping =
+ &dai_data->port_cfg.slot_mapping;
+ struct afe_param_id_custom_tdm_header_cfg *custom_tdm_header =
+ &dai_data->port_cfg.custom_tdm_header;
+
+ pr_debug("%s: dev_name: %s\n",
+ __func__, dev_name(dai->dev));
+
+ if ((params_channels(params) == 0) ||
+ (params_channels(params) > 8)) {
+ dev_err(dai->dev, "%s: invalid param channels %d\n",
+ __func__, params_channels(params));
+ return -EINVAL;
+ }
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dai_data->bitwidth = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ dai_data->bitwidth = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dai_data->bitwidth = 32;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid param format 0x%x\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+ dai_data->channels = params_channels(params);
+ dai_data->rate = params_rate(params);
+
+ /*
+ * update tdm group config param
+ * NOTE: group config is set to the same as slot config.
+ */
+ tdm_group->bit_width = tdm_group->slot_width;
+ tdm_group->num_channels = tdm_group->nslots_per_frame;
+ tdm_group->sample_rate = dai_data->rate;
+
+ pr_debug("%s: TDM GROUP:\n"
+ "num_channels=%d sample_rate=%d bit_width=%d\n"
+ "nslots_per_frame=%d slot_width=%d slot_mask=0x%x\n",
+ __func__,
+ tdm_group->num_channels,
+ tdm_group->sample_rate,
+ tdm_group->bit_width,
+ tdm_group->nslots_per_frame,
+ tdm_group->slot_width,
+ tdm_group->slot_mask);
+ pr_debug("%s: TDM GROUP:\n"
+ "port_id[0]=0x%x port_id[1]=0x%x port_id[2]=0x%x port_id[3]=0x%x\n"
+ "port_id[4]=0x%x port_id[5]=0x%x port_id[6]=0x%x port_id[7]=0x%x\n",
+ __func__,
+ tdm_group->port_id[0],
+ tdm_group->port_id[1],
+ tdm_group->port_id[2],
+ tdm_group->port_id[3],
+ tdm_group->port_id[4],
+ tdm_group->port_id[5],
+ tdm_group->port_id[6],
+ tdm_group->port_id[7]);
+
+ /*
+ * update tdm config param
+ * NOTE: channels/rate/bitwidth are per stream property
+ */
+ tdm->num_channels = dai_data->channels;
+ tdm->sample_rate = dai_data->rate;
+ tdm->bit_width = dai_data->bitwidth;
+ /*
+ * port slot config is the same as group slot config
+ * port slot mask should be set according to offset
+ */
+ tdm->nslots_per_frame = tdm_group->nslots_per_frame;
+ tdm->slot_width = tdm_group->slot_width;
+ tdm->slot_mask = tdm_group->slot_mask;
+
+ pr_debug("%s: TDM:\n"
+ "num_channels=%d sample_rate=%d bit_width=%d\n"
+ "nslots_per_frame=%d slot_width=%d slot_mask=0x%x\n"
+ "data_format=0x%x sync_mode=0x%x sync_src=0x%x\n"
+ "data_out=0x%x invert_sync=0x%x data_delay=0x%x\n",
+ __func__,
+ tdm->num_channels,
+ tdm->sample_rate,
+ tdm->bit_width,
+ tdm->nslots_per_frame,
+ tdm->slot_width,
+ tdm->slot_mask,
+ tdm->data_format,
+ tdm->sync_mode,
+ tdm->sync_src,
+ tdm->ctrl_data_out_enable,
+ tdm->ctrl_invert_sync_pulse,
+ tdm->ctrl_sync_data_delay);
+
+ /*
+ * update slot mapping config param
+ * NOTE: channels/rate/bitwidth are per stream property
+ */
+ slot_mapping->bitwidth = dai_data->bitwidth;
+
+ pr_debug("%s: SLOT MAPPING:\n"
+ "num_channel=%d bitwidth=%d data_align=0x%x\n",
+ __func__,
+ slot_mapping->num_channel,
+ slot_mapping->bitwidth,
+ slot_mapping->data_align_type);
+ pr_debug("%s: SLOT MAPPING:\n"
+ "offset[0]=0x%x offset[1]=0x%x offset[2]=0x%x offset[3]=0x%x\n"
+ "offset[4]=0x%x offset[5]=0x%x offset[6]=0x%x offset[7]=0x%x\n",
+ __func__,
+ slot_mapping->offset[0],
+ slot_mapping->offset[1],
+ slot_mapping->offset[2],
+ slot_mapping->offset[3],
+ slot_mapping->offset[4],
+ slot_mapping->offset[5],
+ slot_mapping->offset[6],
+ slot_mapping->offset[7]);
+
+ /*
+ * update custom header config param
+ * NOTE: channels/rate/bitwidth are per playback stream property.
+ * custom tdm header only applicable to playback stream.
+ */
+ if (custom_tdm_header->header_type !=
+ AFE_CUSTOM_TDM_HEADER_TYPE_INVALID) {
+ pr_debug("%s: CUSTOM TDM HEADER:\n"
+ "start_offset=0x%x header_width=%d\n"
+ "num_frame_repeat=%d header_type=0x%x\n",
+ __func__,
+ custom_tdm_header->start_offset,
+ custom_tdm_header->header_width,
+ custom_tdm_header->num_frame_repeat,
+ custom_tdm_header->header_type);
+ pr_debug("%s: CUSTOM TDM HEADER:\n"
+ "header[0]=0x%x header[1]=0x%x header[2]=0x%x header[3]=0x%x\n"
+ "header[4]=0x%x header[5]=0x%x header[6]=0x%x header[7]=0x%x\n",
+ __func__,
+ custom_tdm_header->header[0],
+ custom_tdm_header->header[1],
+ custom_tdm_header->header[2],
+ custom_tdm_header->header[3],
+ custom_tdm_header->header[4],
+ custom_tdm_header->header[5],
+ custom_tdm_header->header[6],
+ custom_tdm_header->header[7]);
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int rc = 0;
+ struct msm_dai_q6_tdm_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+ u16 group_id = dai_data->group_cfg.tdm_cfg.group_id;
+ int group_idx = 0;
+ atomic_t *group_ref = NULL;
+
+ group_idx = msm_dai_q6_get_group_idx(dai->id);
+ if (group_idx < 0) {
+ dev_err(dai->dev, "%s port id 0x%x not supported\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&tdm_mutex);
+
+ group_ref = &tdm_group_ref[group_idx];
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ /* PORT START should be set if prepare called
+ * in active state.
+ */
+ if (atomic_read(group_ref) == 0) {
+ /* TX and RX share the same clk.
+ * AFE clk is enabled per group to simplify the logic.
+ * DSP will monitor the clk count.
+ */
+ rc = msm_dai_q6_tdm_set_clk(dai_data,
+ dai->id, true);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: fail to enable AFE clk 0x%x\n",
+ __func__, dai->id);
+ goto rtn;
+ }
+ rc = afe_port_group_enable(group_id,
+ &dai_data->group_cfg, true);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: fail to enable AFE group 0x%x\n",
+ __func__, group_id);
+ goto rtn;
+ }
+ }
+
+ rc = afe_tdm_port_start(dai->id, &dai_data->port_cfg,
+ dai_data->rate);
+ if (IS_ERR_VALUE(rc)) {
+ if (atomic_read(group_ref) == 0) {
+ afe_port_group_enable(group_id,
+ NULL, false);
+ msm_dai_q6_tdm_set_clk(dai_data,
+ dai->id, false);
+ }
+ dev_err(dai->dev, "%s: fail to open AFE port 0x%x\n",
+ __func__, dai->id);
+ } else {
+ set_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ atomic_inc(group_ref);
+ }
+
+ /* TODO: need to monitor PCM/MI2S/TDM HW status */
+ /* NOTE: AFE should error out if HW resource contention */
+
+ }
+
+rtn:
+ mutex_unlock(&tdm_mutex);
+ return rc;
+}
+
+static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int rc = 0;
+ struct msm_dai_q6_tdm_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+ u16 group_id = dai_data->group_cfg.tdm_cfg.group_id;
+ int group_idx = 0;
+ atomic_t *group_ref = NULL;
+
+ group_idx = msm_dai_q6_get_group_idx(dai->id);
+ if (group_idx < 0) {
+ dev_err(dai->dev, "%s port id 0x%x not supported\n",
+ __func__, dai->id);
+ return;
+ }
+
+ mutex_lock(&tdm_mutex);
+
+ group_ref = &tdm_group_ref[group_idx];
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ rc = afe_close(dai->id);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: fail to close AFE port 0x%x\n",
+ __func__, dai->id);
+ }
+ atomic_dec(group_ref);
+ clear_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+
+ if (atomic_read(group_ref) == 0) {
+ rc = afe_port_group_enable(group_id,
+ NULL, false);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: fail to disable AFE group 0x%x\n",
+ __func__, group_id);
+ }
+ rc = msm_dai_q6_tdm_set_clk(dai_data,
+ dai->id, false);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: fail to disable AFE clk 0x%x\n",
+ __func__, dai->id);
+ }
+ }
+
+ /* TODO: need to monitor PCM/MI2S/TDM HW status */
+ /* NOTE: AFE should error out if HW resource contention */
+
+ }
+
+ mutex_unlock(&tdm_mutex);
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_tdm_ops = {
+ .prepare = msm_dai_q6_tdm_prepare,
+ .hw_params = msm_dai_q6_tdm_hw_params,
+ .set_tdm_slot = msm_dai_q6_tdm_set_tdm_slot,
+ .set_channel_map = msm_dai_q6_tdm_set_channel_map,
+ .shutdown = msm_dai_q6_tdm_shutdown,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
+ {
+ .playback = {
+ .stream_name = "Primary TDM0 Playback",
+ .aif_name = "PRI_TDM_RX_0",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_RX,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM1 Playback",
+ .aif_name = "PRI_TDM_RX_1",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_RX_1,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM2 Playback",
+ .aif_name = "PRI_TDM_RX_2",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_RX_2,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM3 Playback",
+ .aif_name = "PRI_TDM_RX_3",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_RX_3,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM4 Playback",
+ .aif_name = "PRI_TDM_RX_4",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_RX_4,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM5 Playback",
+ .aif_name = "PRI_TDM_RX_5",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_RX_5,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM6 Playback",
+ .aif_name = "PRI_TDM_RX_6",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_RX_6,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Primary TDM7 Playback",
+ .aif_name = "PRI_TDM_RX_7",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_RX_7,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM0 Capture",
+ .aif_name = "PRI_TDM_TX_0",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_TX,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM1 Capture",
+ .aif_name = "PRI_TDM_TX_1",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_TX_1,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM2 Capture",
+ .aif_name = "PRI_TDM_TX_2",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_TX_2,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM3 Capture",
+ .aif_name = "PRI_TDM_TX_3",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_TX_3,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM4 Capture",
+ .aif_name = "PRI_TDM_TX_4",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_TX_4,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM5 Capture",
+ .aif_name = "PRI_TDM_TX_5",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_TX_5,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM6 Capture",
+ .aif_name = "PRI_TDM_TX_6",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_TX_6,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Primary TDM7 Capture",
+ .aif_name = "PRI_TDM_TX_7",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_PRIMARY_TDM_TX_7,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM0 Playback",
+ .aif_name = "SEC_TDM_RX_0",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_RX,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM1 Playback",
+ .aif_name = "SEC_TDM_RX_1",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_RX_1,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM2 Playback",
+ .aif_name = "SEC_TDM_RX_2",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_RX_2,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM3 Playback",
+ .aif_name = "SEC_TDM_RX_3",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_RX_3,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM4 Playback",
+ .aif_name = "SEC_TDM_RX_4",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_RX_4,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM5 Playback",
+ .aif_name = "SEC_TDM_RX_5",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_RX_5,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM6 Playback",
+ .aif_name = "SEC_TDM_RX_6",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_RX_6,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary TDM7 Playback",
+ .aif_name = "SEC_TDM_RX_7",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_RX_7,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM0 Capture",
+ .aif_name = "SEC_TDM_TX_0",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_TX,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM1 Capture",
+ .aif_name = "SEC_TDM_TX_1",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_TX_1,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM2 Capture",
+ .aif_name = "SEC_TDM_TX_2",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_TX_2,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM3 Capture",
+ .aif_name = "SEC_TDM_TX_3",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_TX_3,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM4 Capture",
+ .aif_name = "SEC_TDM_TX_4",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_TX_4,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM5 Capture",
+ .aif_name = "SEC_TDM_TX_5",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_TX_5,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM6 Capture",
+ .aif_name = "SEC_TDM_TX_6",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_TX_6,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Secondary TDM7 Capture",
+ .aif_name = "SEC_TDM_TX_7",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_SECONDARY_TDM_TX_7,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM0 Playback",
+ .aif_name = "TERT_TDM_RX_0",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_RX,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM1 Playback",
+ .aif_name = "TERT_TDM_RX_1",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_RX_1,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM2 Playback",
+ .aif_name = "TERT_TDM_RX_2",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_RX_2,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM3 Playback",
+ .aif_name = "TERT_TDM_RX_3",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_RX_3,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM4 Playback",
+ .aif_name = "TERT_TDM_RX_4",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_RX_4,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM5 Playback",
+ .aif_name = "TERT_TDM_RX_5",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_RX_5,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM6 Playback",
+ .aif_name = "TERT_TDM_RX_6",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_RX_6,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Tertiary TDM7 Playback",
+ .aif_name = "TERT_TDM_RX_7",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_RX_7,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM0 Capture",
+ .aif_name = "TERT_TDM_TX_0",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_TX,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM1 Capture",
+ .aif_name = "TERT_TDM_TX_1",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_TX_1,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM2 Capture",
+ .aif_name = "TERT_TDM_TX_2",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_TX_2,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM3 Capture",
+ .aif_name = "TERT_TDM_TX_3",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_TX_3,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM4 Capture",
+ .aif_name = "TERT_TDM_TX_4",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_TX_4,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM5 Capture",
+ .aif_name = "TERT_TDM_TX_5",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_TX_5,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM6 Capture",
+ .aif_name = "TERT_TDM_TX_6",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_TX_6,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Tertiary TDM7 Capture",
+ .aif_name = "TERT_TDM_TX_7",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_TERTIARY_TDM_TX_7,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM0 Playback",
+ .aif_name = "QUAT_TDM_RX_0",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_RX,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM1 Playback",
+ .aif_name = "QUAT_TDM_RX_1",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_RX_1,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM2 Playback",
+ .aif_name = "QUAT_TDM_RX_2",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_RX_2,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM3 Playback",
+ .aif_name = "QUAT_TDM_RX_3",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_RX_3,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM4 Playback",
+ .aif_name = "QUAT_TDM_RX_4",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_RX_4,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM5 Playback",
+ .aif_name = "QUAT_TDM_RX_5",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_RX_5,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM6 Playback",
+ .aif_name = "QUAT_TDM_RX_6",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_RX_6,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Quaternary TDM7 Playback",
+ .aif_name = "QUAT_TDM_RX_7",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_RX_7,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM0 Capture",
+ .aif_name = "QUAT_TDM_TX_0",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_TX,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM1 Capture",
+ .aif_name = "QUAT_TDM_TX_1",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_TX_1,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM2 Capture",
+ .aif_name = "QUAT_TDM_TX_2",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_TX_2,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM3 Capture",
+ .aif_name = "QUAT_TDM_TX_3",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_TX_3,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM4 Capture",
+ .aif_name = "QUAT_TDM_TX_4",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_TX_4,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM5 Capture",
+ .aif_name = "QUAT_TDM_TX_5",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_TX_5,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM6 Capture",
+ .aif_name = "QUAT_TDM_TX_6",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_TX_6,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Quaternary TDM7 Capture",
+ .aif_name = "QUAT_TDM_TX_7",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_tdm_ops,
+ .id = AFE_PORT_ID_QUATERNARY_TDM_TX_7,
+ .probe = msm_dai_q6_dai_tdm_probe,
+ .remove = msm_dai_q6_dai_tdm_remove,
+ },
+};
+
+static const struct snd_soc_component_driver msm_q6_tdm_dai_component = {
+ .name = "msm-dai-q6-tdm",
+};
+
+static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data = NULL;
+ struct afe_param_id_custom_tdm_header_cfg *custom_tdm_header = NULL;
+ int rc = 0;
+ u32 tdm_dev_id = 0;
+ int port_idx = 0;
+
+ /* retrieve device/afe id */
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-dev-id",
+ &tdm_dev_id);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Device ID missing in DT file\n",
+ __func__);
+ goto rtn;
+ }
+ if ((tdm_dev_id < AFE_PORT_ID_TDM_PORT_RANGE_START) ||
+ (tdm_dev_id > AFE_PORT_ID_TDM_PORT_RANGE_END)) {
+ dev_err(&pdev->dev, "%s: Invalid TDM Device ID 0x%x in DT file\n",
+ __func__, tdm_dev_id);
+ rc = -ENXIO;
+ goto rtn;
+ }
+ pdev->id = tdm_dev_id;
+
+ dev_info(&pdev->dev, "%s: dev_name: %s dev_id: 0x%x\n",
+ __func__, dev_name(&pdev->dev), tdm_dev_id);
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_tdm_dai_data),
+ GFP_KERNEL);
+ if (!dai_data) {
+ rc = -ENOMEM;
+ dev_err(&pdev->dev,
+ "%s Failed to allocate memory for tdm dai_data\n",
+ __func__);
+ goto rtn;
+ }
+ memset(dai_data, 0, sizeof(*dai_data));
+
+ /* TDM CFG */
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-sync-mode",
+ (u32 *)&dai_data->port_cfg.tdm.sync_mode);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Sync Mode from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-sync-mode");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Sync Mode from DT file 0x%x\n",
+ __func__, dai_data->port_cfg.tdm.sync_mode);
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-sync-src",
+ (u32 *)&dai_data->port_cfg.tdm.sync_src);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Sync Src from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-sync-src");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Sync Src from DT file 0x%x\n",
+ __func__, dai_data->port_cfg.tdm.sync_src);
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-data-out",
+ (u32 *)&dai_data->port_cfg.tdm.ctrl_data_out_enable);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Data Out from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-data-out");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Data Out from DT file 0x%x\n",
+ __func__, dai_data->port_cfg.tdm.ctrl_data_out_enable);
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-invert-sync",
+ (u32 *)&dai_data->port_cfg.tdm.ctrl_invert_sync_pulse);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Invert Sync from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-invert-sync");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Invert Sync from DT file 0x%x\n",
+ __func__, dai_data->port_cfg.tdm.ctrl_invert_sync_pulse);
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-data-delay",
+ (u32 *)&dai_data->port_cfg.tdm.ctrl_sync_data_delay);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Data Delay from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-data-delay");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Data Delay from DT file 0x%x\n",
+ __func__, dai_data->port_cfg.tdm.ctrl_sync_data_delay);
+
+ /* TDM CFG -- set default */
+ dai_data->port_cfg.tdm.data_format = AFE_LINEAR_PCM_DATA;
+ dai_data->port_cfg.tdm.tdm_cfg_minor_version =
+ AFE_API_VERSION_TDM_CONFIG;
+
+ /* TDM SLOT MAPPING CFG */
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-data-align",
+ &dai_data->port_cfg.slot_mapping.data_align_type);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Data Align from DT file %s\n",
+ __func__,
+ "qcom,msm-cpudai-tdm-data-align");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Data Align from DT file 0x%x\n",
+ __func__, dai_data->port_cfg.slot_mapping.data_align_type);
+
+ /* TDM SLOT MAPPING CFG -- set default */
+ dai_data->port_cfg.slot_mapping.minor_version =
+ AFE_API_VERSION_SLOT_MAPPING_CONFIG;
+
+ /* CUSTOM TDM HEADER CFG */
+ custom_tdm_header = &dai_data->port_cfg.custom_tdm_header;
+ if (of_find_property(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-header-start-offset", NULL) &&
+ of_find_property(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-header-width", NULL) &&
+ of_find_property(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-header-num-frame-repeat", NULL)) {
+ /* if the property exist */
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-header-start-offset",
+ (u32 *)&custom_tdm_header->start_offset);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Header Start Offset from DT file %s\n",
+ __func__,
+ "qcom,msm-cpudai-tdm-header-start-offset");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Header Start Offset from DT file 0x%x\n",
+ __func__, custom_tdm_header->start_offset);
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-header-width",
+ (u32 *)&custom_tdm_header->header_width);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Header Width from DT file %s\n",
+ __func__, "qcom,msm-cpudai-tdm-header-width");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Header Width from DT file 0x%x\n",
+ __func__, custom_tdm_header->header_width);
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-cpudai-tdm-header-num-frame-repeat",
+ (u32 *)&custom_tdm_header->num_frame_repeat);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Header Num Frame Repeat from DT file %s\n",
+ __func__,
+ "qcom,msm-cpudai-tdm-header-num-frame-repeat");
+ goto free_dai_data;
+ }
+ dev_dbg(&pdev->dev, "%s: Header Num Frame Repeat from DT file 0x%x\n",
+ __func__, custom_tdm_header->num_frame_repeat);
+
+ /* CUSTOM TDM HEADER CFG -- set default */
+ custom_tdm_header->minor_version =
+ AFE_API_VERSION_CUSTOM_TDM_HEADER_CONFIG;
+ custom_tdm_header->header_type =
+ AFE_CUSTOM_TDM_HEADER_TYPE_INVALID;
+ } else {
+ dev_info(&pdev->dev,
+ "%s: Custom tdm header not supported\n", __func__);
+ /* CUSTOM TDM HEADER CFG -- set default */
+ custom_tdm_header->header_type =
+ AFE_CUSTOM_TDM_HEADER_TYPE_INVALID;
+ /* proceed with probe */
+ }
+
+ /* copy static clk per parent node */
+ dai_data->clk_set = tdm_clk_set;
+ /* copy static group cfg per parent node */
+ dai_data->group_cfg.tdm_cfg = tdm_group_cfg;
+
+ dev_set_drvdata(&pdev->dev, dai_data);
+
+ port_idx = msm_dai_q6_get_port_idx(tdm_dev_id);
+ if (port_idx < 0) {
+ dev_err(&pdev->dev, "%s Port id 0x%x not supported\n",
+ __func__, tdm_dev_id);
+ rc = -EINVAL;
+ goto free_dai_data;
+ }
+
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_q6_tdm_dai_component,
+ &msm_dai_q6_tdm_dai[port_idx], 1);
+
+ if (rc) {
+ dev_err(&pdev->dev, "%s: TDM dai 0x%x register failed, rc=%d\n",
+ __func__, tdm_dev_id, rc);
+ goto err_register;
+ }
+
+ return 0;
+
+err_register:
+free_dai_data:
+ kfree(dai_data);
+rtn:
+ return rc;
+}
+
+static int msm_dai_q6_tdm_dev_remove(struct platform_device *pdev)
+{
+ struct msm_dai_q6_tdm_dai_data *dai_data =
+ dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_component(&pdev->dev);
+
+ kfree(dai_data);
+
+ return 0;
+}
+
+static const struct of_device_id msm_dai_q6_tdm_dev_dt_match[] = {
+ { .compatible = "qcom,msm-dai-q6-tdm", },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_q6_tdm_dev_dt_match);
+
+static struct platform_driver msm_dai_q6_tdm_driver = {
+ .probe = msm_dai_q6_tdm_dev_probe,
+ .remove = msm_dai_q6_tdm_dev_remove,
+ .driver = {
+ .name = "msm-dai-q6-tdm",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_q6_tdm_dev_dt_match,
+ },
+};
+
+static int __init msm_dai_q6_init(void)
+{
+ int rc;
+
+ rc = platform_driver_register(&msm_auxpcm_dev_driver);
+ if (rc) {
+ pr_err("%s: fail to register auxpcm dev driver", __func__);
+ goto fail;
+ }
+
+ rc = platform_driver_register(&msm_dai_q6);
+ if (rc) {
+ pr_err("%s: fail to register dai q6 driver", __func__);
+ goto dai_q6_fail;
+ }
+
+ rc = platform_driver_register(&msm_dai_q6_dev);
+ if (rc) {
+ pr_err("%s: fail to register dai q6 dev driver", __func__);
+ goto dai_q6_dev_fail;
+ }
+
+ rc = platform_driver_register(&msm_dai_q6_mi2s_driver);
+ if (rc) {
+ pr_err("%s: fail to register dai MI2S dev drv\n", __func__);
+ goto dai_q6_mi2s_drv_fail;
+ }
+
+ rc = platform_driver_register(&msm_dai_mi2s_q6);
+ if (rc) {
+ pr_err("%s: fail to register dai MI2S\n", __func__);
+ goto dai_mi2s_q6_fail;
+ }
+
+ rc = platform_driver_register(&msm_dai_q6_spdif_driver);
+ if (rc) {
+ pr_err("%s: fail to register dai SPDIF\n", __func__);
+ goto dai_spdif_q6_fail;
+ }
+
+ rc = platform_driver_register(&msm_dai_q6_tdm_driver);
+ if (rc) {
+ pr_err("%s: fail to register dai TDM dev drv\n", __func__);
+ goto dai_q6_tdm_drv_fail;
+ }
+
+ rc = platform_driver_register(&msm_dai_tdm_q6);
+ if (rc) {
+ pr_err("%s: fail to register dai TDM\n", __func__);
+ goto dai_tdm_q6_fail;
+ }
+ return rc;
+
+dai_tdm_q6_fail:
+ platform_driver_unregister(&msm_dai_q6_tdm_driver);
+dai_q6_tdm_drv_fail:
+ platform_driver_unregister(&msm_dai_q6_spdif_driver);
+dai_spdif_q6_fail:
+ platform_driver_unregister(&msm_dai_mi2s_q6);
+dai_mi2s_q6_fail:
+ platform_driver_unregister(&msm_dai_q6_mi2s_driver);
+dai_q6_mi2s_drv_fail:
+ platform_driver_unregister(&msm_dai_q6_dev);
+dai_q6_dev_fail:
+ platform_driver_unregister(&msm_dai_q6);
+dai_q6_fail:
+ platform_driver_unregister(&msm_auxpcm_dev_driver);
+fail:
+ return rc;
+}
+module_init(msm_dai_q6_init);
+
+static void __exit msm_dai_q6_exit(void)
+{
+ platform_driver_unregister(&msm_dai_q6_dev);
+ platform_driver_unregister(&msm_dai_q6);
+ platform_driver_unregister(&msm_auxpcm_dev_driver);
+ platform_driver_unregister(&msm_dai_q6_spdif_driver);
+}
+module_exit(msm_dai_q6_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM DSP DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-slim.c b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
new file mode 100644
index 0000000..e012cf2
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
@@ -0,0 +1,659 @@
+/*
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/bitops.h>
+#include <linux/slimbus/slimbus.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/msm-slim-dma.h>
+
+#define SLIM_DEV_NAME "msm-dai-slim"
+
+#define SLIM_DAI_RATES (SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_8000 | \
+ SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_192000 | \
+ SNDRV_PCM_RATE_384000)
+
+#define SLIM_DAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define DAI_STATE_INITIALIZED (0x01 << 0)
+#define DAI_STATE_PREPARED (0x01 << 1)
+#define DAI_STATE_RUNNING (0x01 << 2)
+
+#define SET_DAI_STATE(status, state) \
+ (status |= state)
+
+#define CLR_DAI_STATE(status, state) \
+ (status = status & (~state))
+
+enum {
+ MSM_DAI_SLIM0 = 0,
+ NUM_SLIM_DAIS,
+};
+
+struct msm_slim_dai_data {
+ unsigned int dai_id;
+ u16 *chan_h;
+ u16 *sh_ch;
+ u16 grph;
+ u32 rate;
+ u16 bits;
+ u16 ch_cnt;
+ u8 status;
+ struct snd_soc_dai_driver *dai_drv;
+ struct msm_slim_dma_data dma_data;
+ struct slim_port_cfg port_cfg;
+};
+
+struct msm_dai_slim_drv_data {
+ struct slim_device *sdev;
+ u16 num_dais;
+ struct msm_slim_dai_data slim_dai_data[NUM_SLIM_DAIS];
+};
+
+struct msm_slim_dai_data *msm_slim_get_dai_data(
+ struct msm_dai_slim_drv_data *drv_data,
+ struct snd_soc_dai *dai)
+{
+ struct msm_slim_dai_data *dai_data_t;
+ int i;
+
+ for (i = 0; i < drv_data->num_dais; i++) {
+ dai_data_t = &drv_data->slim_dai_data[i];
+ if (dai_data_t->dai_id == dai->id)
+ return dai_data_t;
+ }
+
+ dev_err(dai->dev,
+ "%s: no dai data found for dai_id %d\n",
+ __func__, dai->id);
+ return NULL;
+}
+
+static int msm_dai_slim_ch_ctl(struct msm_slim_dma_data *dma_data,
+ struct snd_soc_dai *dai, bool enable)
+{
+ struct slim_device *sdev;
+ struct msm_dai_slim_drv_data *drv_data;
+ struct msm_slim_dai_data *dai_data;
+ int rc, rc1, i;
+
+ if (!dma_data || !dma_data->sdev) {
+ pr_err("%s: Invalid %s\n", __func__,
+ (!dma_data) ? "dma_data" : "slim_device");
+ return -EINVAL;
+ }
+
+ sdev = dma_data->sdev;
+ drv_data = dev_get_drvdata(&sdev->dev);
+ dai_data = msm_slim_get_dai_data(drv_data, dai);
+
+ if (!dai_data) {
+ dev_err(dai->dev,
+ "%s: Invalid dai_data for dai_id %d\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ dev_dbg(&sdev->dev,
+ "%s: enable = %s, rate = %u\n", __func__,
+ enable ? "true" : "false",
+ dai_data->rate);
+
+ if (enable) {
+ if (!(dai_data->status & DAI_STATE_PREPARED)) {
+ dev_err(&sdev->dev,
+ "%s: dai id (%d) has invalid state 0x%x\n",
+ __func__, dai->id, dai_data->status);
+ return -EINVAL;
+ }
+
+ rc = slim_alloc_mgrports(sdev,
+ SLIM_REQ_DEFAULT, dai_data->ch_cnt,
+ &(dma_data->ph),
+ sizeof(dma_data->ph));
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&sdev->dev,
+ "%s:alloc mgrport failed rc %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ rc = slim_config_mgrports(sdev, &(dma_data->ph),
+ dai_data->ch_cnt,
+ &(dai_data->port_cfg));
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&sdev->dev,
+ "%s: config mgrport failed rc %d\n",
+ __func__, rc);
+ goto err_done;
+ }
+
+ for (i = 0; i < dai_data->ch_cnt; i++) {
+ rc = slim_connect_sink(sdev,
+ &dma_data->ph, 1,
+ dai_data->chan_h[i]);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&sdev->dev,
+ "%s: slim_connect_sink failed, ch = %d, err = %d\n",
+ __func__, i, rc);
+ goto err_done;
+ }
+ }
+
+ rc = slim_control_ch(sdev,
+ dai_data->grph,
+ SLIM_CH_ACTIVATE, true);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&sdev->dev,
+ "%s: slim activate ch failed, err = %d\n",
+ __func__, rc);
+ goto err_done;
+ }
+ /* Mark dai status as running */
+ SET_DAI_STATE(dai_data->status, DAI_STATE_RUNNING);
+ } else {
+ if (!(dai_data->status & DAI_STATE_RUNNING)) {
+ dev_err(&sdev->dev,
+ "%s: dai id (%d) has invalid state 0x%x\n",
+ __func__, dai->id, dai_data->status);
+ return -EINVAL;
+ }
+
+ rc = slim_control_ch(sdev,
+ dai_data->grph,
+ SLIM_CH_REMOVE, true);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&sdev->dev,
+ "%s: slim activate ch failed, err = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ rc = slim_dealloc_mgrports(sdev,
+ &dma_data->ph, 1);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&sdev->dev,
+ "%s: dealloc mgrport failed, err = %d\n",
+ __func__, rc);
+ goto done;
+ }
+ /* clear running state for dai*/
+ CLR_DAI_STATE(dai_data->status, DAI_STATE_RUNNING);
+ }
+
+ return rc;
+
+err_done:
+ rc1 = slim_dealloc_mgrports(sdev,
+ &dma_data->ph, 1);
+ if (IS_ERR_VALUE(rc1))
+ dev_err(&sdev->dev,
+ "%s: dealloc mgrport failed, err = %d\n",
+ __func__, rc1);
+done:
+ return rc;
+}
+
+static int msm_dai_slim_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
+ struct msm_slim_dai_data *dai_data;
+ int rc = 0;
+
+ dai_data = msm_slim_get_dai_data(drv_data, dai);
+ if (!dai_data) {
+ dev_err(dai->dev,
+ "%s: Invalid dai_data for dai_id %d\n",
+ __func__, dai->id);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (!dai_data->ch_cnt || dai_data->ch_cnt != params_channels(params)) {
+ dev_err(dai->dev, "%s: invalid ch_cnt %d %d\n",
+ __func__, dai_data->ch_cnt, params_channels(params));
+ rc = -EINVAL;
+ goto done;
+ }
+
+ dai_data->rate = params_rate(params);
+ dai_data->port_cfg.port_opts = SLIM_OPT_NONE;
+ if (dai_data->rate >= SNDRV_PCM_RATE_48000)
+ dai_data->port_cfg.watermark = 16;
+ else
+ dai_data->port_cfg.watermark = 8;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dai_data->bits = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dai_data->bits = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dai_data->bits = 32;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid format %d\n", __func__,
+ params_format(params));
+ rc = -EINVAL;
+ goto done;
+ }
+
+ dev_dbg(dai->dev, "%s: ch_cnt=%u rate=%u, bit_width = %u\n",
+ __func__, dai_data->ch_cnt, dai_data->rate,
+ dai_data->bits);
+done:
+ return rc;
+}
+
+static int msm_dai_slim_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
+ struct msm_slim_dai_data *dai_data;
+ struct snd_soc_dai_driver *dai_drv;
+ u8 i = 0;
+
+ dev_dbg(dai->dev,
+ "%s: tx_num=%u, rx_num=%u\n",
+ __func__, tx_num, rx_num);
+
+ dai_data = msm_slim_get_dai_data(drv_data, dai);
+ if (!dai_data) {
+ dev_err(dai->dev,
+ "%s: Invalid dai_data for dai_id %d\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ dai_drv = dai_data->dai_drv;
+
+ if (tx_num > dai_drv->capture.channels_max) {
+ dev_err(dai->dev, "%s: tx_num %u max out master port cnt\n",
+ __func__, tx_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < tx_num; i++)
+ dai_data->sh_ch[i] = tx_slot[i];
+
+ dai_data->ch_cnt = tx_num;
+ return 0;
+}
+
+static int msm_dai_slim_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
+ struct msm_slim_dma_data *dma_data;
+ struct msm_slim_dai_data *dai_data = NULL;
+ struct slim_ch prop;
+ int rc;
+ u8 i, j;
+
+ dai_data = msm_slim_get_dai_data(drv_data, dai);
+ if (!dai_data) {
+ dev_err(dai->dev,
+ "%s: Invalid dai_data for dai %d\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ if (!(dai_data->status & DAI_STATE_INITIALIZED)) {
+ dev_err(dai->dev,
+ "%s: dai id (%d) has invalid state 0x%x\n",
+ __func__, dai->id, dai_data->status);
+ return -EINVAL;
+ }
+
+ dma_data = &dai_data->dma_data;
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+ for (i = 0; i < dai_data->ch_cnt; i++) {
+ rc = slim_query_ch(drv_data->sdev, dai_data->sh_ch[i],
+ &dai_data->chan_h[i]);
+ if (rc) {
+ dev_err(dai->dev, "%s:query chan handle failed rc %d\n",
+ __func__, rc);
+ goto error_chan_query;
+ }
+ }
+
+ prop.prot = SLIM_AUTO_ISO;
+ prop.baser = SLIM_RATE_4000HZ;
+ prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
+ prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
+ prop.ratem = (dai_data->rate/4000);
+ prop.sampleszbits = dai_data->bits;
+
+ rc = slim_define_ch(drv_data->sdev, &prop, dai_data->chan_h,
+ dai_data->ch_cnt, true, &dai_data->grph);
+
+ if (rc) {
+ dev_err(dai->dev, "%s:define chan failed rc %d\n",
+ __func__, rc);
+ goto error_define_chan;
+ }
+
+ /* Mark stream status as prepared */
+ SET_DAI_STATE(dai_data->status, DAI_STATE_PREPARED);
+
+ return rc;
+
+error_define_chan:
+error_chan_query:
+ for (j = 0; j < i; j++)
+ slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[j]);
+ return rc;
+}
+
+static void msm_dai_slim_shutdown(struct snd_pcm_substream *stream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
+ struct msm_slim_dma_data *dma_data = NULL;
+ struct msm_slim_dai_data *dai_data;
+ int i, rc = 0;
+
+ dai_data = msm_slim_get_dai_data(drv_data, dai);
+ dma_data = snd_soc_dai_get_dma_data(dai, stream);
+ if (!dma_data || !dai_data) {
+ dev_err(dai->dev,
+ "%s: Invalid %s\n", __func__,
+ (!dma_data) ? "dma_data" : "dai_data");
+ return;
+ }
+
+ if ((!(dai_data->status & DAI_STATE_PREPARED)) ||
+ dai_data->status & DAI_STATE_RUNNING) {
+ dev_err(dai->dev,
+ "%s: dai id (%d) has invalid state 0x%x\n",
+ __func__, dai->id, dai_data->status);
+ return;
+ }
+
+ for (i = 0; i < dai_data->ch_cnt; i++) {
+ rc = slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
+ if (rc) {
+ dev_err(dai->dev,
+ "%s: dealloc_ch failed, err = %d\n",
+ __func__, rc);
+ }
+ }
+
+ snd_soc_dai_set_dma_data(dai, stream, NULL);
+ /* clear prepared state for the dai */
+ CLR_DAI_STATE(dai_data->status, DAI_STATE_PREPARED);
+}
+
+static const struct snd_soc_component_driver msm_dai_slim_component = {
+ .name = "msm-dai-slim-cmpnt",
+};
+
+static struct snd_soc_dai_ops msm_dai_slim_ops = {
+ .prepare = msm_dai_slim_prepare,
+ .hw_params = msm_dai_slim_hw_params,
+ .shutdown = msm_dai_slim_shutdown,
+ .set_channel_map = msm_dai_slim_set_channel_map,
+};
+
+static struct snd_soc_dai_driver msm_slim_dais[] = {
+ {
+ /*
+ * The first dai name should be same as device name
+ * to support registering single and multile dais.
+ */
+ .name = SLIM_DEV_NAME,
+ .id = MSM_DAI_SLIM0,
+ .capture = {
+ .rates = SLIM_DAI_RATES,
+ .formats = SLIM_DAI_FORMATS,
+ .channels_min = 1,
+ /*
+ * max channels allowed is
+ * dependent on platform and
+ * will be updated before this
+ * dai driver is registered.
+ */
+ .channels_max = 1,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .stream_name = "SLIM_DAI0 Capture",
+ },
+ .ops = &msm_dai_slim_ops,
+ },
+ /*
+ * If multiple dais are needed,
+ * add dais here and update the
+ * dai_id enum.
+ */
+};
+
+static void msm_dai_slim_remove_dai_data(
+ struct device *dev,
+ struct msm_dai_slim_drv_data *drv_data)
+{
+ int i;
+ struct msm_slim_dai_data *dai_data_t;
+
+ for (i = 0; i < drv_data->num_dais; i++) {
+ dai_data_t = &drv_data->slim_dai_data[i];
+
+ kfree(dai_data_t->chan_h);
+ dai_data_t->chan_h = NULL;
+ kfree(dai_data_t->sh_ch);
+ dai_data_t->sh_ch = NULL;
+ }
+}
+
+static int msm_dai_slim_populate_dai_data(struct device *dev,
+ struct msm_dai_slim_drv_data *drv_data)
+{
+ struct snd_soc_dai_driver *dai_drv;
+ struct msm_slim_dai_data *dai_data_t;
+ u8 num_ch;
+ int i, j, rc;
+
+ for (i = 0; i < drv_data->num_dais; i++) {
+ num_ch = 0;
+ dai_drv = &msm_slim_dais[i];
+ num_ch += dai_drv->capture.channels_max;
+ num_ch += dai_drv->playback.channels_max;
+
+ dai_data_t = &drv_data->slim_dai_data[i];
+ dai_data_t->dai_drv = dai_drv;
+ dai_data_t->dai_id = dai_drv->id;
+ dai_data_t->dma_data.sdev = drv_data->sdev;
+ dai_data_t->dma_data.dai_channel_ctl =
+ msm_dai_slim_ch_ctl;
+ SET_DAI_STATE(dai_data_t->status,
+ DAI_STATE_INITIALIZED);
+
+ dai_data_t->chan_h = devm_kzalloc(dev,
+ sizeof(u16) * num_ch,
+ GFP_KERNEL);
+ if (!dai_data_t->chan_h) {
+ dev_err(dev,
+ "%s: DAI ID %d, Failed to alloc channel handles\n",
+ __func__, i);
+ rc = -ENOMEM;
+ goto err_mem_alloc;
+ }
+
+ dai_data_t->sh_ch = devm_kzalloc(dev,
+ sizeof(u16) * num_ch,
+ GFP_KERNEL);
+ if (!dai_data_t->sh_ch) {
+ dev_err(dev,
+ "%s: DAI ID %d, Failed to alloc sh_ch\n",
+ __func__, i);
+ rc = -ENOMEM;
+ goto err_mem_alloc;
+ }
+ }
+ return 0;
+
+err_mem_alloc:
+ for (j = 0; j < i; j++) {
+ dai_data_t = &drv_data->slim_dai_data[i];
+
+ devm_kfree(dev, dai_data_t->chan_h);
+ dai_data_t->chan_h = NULL;
+
+ devm_kfree(dev, dai_data_t->sh_ch);
+ dai_data_t->sh_ch = NULL;
+ }
+ return rc;
+}
+
+static int msm_dai_slim_dev_probe(struct slim_device *sdev)
+{
+ int rc, i;
+ u8 max_channels;
+ u32 apps_ch_pipes;
+ struct msm_dai_slim_drv_data *drv_data;
+ struct device *dev = &sdev->dev;
+ struct snd_soc_dai_driver *dai_drv;
+
+ if (!dev->of_node ||
+ !dev->of_node->parent) {
+ dev_err(dev,
+ "%s: Invalid %s\n", __func__,
+ (!dev->of_node) ? "of_node" : "parent_of_node");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(dev->of_node->parent,
+ "qcom,apps-ch-pipes",
+ &apps_ch_pipes);
+ if (rc) {
+ dev_err(dev,
+ "%s: Failed to lookup property %s in node %s, err = %d\n",
+ __func__, "qcom,apps-ch-pipes",
+ dev->of_node->parent->full_name, rc);
+ goto err_ret;
+ }
+
+ max_channels = hweight_long(apps_ch_pipes);
+ if (max_channels <= 0) {
+ dev_err(dev,
+ "%s: Invalid apps owned ports %d\n",
+ __func__, max_channels);
+ goto err_ret;
+ }
+
+ dev_dbg(dev, "%s: max channels = %u\n",
+ __func__, max_channels);
+
+ for (i = 0; i < ARRAY_SIZE(msm_slim_dais); i++) {
+ dai_drv = &msm_slim_dais[i];
+ dai_drv->capture.channels_max = max_channels;
+ dai_drv->playback.channels_max = max_channels;
+ }
+
+ drv_data = devm_kzalloc(dev, sizeof(*drv_data),
+ GFP_KERNEL);
+ if (!drv_data) {
+ rc = -ENOMEM;
+ goto err_ret;
+ }
+
+ drv_data->sdev = sdev;
+ drv_data->num_dais = NUM_SLIM_DAIS;
+
+ rc = msm_dai_slim_populate_dai_data(dev, drv_data);
+ if (rc) {
+ dev_err(dev,
+ "%s: failed to setup dai_data, err = %d\n",
+ __func__, rc);
+ goto err_populate_dai;
+ }
+
+ rc = snd_soc_register_component(&sdev->dev, &msm_dai_slim_component,
+ msm_slim_dais, NUM_SLIM_DAIS);
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dev, "%s: failed to register DAI, err = %d\n",
+ __func__, rc);
+ goto err_reg_comp;
+ }
+
+ dev_set_drvdata(dev, drv_data);
+ return rc;
+
+err_reg_comp:
+ msm_dai_slim_remove_dai_data(dev, drv_data);
+
+err_populate_dai:
+ devm_kfree(dev, drv_data);
+
+err_ret:
+ return rc;
+}
+
+static int msm_dai_slim_dev_remove(struct slim_device *sdev)
+{
+ snd_soc_unregister_component(&sdev->dev);
+ return 0;
+}
+
+static const struct slim_device_id msm_dai_slim_dt_match[] = {
+ {SLIM_DEV_NAME, 0 },
+ {}
+};
+
+static struct slim_driver msm_dai_slim_driver = {
+ .driver = {
+ .name = SLIM_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = msm_dai_slim_dev_probe,
+ .remove = msm_dai_slim_dev_remove,
+ .id_table = msm_dai_slim_dt_match,
+};
+
+static int __init msm_dai_slim_init(void)
+{
+ int rc;
+
+ rc = slim_driver_register(&msm_dai_slim_driver);
+ if (rc)
+ pr_err("%s: failed to register with slimbus driver rc = %d",
+ __func__, rc);
+ return rc;
+}
+module_init(msm_dai_slim_init);
+
+static void __exit msm_dai_slim_exit(void)
+{
+}
+module_exit(msm_dai_slim_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("Slimbus apps-owned channel handling driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-stub-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-stub-v2.c
new file mode 100644
index 0000000..3a2c3d3
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dai-stub-v2.c
@@ -0,0 +1,394 @@
+/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+enum {
+ STUB_RX,
+ STUB_TX,
+ STUB_1_RX,
+ STUB_1_TX,
+ STUB_DTMF_TX,
+ STUB_HOST_RX_CAPTURE_TX,
+ STUB_HOST_RX_PLAYBACK_RX,
+ STUB_HOST_TX_CAPTURE_TX,
+ STUB_HOST_TX_PLAYBACK_RX,
+};
+
+static int msm_dai_stub_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ pr_debug("%s:\n", __func__);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops msm_dai_stub_ops = {
+ .set_channel_map = msm_dai_stub_set_channel_map,
+};
+
+static int msm_dai_stub_add_route(struct snd_soc_dai *dai)
+{
+ struct snd_soc_dapm_route intercon;
+ struct snd_soc_dapm_context *dapm;
+
+ if (!dai || !dai->driver) {
+ pr_err("%s Invalid params\n", __func__);
+ return -EINVAL;
+ }
+ dapm = snd_soc_component_get_dapm(dai->component);
+ memset(&intercon, 0, sizeof(intercon));
+ if (dai->driver->playback.stream_name &&
+ dai->driver->playback.aif_name) {
+ dev_dbg(dai->dev, "%s add route for widget %s",
+ __func__, dai->driver->playback.stream_name);
+ intercon.source = dai->driver->playback.aif_name;
+ intercon.sink = dai->driver->playback.stream_name;
+ dev_dbg(dai->dev, "%s src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ }
+ if (dai->driver->capture.stream_name &&
+ dai->driver->capture.aif_name) {
+ dev_dbg(dai->dev, "%s add route for widget %s",
+ __func__, dai->driver->capture.stream_name);
+ intercon.sink = dai->driver->capture.aif_name;
+ intercon.source = dai->driver->capture.stream_name;
+ dev_dbg(dai->dev, "%s src %s sink %s\n",
+ __func__, intercon.source, intercon.sink);
+ snd_soc_dapm_add_routes(dapm, &intercon, 1);
+ }
+ return 0;
+}
+
+static int msm_dai_stub_dai_probe(struct snd_soc_dai *dai)
+{
+ return msm_dai_stub_add_route(dai);
+}
+
+static int msm_dai_stub_dai_remove(struct snd_soc_dai *dai)
+{
+ pr_debug("%s:\n", __func__);
+ return 0;
+}
+
+static struct snd_soc_dai_driver msm_dai_stub_dai_rx = {
+ .playback = {
+ .stream_name = "Stub Playback",
+ .aif_name = "STUB_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+ .probe = &msm_dai_stub_dai_probe,
+ .remove = &msm_dai_stub_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_stub_dai_tx[] = {
+ {
+ .capture = {
+ .stream_name = "Stub Capture",
+ .aif_name = "STUB_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+ .probe = &msm_dai_stub_dai_probe,
+ .remove = &msm_dai_stub_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "Stub1 Capture",
+ .aif_name = "STUB_1_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+ .probe = &msm_dai_stub_dai_probe,
+ .remove = &msm_dai_stub_dai_remove,
+ }
+};
+
+static struct snd_soc_dai_driver msm_dai_stub_dtmf_tx_dai = {
+ .capture = {
+ .stream_name = "DTMF TX",
+ .aif_name = "STUB_DTMF_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+ .probe = &msm_dai_stub_dai_probe,
+ .remove = &msm_dai_stub_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_stub_host_capture_tx_dai[] = {
+ {
+ .capture = {
+ .stream_name = "CS-VOICE HOST RX CAPTURE",
+ .aif_name = "STUB_HOST_RX_CAPTURE_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+ .probe = &msm_dai_stub_dai_probe,
+ .remove = &msm_dai_stub_dai_remove,
+ },
+ {
+ .capture = {
+ .stream_name = "CS-VOICE HOST TX CAPTURE",
+ .aif_name = "STUB_HOST_TX_CAPTURE_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+ .probe = &msm_dai_stub_dai_probe,
+ .remove = &msm_dai_stub_dai_remove,
+ },
+};
+
+static struct snd_soc_dai_driver msm_dai_stub_host_playback_rx_dai[] = {
+ {
+ .playback = {
+ .stream_name = "CS-VOICE HOST RX PLAYBACK",
+ .aif_name = "STUB_HOST_RX_PLAYBACK_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+ .probe = &msm_dai_stub_dai_probe,
+ .remove = &msm_dai_stub_dai_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "CS-VOICE HOST TX PLAYBACK",
+ .aif_name = "STUB_HOST_TX_PLAYBACK_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+ .probe = &msm_dai_stub_dai_probe,
+ .remove = &msm_dai_stub_dai_remove,
+ },
+};
+
+static const struct snd_soc_component_driver msm_dai_stub_component = {
+ .name = "msm-dai-stub-dev",
+};
+
+static int msm_dai_stub_dev_probe(struct platform_device *pdev)
+{
+ int rc, id = -1;
+ const char *stub_dev_id = "qcom,msm-dai-stub-dev-id";
+
+ rc = of_property_read_u32(pdev->dev.of_node, stub_dev_id, &id);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: missing %s in dt node\n", __func__, stub_dev_id);
+ return rc;
+ }
+
+ pdev->id = id;
+
+ pr_debug("%s: dev name %s, id:%d\n", __func__,
+ dev_name(&pdev->dev), pdev->id);
+
+ switch (id) {
+ case STUB_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_stub_component, &msm_dai_stub_dai_rx, 1);
+ break;
+ case STUB_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_stub_component, &msm_dai_stub_dai_tx[0], 1);
+ break;
+ case STUB_1_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_stub_component, &msm_dai_stub_dai_tx[1], 1);
+ break;
+ case STUB_DTMF_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_stub_component,
+ &msm_dai_stub_dtmf_tx_dai, 1);
+ break;
+ case STUB_HOST_RX_CAPTURE_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_stub_component,
+ &msm_dai_stub_host_capture_tx_dai[0], 1);
+ break;
+ case STUB_HOST_TX_CAPTURE_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_stub_component,
+ &msm_dai_stub_host_capture_tx_dai[1], 1);
+ break;
+ case STUB_HOST_RX_PLAYBACK_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_stub_component,
+ &msm_dai_stub_host_playback_rx_dai[0], 1);
+ break;
+ case STUB_HOST_TX_PLAYBACK_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_stub_component,
+ &msm_dai_stub_host_playback_rx_dai[1], 1);
+ break;
+ }
+
+ return rc;
+}
+
+static int msm_dai_stub_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_dai_stub_dev_dt_match[] = {
+ { .compatible = "qcom,msm-dai-stub-dev", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, msm_dai_stub_dev_dt_match);
+
+static struct platform_driver msm_dai_stub_dev = {
+ .probe = msm_dai_stub_dev_probe,
+ .remove = msm_dai_stub_dev_remove,
+ .driver = {
+ .name = "msm-dai-stub-dev",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_stub_dev_dt_match,
+ },
+};
+
+static int msm_dai_stub_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+
+ rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
+ __func__, rc);
+ } else
+ dev_dbg(&pdev->dev, "%s: added child node\n", __func__);
+
+ return rc;
+}
+
+static int msm_dai_stub_remove(struct platform_device *pdev)
+{
+ pr_debug("%s:\n", __func__);
+
+ return 0;
+}
+
+static const struct of_device_id msm_dai_stub_dt_match[] = {
+ {.compatible = "qcom,msm-dai-stub"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_stub_dt_match);
+
+
+static struct platform_driver msm_dai_stub_driver = {
+ .probe = msm_dai_stub_probe,
+ .remove = msm_dai_stub_remove,
+ .driver = {
+ .name = "msm-dai-stub",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_stub_dt_match,
+ },
+};
+
+static int __init msm_dai_stub_init(void)
+{
+ int rc = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ rc = platform_driver_register(&msm_dai_stub_driver);
+ if (rc) {
+ pr_err("%s: fail to register dai q6 driver", __func__);
+ goto fail;
+ }
+
+ rc = platform_driver_register(&msm_dai_stub_dev);
+ if (rc) {
+ pr_err("%s: fail to register dai q6 dev driver", __func__);
+ goto dai_stub_dev_fail;
+ }
+ return rc;
+
+dai_stub_dev_fail:
+ platform_driver_unregister(&msm_dai_stub_driver);
+fail:
+ return rc;
+}
+module_init(msm_dai_stub_init);
+
+static void __exit msm_dai_stub_exit(void)
+{
+ pr_debug("%s:\n", __func__);
+
+ platform_driver_unregister(&msm_dai_stub_dev);
+ platform_driver_unregister(&msm_dai_stub_driver);
+}
+module_exit(msm_dai_stub_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Stub DSP DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-common.h b/sound/soc/msm/qdsp6v2/msm-dolby-common.h
new file mode 100644
index 0000000..f14e42e
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-common.h
@@ -0,0 +1,266 @@
+
+/* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_DOLBY_COMMON_H_
+#define _MSM_DOLBY_COMMON_H_
+
+#include <sound/soc.h>
+
+
+#define DOLBY_BUNDLE_MODULE_ID 0x00010723
+#define DOLBY_VISUALIZER_MODULE_ID 0x0001072B
+
+#define DOLBY_PARAM_ID_VDHE 0x0001074D
+#define DOLBY_PARAM_ID_VSPE 0x00010750
+#define DOLBY_PARAM_ID_DSSF 0x00010753
+#define DOLBY_PARAM_ID_DVLI 0x0001073E
+#define DOLBY_PARAM_ID_DVLO 0x0001073F
+#define DOLBY_PARAM_ID_DVLE 0x0001073C
+#define DOLBY_PARAM_ID_DVMC 0x00010741
+#define DOLBY_PARAM_ID_DVME 0x00010740
+#define DOLBY_PARAM_ID_IENB 0x00010744
+#define DOLBY_PARAM_ID_IEBF 0x00010745
+#define DOLBY_PARAM_ID_IEON 0x00010743
+#define DOLBY_PARAM_ID_DEON 0x00010738
+#define DOLBY_PARAM_ID_NGON 0x00010736
+#define DOLBY_PARAM_ID_GEON 0x00010748
+#define DOLBY_PARAM_ID_GENB 0x00010749
+#define DOLBY_PARAM_ID_GEBF 0x0001074A
+#define DOLBY_PARAM_ID_AONB 0x0001075B
+#define DOLBY_PARAM_ID_AOBF 0x0001075C
+#define DOLBY_PARAM_ID_AOBG 0x0001075D
+#define DOLBY_PARAM_ID_AOON 0x00010759
+#define DOLBY_PARAM_ID_ARNB 0x0001075F
+#define DOLBY_PARAM_ID_ARBF 0x00010760
+#define DOLBY_PARAM_ID_PLB 0x00010768
+#define DOLBY_PARAM_ID_PLMD 0x00010767
+#define DOLBY_PARAM_ID_DHSB 0x0001074E
+#define DOLBY_PARAM_ID_DHRG 0x0001074F
+#define DOLBY_PARAM_ID_DSSB 0x00010751
+#define DOLBY_PARAM_ID_DSSA 0x00010752
+#define DOLBY_PARAM_ID_DVLA 0x0001073D
+#define DOLBY_PARAM_ID_IEBT 0x00010746
+#define DOLBY_PARAM_ID_IEA 0x0001076A
+#define DOLBY_PARAM_ID_DEA 0x00010739
+#define DOLBY_PARAM_ID_DED 0x0001073A
+#define DOLBY_PARAM_ID_GEBG 0x0001074B
+#define DOLBY_PARAM_ID_AOCC 0x0001075A
+#define DOLBY_PARAM_ID_ARBI 0x00010761
+#define DOLBY_PARAM_ID_ARBL 0x00010762
+#define DOLBY_PARAM_ID_ARBH 0x00010763
+#define DOLBY_PARAM_ID_AROD 0x00010764
+#define DOLBY_PARAM_ID_ARTP 0x00010765
+#define DOLBY_PARAM_ID_VMON 0x00010756
+#define DOLBY_PARAM_ID_VMB 0x00010757
+#define DOLBY_PARAM_ID_VCNB 0x00010733
+#define DOLBY_PARAM_ID_VCBF 0x00010734
+#define DOLBY_PARAM_ID_PREG 0x00010728
+#define DOLBY_PARAM_ID_VEN 0x00010732
+#define DOLBY_PARAM_ID_PSTG 0x00010729
+#define DOLBY_PARAM_ID_INIT_ENDP 0x00010727
+
+/* Not Used with Set Param kcontrol, only to query using Get Param */
+#define DOLBY_PARAM_ID_VER 0x00010726
+
+#define DOLBY_PARAM_ID_VCBG 0x00010730
+#define DOLBY_PARAM_ID_VCBE 0x00010731
+
+/* DOLBY DAP control params */
+#define DOLBY_COMMIT_ALL_TO_DSP 0x70000001
+#define DOLBY_COMMIT_TO_DSP 0x70000002
+#define DOLBY_USE_CACHE 0x70000003
+#define DOLBY_AUTO_ENDP 0x70000004
+#define DOLBY_AUTO_ENDDEP_PARAMS 0x70000005
+#define DOLBY_DAP_BYPASS 0x70000006
+
+#define DOLBY_ENABLE_CUSTOM_STEREO 0x000108c7
+
+/* DOLBY DAP offsets start */
+#define DOLBY_PARAM_VDHE_LENGTH 1
+#define DOLBY_PARAM_VDHE_OFFSET 0
+#define DOLBY_PARAM_VSPE_LENGTH 1
+#define DOLBY_PARAM_VSPE_OFFSET (DOLBY_PARAM_VDHE_OFFSET + \
+ DOLBY_PARAM_VDHE_LENGTH)
+#define DOLBY_PARAM_DSSF_LENGTH 1
+#define DOLBY_PARAM_DSSF_OFFSET (DOLBY_PARAM_VSPE_OFFSET + \
+ DOLBY_PARAM_VSPE_LENGTH)
+#define DOLBY_PARAM_DVLI_LENGTH 1
+#define DOLBY_PARAM_DVLI_OFFSET (DOLBY_PARAM_DSSF_OFFSET + \
+ DOLBY_PARAM_DSSF_LENGTH)
+#define DOLBY_PARAM_DVLO_LENGTH 1
+#define DOLBY_PARAM_DVLO_OFFSET (DOLBY_PARAM_DVLI_OFFSET + \
+ DOLBY_PARAM_DVLI_LENGTH)
+#define DOLBY_PARAM_DVLE_LENGTH 1
+#define DOLBY_PARAM_DVLE_OFFSET (DOLBY_PARAM_DVLO_OFFSET + \
+ DOLBY_PARAM_DVLO_LENGTH)
+#define DOLBY_PARAM_DVMC_LENGTH 1
+#define DOLBY_PARAM_DVMC_OFFSET (DOLBY_PARAM_DVLE_OFFSET + \
+ DOLBY_PARAM_DVLE_LENGTH)
+#define DOLBY_PARAM_DVME_LENGTH 1
+#define DOLBY_PARAM_DVME_OFFSET (DOLBY_PARAM_DVMC_OFFSET + \
+ DOLBY_PARAM_DVMC_LENGTH)
+#define DOLBY_PARAM_IENB_LENGTH 1
+#define DOLBY_PARAM_IENB_OFFSET (DOLBY_PARAM_DVME_OFFSET + \
+ DOLBY_PARAM_DVME_LENGTH)
+#define DOLBY_PARAM_IEBF_LENGTH 40
+#define DOLBY_PARAM_IEBF_OFFSET (DOLBY_PARAM_IENB_OFFSET + \
+ DOLBY_PARAM_IENB_LENGTH)
+#define DOLBY_PARAM_IEON_LENGTH 1
+#define DOLBY_PARAM_IEON_OFFSET (DOLBY_PARAM_IEBF_OFFSET + \
+ DOLBY_PARAM_IEBF_LENGTH)
+#define DOLBY_PARAM_DEON_LENGTH 1
+#define DOLBY_PARAM_DEON_OFFSET (DOLBY_PARAM_IEON_OFFSET + \
+ DOLBY_PARAM_IEON_LENGTH)
+#define DOLBY_PARAM_NGON_LENGTH 1
+#define DOLBY_PARAM_NGON_OFFSET (DOLBY_PARAM_DEON_OFFSET + \
+ DOLBY_PARAM_DEON_LENGTH)
+#define DOLBY_PARAM_GEON_LENGTH 1
+#define DOLBY_PARAM_GEON_OFFSET (DOLBY_PARAM_NGON_OFFSET + \
+ DOLBY_PARAM_NGON_LENGTH)
+#define DOLBY_PARAM_GENB_LENGTH 1
+#define DOLBY_PARAM_GENB_OFFSET (DOLBY_PARAM_GEON_OFFSET + \
+ DOLBY_PARAM_GEON_LENGTH)
+#define DOLBY_PARAM_GEBF_LENGTH 40
+#define DOLBY_PARAM_GEBF_OFFSET (DOLBY_PARAM_GENB_OFFSET + \
+ DOLBY_PARAM_GENB_LENGTH)
+#define DOLBY_PARAM_AONB_LENGTH 1
+#define DOLBY_PARAM_AONB_OFFSET (DOLBY_PARAM_GEBF_OFFSET + \
+ DOLBY_PARAM_GEBF_LENGTH)
+#define DOLBY_PARAM_AOBF_LENGTH 40
+#define DOLBY_PARAM_AOBF_OFFSET (DOLBY_PARAM_AONB_OFFSET + \
+ DOLBY_PARAM_AONB_LENGTH)
+#define DOLBY_PARAM_AOBG_LENGTH 329
+#define DOLBY_PARAM_AOBG_OFFSET (DOLBY_PARAM_AOBF_OFFSET + \
+ DOLBY_PARAM_AOBF_LENGTH)
+#define DOLBY_PARAM_AOON_LENGTH 1
+#define DOLBY_PARAM_AOON_OFFSET (DOLBY_PARAM_AOBG_OFFSET + \
+ DOLBY_PARAM_AOBG_LENGTH)
+#define DOLBY_PARAM_ARNB_LENGTH 1
+#define DOLBY_PARAM_ARNB_OFFSET (DOLBY_PARAM_AOON_OFFSET + \
+ DOLBY_PARAM_AOON_LENGTH)
+#define DOLBY_PARAM_ARBF_LENGTH 40
+#define DOLBY_PARAM_ARBF_OFFSET (DOLBY_PARAM_ARNB_OFFSET + \
+ DOLBY_PARAM_ARNB_LENGTH)
+#define DOLBY_PARAM_PLB_LENGTH 1
+#define DOLBY_PARAM_PLB_OFFSET (DOLBY_PARAM_ARBF_OFFSET + \
+ DOLBY_PARAM_ARBF_LENGTH)
+#define DOLBY_PARAM_PLMD_LENGTH 1
+#define DOLBY_PARAM_PLMD_OFFSET (DOLBY_PARAM_PLB_OFFSET + \
+ DOLBY_PARAM_PLB_LENGTH)
+#define DOLBY_PARAM_DHSB_LENGTH 1
+#define DOLBY_PARAM_DHSB_OFFSET (DOLBY_PARAM_PLMD_OFFSET + \
+ DOLBY_PARAM_PLMD_LENGTH)
+#define DOLBY_PARAM_DHRG_LENGTH 1
+#define DOLBY_PARAM_DHRG_OFFSET (DOLBY_PARAM_DHSB_OFFSET + \
+ DOLBY_PARAM_DHSB_LENGTH)
+#define DOLBY_PARAM_DSSB_LENGTH 1
+#define DOLBY_PARAM_DSSB_OFFSET (DOLBY_PARAM_DHRG_OFFSET + \
+ DOLBY_PARAM_DHRG_LENGTH)
+#define DOLBY_PARAM_DSSA_LENGTH 1
+#define DOLBY_PARAM_DSSA_OFFSET (DOLBY_PARAM_DSSB_OFFSET + \
+ DOLBY_PARAM_DSSB_LENGTH)
+#define DOLBY_PARAM_DVLA_LENGTH 1
+#define DOLBY_PARAM_DVLA_OFFSET (DOLBY_PARAM_DSSA_OFFSET + \
+ DOLBY_PARAM_DSSA_LENGTH)
+#define DOLBY_PARAM_IEBT_LENGTH 40
+#define DOLBY_PARAM_IEBT_OFFSET (DOLBY_PARAM_DVLA_OFFSET + \
+ DOLBY_PARAM_DVLA_LENGTH)
+#define DOLBY_PARAM_IEA_LENGTH 1
+#define DOLBY_PARAM_IEA_OFFSET (DOLBY_PARAM_IEBT_OFFSET + \
+ DOLBY_PARAM_IEBT_LENGTH)
+#define DOLBY_PARAM_DEA_LENGTH 1
+#define DOLBY_PARAM_DEA_OFFSET (DOLBY_PARAM_IEA_OFFSET + \
+ DOLBY_PARAM_IEA_LENGTH)
+#define DOLBY_PARAM_DED_LENGTH 1
+#define DOLBY_PARAM_DED_OFFSET (DOLBY_PARAM_DEA_OFFSET + \
+ DOLBY_PARAM_DEA_LENGTH)
+#define DOLBY_PARAM_GEBG_LENGTH 40
+#define DOLBY_PARAM_GEBG_OFFSET (DOLBY_PARAM_DED_OFFSET + \
+ DOLBY_PARAM_DED_LENGTH)
+#define DOLBY_PARAM_AOCC_LENGTH 1
+#define DOLBY_PARAM_AOCC_OFFSET (DOLBY_PARAM_GEBG_OFFSET + \
+ DOLBY_PARAM_GEBG_LENGTH)
+#define DOLBY_PARAM_ARBI_LENGTH 40
+#define DOLBY_PARAM_ARBI_OFFSET (DOLBY_PARAM_AOCC_OFFSET + \
+ DOLBY_PARAM_AOCC_LENGTH)
+#define DOLBY_PARAM_ARBL_LENGTH 40
+#define DOLBY_PARAM_ARBL_OFFSET (DOLBY_PARAM_ARBI_OFFSET + \
+ DOLBY_PARAM_ARBI_LENGTH)
+#define DOLBY_PARAM_ARBH_LENGTH 40
+#define DOLBY_PARAM_ARBH_OFFSET (DOLBY_PARAM_ARBL_OFFSET + \
+ DOLBY_PARAM_ARBL_LENGTH)
+#define DOLBY_PARAM_AROD_LENGTH 1
+#define DOLBY_PARAM_AROD_OFFSET (DOLBY_PARAM_ARBH_OFFSET + \
+ DOLBY_PARAM_ARBH_LENGTH)
+#define DOLBY_PARAM_ARTP_LENGTH 1
+#define DOLBY_PARAM_ARTP_OFFSET (DOLBY_PARAM_AROD_OFFSET + \
+ DOLBY_PARAM_AROD_LENGTH)
+#define DOLBY_PARAM_VMON_LENGTH 1
+#define DOLBY_PARAM_VMON_OFFSET (DOLBY_PARAM_ARTP_OFFSET + \
+ DOLBY_PARAM_ARTP_LENGTH)
+#define DOLBY_PARAM_VMB_LENGTH 1
+#define DOLBY_PARAM_VMB_OFFSET (DOLBY_PARAM_VMON_OFFSET + \
+ DOLBY_PARAM_VMON_LENGTH)
+#define DOLBY_PARAM_VCNB_LENGTH 1
+#define DOLBY_PARAM_VCNB_OFFSET (DOLBY_PARAM_VMB_OFFSET + \
+ DOLBY_PARAM_VMB_LENGTH)
+#define DOLBY_PARAM_VCBF_LENGTH 20
+#define DOLBY_PARAM_VCBF_OFFSET (DOLBY_PARAM_VCNB_OFFSET + \
+ DOLBY_PARAM_VCNB_LENGTH)
+#define DOLBY_PARAM_PREG_LENGTH 1
+#define DOLBY_PARAM_PREG_OFFSET (DOLBY_PARAM_VCBF_OFFSET + \
+ DOLBY_PARAM_VCBF_LENGTH)
+#define DOLBY_PARAM_VEN_LENGTH 1
+#define DOLBY_PARAM_VEN_OFFSET (DOLBY_PARAM_PREG_OFFSET + \
+ DOLBY_PARAM_PREG_LENGTH)
+#define DOLBY_PARAM_PSTG_LENGTH 1
+#define DOLBY_PARAM_PSTG_OFFSET (DOLBY_PARAM_VEN_OFFSET + \
+ DOLBY_PARAM_VEN_LENGTH)
+
+#define DOLBY_PARAM_INT_ENDP_LENGTH 1
+#define DOLBY_PARAM_PAYLOAD_SIZE 3
+#define DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM 329
+
+#define TOTAL_LENGTH_DOLBY_PARAM 745
+#define DOLBY_VIS_PARAM_HEADER_SIZE 25
+#define DOLBY_PARAM_VCNB_MAX_LENGTH 40
+
+#define DOLBY_INVALID_PORT_ID -1
+
+enum {
+ DEVICE_NONE = 0x0,
+ /* output devices */
+ EARPIECE = 0x1,
+ SPEAKER = 0x2,
+ WIRED_HEADSET = 0x4,
+ WIRED_HEADPHONE = 0x8,
+ BLUETOOTH_SCO = 0x10,
+ BLUETOOTH_SCO_HEADSET = 0x20,
+ BLUETOOTH_SCO_CARKIT = 0x40,
+ BLUETOOTH_A2DP = 0x80,
+ BLUETOOTH_A2DP_HEADPHONES = 0x100,
+ BLUETOOTH_A2DP_SPEAKER = 0x200,
+ AUX_DIGITAL = 0x400,
+ ANLG_DOCK_HEADSET = 0x800,
+ DGTL_DOCK_HEADSET = 0x1000,
+ USB_ACCESSORY = 0x2000,
+ USB_DEVICE = 0x4000,
+ REMOTE_SUBMIX = 0x8000,
+ ANC_HEADSET = 0x10000,
+ ANC_HEADPHONE = 0x20000,
+ PROXY = 0x2000000,
+ FM = 0x100000,
+ FM_TX = 0x1000000,
+ DEVICE_OUT_DEFAULT = 0x40000000,
+ DEVICE_OUT_ALL = 0x403FFFFF,
+};
+#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
new file mode 100644
index 0000000..29a1b3d
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -0,0 +1,1071 @@
+/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <sound/control.h>
+#include <sound/q6adm-v2.h>
+#include <sound/q6core.h>
+
+#include "msm-dolby-dap-config.h"
+
+/* dolby endp based parameters */
+struct dolby_dap_endp_params_s {
+ int device;
+ int device_ch_caps;
+ int dap_device;
+ int params_id[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
+ int params_len[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
+ int params_offset[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
+ int params_val[DOLBY_ENDDEP_PARAM_LENGTH];
+};
+
+const struct dolby_dap_endp_params_s
+ dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = {
+ {EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {WIRED_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {BLUETOOTH_SCO, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {BLUETOOTH_SCO_HEADSET, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {AUX_DIGITAL, 2, DOLBY_ENDP_HDMI,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-496, -496, 0}
+ },
+ {AUX_DIGITAL, 6, DOLBY_ENDP_HDMI,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-496, -496, 0}
+ },
+ {AUX_DIGITAL, 8, DOLBY_ENDP_HDMI,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-496, -496, 0}
+ },
+ {ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {USB_ACCESSORY, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {REMOTE_SUBMIX, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {PROXY, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {PROXY, 6, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+ {FM_TX, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
+};
+
+/* dolby param ids to/from dsp */
+static uint32_t dolby_dap_params_id[ALL_DOLBY_PARAMS] = {
+ DOLBY_PARAM_ID_VDHE, DOLBY_PARAM_ID_VSPE, DOLBY_PARAM_ID_DSSF,
+ DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLE,
+ DOLBY_PARAM_ID_DVMC, DOLBY_PARAM_ID_DVME, DOLBY_PARAM_ID_IENB,
+ DOLBY_PARAM_ID_IEBF, DOLBY_PARAM_ID_IEON, DOLBY_PARAM_ID_DEON,
+ DOLBY_PARAM_ID_NGON, DOLBY_PARAM_ID_GEON, DOLBY_PARAM_ID_GENB,
+ DOLBY_PARAM_ID_GEBF, DOLBY_PARAM_ID_AONB, DOLBY_PARAM_ID_AOBF,
+ DOLBY_PARAM_ID_AOBG, DOLBY_PARAM_ID_AOON, DOLBY_PARAM_ID_ARNB,
+ DOLBY_PARAM_ID_ARBF, DOLBY_PARAM_ID_PLB, DOLBY_PARAM_ID_PLMD,
+ DOLBY_PARAM_ID_DHSB, DOLBY_PARAM_ID_DHRG, DOLBY_PARAM_ID_DSSB,
+ DOLBY_PARAM_ID_DSSA, DOLBY_PARAM_ID_DVLA, DOLBY_PARAM_ID_IEBT,
+ DOLBY_PARAM_ID_IEA, DOLBY_PARAM_ID_DEA, DOLBY_PARAM_ID_DED,
+ DOLBY_PARAM_ID_GEBG, DOLBY_PARAM_ID_AOCC, DOLBY_PARAM_ID_ARBI,
+ DOLBY_PARAM_ID_ARBL, DOLBY_PARAM_ID_ARBH, DOLBY_PARAM_ID_AROD,
+ DOLBY_PARAM_ID_ARTP, DOLBY_PARAM_ID_VMON, DOLBY_PARAM_ID_VMB,
+ DOLBY_PARAM_ID_VCNB, DOLBY_PARAM_ID_VCBF, DOLBY_PARAM_ID_PREG,
+ DOLBY_PARAM_ID_VEN, DOLBY_PARAM_ID_PSTG, DOLBY_COMMIT_ALL_TO_DSP,
+ DOLBY_COMMIT_TO_DSP, DOLBY_USE_CACHE, DOLBY_AUTO_ENDP,
+ DOLBY_AUTO_ENDDEP_PARAMS
+};
+
+/* modifed state: 0x00000000 - Not updated
+ * > 0x00000000 && < 0x00010000
+ * Updated and not committed to DSP
+ * 0x00010001 - Updated and committed to DSP
+ * > 0x00010001 - Modified the committed value
+ */
+static int dolby_dap_params_modified[MAX_DOLBY_PARAMS] = { 0 };
+/* param offset */
+static uint32_t dolby_dap_params_offset[MAX_DOLBY_PARAMS] = {
+ DOLBY_PARAM_VDHE_OFFSET, DOLBY_PARAM_VSPE_OFFSET,
+ DOLBY_PARAM_DSSF_OFFSET, DOLBY_PARAM_DVLI_OFFSET,
+ DOLBY_PARAM_DVLO_OFFSET, DOLBY_PARAM_DVLE_OFFSET,
+ DOLBY_PARAM_DVMC_OFFSET, DOLBY_PARAM_DVME_OFFSET,
+ DOLBY_PARAM_IENB_OFFSET, DOLBY_PARAM_IEBF_OFFSET,
+ DOLBY_PARAM_IEON_OFFSET, DOLBY_PARAM_DEON_OFFSET,
+ DOLBY_PARAM_NGON_OFFSET, DOLBY_PARAM_GEON_OFFSET,
+ DOLBY_PARAM_GENB_OFFSET, DOLBY_PARAM_GEBF_OFFSET,
+ DOLBY_PARAM_AONB_OFFSET, DOLBY_PARAM_AOBF_OFFSET,
+ DOLBY_PARAM_AOBG_OFFSET, DOLBY_PARAM_AOON_OFFSET,
+ DOLBY_PARAM_ARNB_OFFSET, DOLBY_PARAM_ARBF_OFFSET,
+ DOLBY_PARAM_PLB_OFFSET, DOLBY_PARAM_PLMD_OFFSET,
+ DOLBY_PARAM_DHSB_OFFSET, DOLBY_PARAM_DHRG_OFFSET,
+ DOLBY_PARAM_DSSB_OFFSET, DOLBY_PARAM_DSSA_OFFSET,
+ DOLBY_PARAM_DVLA_OFFSET, DOLBY_PARAM_IEBT_OFFSET,
+ DOLBY_PARAM_IEA_OFFSET, DOLBY_PARAM_DEA_OFFSET,
+ DOLBY_PARAM_DED_OFFSET, DOLBY_PARAM_GEBG_OFFSET,
+ DOLBY_PARAM_AOCC_OFFSET, DOLBY_PARAM_ARBI_OFFSET,
+ DOLBY_PARAM_ARBL_OFFSET, DOLBY_PARAM_ARBH_OFFSET,
+ DOLBY_PARAM_AROD_OFFSET, DOLBY_PARAM_ARTP_OFFSET,
+ DOLBY_PARAM_VMON_OFFSET, DOLBY_PARAM_VMB_OFFSET,
+ DOLBY_PARAM_VCNB_OFFSET, DOLBY_PARAM_VCBF_OFFSET,
+ DOLBY_PARAM_PREG_OFFSET, DOLBY_PARAM_VEN_OFFSET,
+ DOLBY_PARAM_PSTG_OFFSET
+};
+/* param_length */
+static uint32_t dolby_dap_params_length[MAX_DOLBY_PARAMS] = {
+ DOLBY_PARAM_VDHE_LENGTH, DOLBY_PARAM_VSPE_LENGTH,
+ DOLBY_PARAM_DSSF_LENGTH, DOLBY_PARAM_DVLI_LENGTH,
+ DOLBY_PARAM_DVLO_LENGTH, DOLBY_PARAM_DVLE_LENGTH,
+ DOLBY_PARAM_DVMC_LENGTH, DOLBY_PARAM_DVME_LENGTH,
+ DOLBY_PARAM_IENB_LENGTH, DOLBY_PARAM_IEBF_LENGTH,
+ DOLBY_PARAM_IEON_LENGTH, DOLBY_PARAM_DEON_LENGTH,
+ DOLBY_PARAM_NGON_LENGTH, DOLBY_PARAM_GEON_LENGTH,
+ DOLBY_PARAM_GENB_LENGTH, DOLBY_PARAM_GEBF_LENGTH,
+ DOLBY_PARAM_AONB_LENGTH, DOLBY_PARAM_AOBF_LENGTH,
+ DOLBY_PARAM_AOBG_LENGTH, DOLBY_PARAM_AOON_LENGTH,
+ DOLBY_PARAM_ARNB_LENGTH, DOLBY_PARAM_ARBF_LENGTH,
+ DOLBY_PARAM_PLB_LENGTH, DOLBY_PARAM_PLMD_LENGTH,
+ DOLBY_PARAM_DHSB_LENGTH, DOLBY_PARAM_DHRG_LENGTH,
+ DOLBY_PARAM_DSSB_LENGTH, DOLBY_PARAM_DSSA_LENGTH,
+ DOLBY_PARAM_DVLA_LENGTH, DOLBY_PARAM_IEBT_LENGTH,
+ DOLBY_PARAM_IEA_LENGTH, DOLBY_PARAM_DEA_LENGTH,
+ DOLBY_PARAM_DED_LENGTH, DOLBY_PARAM_GEBG_LENGTH,
+ DOLBY_PARAM_AOCC_LENGTH, DOLBY_PARAM_ARBI_LENGTH,
+ DOLBY_PARAM_ARBL_LENGTH, DOLBY_PARAM_ARBH_LENGTH,
+ DOLBY_PARAM_AROD_LENGTH, DOLBY_PARAM_ARTP_LENGTH,
+ DOLBY_PARAM_VMON_LENGTH, DOLBY_PARAM_VMB_LENGTH,
+ DOLBY_PARAM_VCNB_LENGTH, DOLBY_PARAM_VCBF_LENGTH,
+ DOLBY_PARAM_PREG_LENGTH, DOLBY_PARAM_VEN_LENGTH,
+ DOLBY_PARAM_PSTG_LENGTH
+};
+
+/* param_value */
+static uint32_t dolby_dap_params_value[TOTAL_LENGTH_DOLBY_PARAM] = {0};
+
+struct dolby_dap_params_get_s {
+ int32_t port_id;
+ uint32_t device_id;
+ uint32_t param_id;
+ uint32_t offset;
+ uint32_t length;
+};
+
+struct dolby_dap_params_states_s {
+ bool use_cache;
+ bool auto_endp;
+ bool enddep_params;
+ int port_id[AFE_MAX_PORTS];
+ int copp_idx[AFE_MAX_PORTS];
+ int port_open_count;
+ int port_ids_dolby_can_be_enabled;
+ int device;
+};
+
+static struct dolby_dap_params_get_s dolby_dap_params_get = {-1, DEVICE_OUT_ALL,
+ 0, 0, 0};
+static struct dolby_dap_params_states_s dolby_dap_params_states = { true, true,
+ true, {DOLBY_INVALID_PORT_ID},
+ {-1}, 0, DEVICE_OUT_ALL, 0 };
+/*
+ * port_ids_dolby_can_be_enabled is set to 0x7FFFFFFF.
+ * this needs to be removed after interface validation
+ */
+
+static int msm_dolby_dap_map_device_to_dolby_endpoint(int device)
+{
+ int i, dolby_dap_device = DOLBY_ENDP_EXT_SPEAKERS;
+
+ for (i = 0; i < NUM_DOLBY_ENDP_DEVICE; i++) {
+ if (dolby_dap_endp_params[i].device == device) {
+ dolby_dap_device = dolby_dap_endp_params[i].dap_device;
+ break;
+ }
+ }
+ /* default the endpoint to speaker if corresponding device entry */
+ /* not found */
+ if (i >= NUM_DOLBY_ENDP_DEVICE)
+ dolby_dap_params_states.device = SPEAKER;
+ return dolby_dap_device;
+}
+
+static int msm_dolby_dap_send_end_point(int port_id, int copp_idx)
+{
+ int rc = 0;
+ char *params_value;
+ int *update_params_value;
+ uint32_t params_length = (DOLBY_PARAM_INT_ENDP_LENGTH +
+ DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t);
+
+ pr_debug("%s\n", __func__);
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value) {
+ pr_err("%s, params memory alloc failed", __func__);
+ return -ENOMEM;
+ }
+ update_params_value = (int *)params_value;
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ = DOLBY_PARAM_ID_INIT_ENDP;
+ *update_params_value++ = DOLBY_PARAM_INT_ENDP_LENGTH * sizeof(uint32_t);
+ *update_params_value++ =
+ msm_dolby_dap_map_device_to_dolby_endpoint(
+ dolby_dap_params_states.device);
+ rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
+ params_length);
+ if (rc) {
+ pr_err("%s: send dolby params failed\n", __func__);
+ rc = -EINVAL;
+ }
+ kfree(params_value);
+ return rc;
+}
+
+static int msm_dolby_dap_send_enddep_params(int port_id, int copp_idx,
+ int device_channels)
+{
+ int i, j, rc = 0, idx, offset;
+ char *params_value;
+ int *update_params_value;
+ uint32_t params_length = (DOLBY_ENDDEP_PARAM_LENGTH +
+ DOLBY_NUM_ENDP_DEPENDENT_PARAMS *
+ DOLBY_PARAM_PAYLOAD_SIZE) *
+ sizeof(uint32_t);
+
+ pr_debug("%s\n", __func__);
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value) {
+ pr_err("%s, params memory alloc failed", __func__);
+ return -ENOMEM;
+ }
+ update_params_value = (int *)params_value;
+ for (idx = 0; idx < NUM_DOLBY_ENDP_DEVICE; idx++) {
+ if (dolby_dap_endp_params[idx].device ==
+ dolby_dap_params_states.device) {
+ if (dolby_dap_params_states.device == AUX_DIGITAL ||
+ dolby_dap_params_states.device == PROXY) {
+ if (dolby_dap_endp_params[idx].device_ch_caps ==
+ device_channels)
+ break;
+ } else {
+ break;
+ }
+ }
+ }
+ if (idx >= NUM_DOLBY_ENDP_DEVICE) {
+ pr_err("%s: device is not set accordingly\n", __func__);
+ kfree(params_value);
+ return -EINVAL;
+ }
+ for (i = 0; i < DOLBY_ENDDEP_PARAM_LENGTH; i++) {
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ =
+ dolby_dap_endp_params[idx].params_id[i];
+ *update_params_value++ =
+ dolby_dap_endp_params[idx].params_len[i] *
+ sizeof(uint32_t);
+ offset = dolby_dap_endp_params[idx].params_offset[i];
+ for (j = 0; j < dolby_dap_endp_params[idx].params_len[i]; j++)
+ *update_params_value++ =
+ dolby_dap_endp_params[idx].params_val[offset+j];
+ }
+ rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
+ params_length);
+ if (rc) {
+ pr_err("%s: send dolby params failed\n", __func__);
+ rc = -EINVAL;
+ }
+ kfree(params_value);
+ return rc;
+}
+
+static int msm_dolby_dap_send_cached_params(int port_id, int copp_idx,
+ int commit)
+{
+ char *params_value;
+ int *update_params_value, rc = 0;
+ uint32_t index_offset, i, j;
+ uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
+ MAX_DOLBY_PARAMS * DOLBY_PARAM_PAYLOAD_SIZE) *
+ sizeof(uint32_t);
+
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value)
+ return -ENOMEM;
+
+ update_params_value = (int *)params_value;
+ params_length = 0;
+ for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
+ if ((dolby_dap_params_modified[i] == 0) ||
+ ((commit) &&
+ ((dolby_dap_params_modified[i] & 0x00010000) &&
+ ((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1))))
+ continue;
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ = dolby_dap_params_id[i];
+ *update_params_value++ = dolby_dap_params_length[i] *
+ sizeof(uint32_t);
+ index_offset = dolby_dap_params_offset[i];
+ for (j = 0; j < dolby_dap_params_length[i]; j++) {
+ *update_params_value++ =
+ dolby_dap_params_value[index_offset+j];
+ }
+ params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
+ dolby_dap_params_length[i]) * sizeof(uint32_t);
+ }
+ pr_debug("%s, valid param length: %d", __func__, params_length);
+ if (params_length) {
+ rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
+ params_length);
+ if (rc) {
+ pr_err("%s: send dolby params failed\n", __func__);
+ kfree(params_value);
+ return -EINVAL;
+ }
+ for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
+ if ((dolby_dap_params_modified[i] == 0) ||
+ ((commit) &&
+ ((dolby_dap_params_modified[i] & 0x00010000) &&
+ ((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1))
+ ))
+ continue;
+ dolby_dap_params_modified[i] = 0x00010001;
+ }
+ }
+ kfree(params_value);
+ return 0;
+}
+
+int msm_dolby_dap_init(int port_id, int copp_idx, int channels,
+ bool is_custom_stereo_on)
+{
+ int ret = 0;
+ int index = adm_validate_and_get_port_index(port_id);
+
+ if (index < 0) {
+ pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
+ port_id);
+ return -EINVAL;
+ }
+ if ((port_id != DOLBY_INVALID_PORT_ID) &&
+ (port_id & dolby_dap_params_states.port_ids_dolby_can_be_enabled)) {
+ dolby_dap_params_states.port_id[index] = port_id;
+ dolby_dap_params_states.copp_idx[index] = copp_idx;
+ dolby_dap_params_states.port_open_count++;
+ if (dolby_dap_params_states.auto_endp) {
+ ret = msm_dolby_dap_send_end_point(port_id, copp_idx);
+ if (ret) {
+ pr_err("%s: err sending endppoint\n", __func__);
+ return ret;
+ }
+ }
+ if (dolby_dap_params_states.use_cache) {
+ ret = msm_dolby_dap_send_cached_params(port_id,
+ copp_idx, 0);
+ if (ret) {
+ pr_err("%s: err sending cached params\n",
+ __func__);
+ return ret;
+ }
+ }
+ if (dolby_dap_params_states.enddep_params) {
+ msm_dolby_dap_send_enddep_params(port_id, copp_idx,
+ channels);
+ if (ret) {
+ pr_err("%s: err sending endp dependent params\n",
+ __func__);
+ return ret;
+ }
+ }
+ if (is_custom_stereo_on)
+ dolby_dap_set_custom_stereo_onoff(port_id, copp_idx,
+ is_custom_stereo_on);
+ }
+ return ret;
+}
+
+void msm_dolby_dap_deinit(int port_id)
+{
+ int index = adm_validate_and_get_port_index(port_id);
+
+ if (index < 0) {
+ pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
+ port_id);
+ return;
+ }
+ dolby_dap_params_states.port_open_count--;
+ if ((dolby_dap_params_states.port_id[index] == port_id) &&
+ (!dolby_dap_params_states.port_open_count)) {
+ dolby_dap_params_states.port_id[index] = DOLBY_INVALID_PORT_ID;
+ dolby_dap_params_states.copp_idx[index] = -1;
+ }
+}
+
+static int msm_dolby_dap_set_vspe_vdhe(int port_id, int copp_idx,
+ bool is_custom_stereo_enabled)
+{
+ char *params_value;
+ int *update_params_value, rc = 0;
+ uint32_t index_offset, i, j;
+ uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
+ 2 * DOLBY_PARAM_PAYLOAD_SIZE) *
+ sizeof(uint32_t);
+ if (port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s: Not a Dolby topology. Do not set custom stereo mixing\n",
+ __func__);
+ return -EINVAL;
+ }
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value)
+ return -ENOMEM;
+
+ update_params_value = (int *)params_value;
+ params_length = 0;
+ /* for VDHE and VSPE DAP params at index 0 and 1 in table */
+ for (i = 0; i < 2; i++) {
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ = dolby_dap_params_id[i];
+ *update_params_value++ = dolby_dap_params_length[i] *
+ sizeof(uint32_t);
+ index_offset = dolby_dap_params_offset[i];
+ for (j = 0; j < dolby_dap_params_length[i]; j++) {
+ if (is_custom_stereo_enabled)
+ *update_params_value++ = 0;
+ else
+ *update_params_value++ =
+ dolby_dap_params_value[index_offset+j];
+ }
+ params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
+ dolby_dap_params_length[i]) * sizeof(uint32_t);
+ }
+ pr_debug("%s, valid param length: %d", __func__, params_length);
+ if (params_length) {
+ rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
+ params_length);
+ if (rc) {
+ pr_err("%s: send vdhe/vspe params failed with rc=%d\n",
+ __func__, rc);
+ kfree(params_value);
+ return -EINVAL;
+ }
+ }
+ kfree(params_value);
+ return 0;
+}
+
+int dolby_dap_set_custom_stereo_onoff(int port_id, int copp_idx,
+ bool is_custom_stereo_enabled)
+{
+ char *params_value;
+ int *update_params_value, rc = 0;
+ uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
+ DOLBY_PARAM_PAYLOAD_SIZE) *
+ sizeof(uint32_t);
+ if (port_id == DOLBY_INVALID_PORT_ID)
+ return -EINVAL;
+
+ msm_dolby_dap_set_vspe_vdhe(port_id, copp_idx,
+ is_custom_stereo_enabled);
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value) {
+ pr_err("%s, params memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ update_params_value = (int *)params_value;
+ params_length = 0;
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ = DOLBY_ENABLE_CUSTOM_STEREO;
+ *update_params_value++ = sizeof(uint32_t);
+ if (is_custom_stereo_enabled)
+ *update_params_value++ = 1;
+ else
+ *update_params_value++ = 0;
+ params_length += (DOLBY_PARAM_PAYLOAD_SIZE + 1) * sizeof(uint32_t);
+ pr_debug("%s, valid param length: %d", __func__, params_length);
+ if (params_length) {
+ rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
+ params_length);
+ if (rc) {
+ pr_err("%s: setting ds1 custom stereo param failed with rc=%d\n",
+ __func__, rc);
+ kfree(params_value);
+ return -EINVAL;
+ }
+ }
+ kfree(params_value);
+ return 0;
+}
+
+static int msm_dolby_dap_map_device_to_port_id(int device)
+{
+ int port_id = SLIMBUS_0_RX;
+
+ device = DEVICE_OUT_ALL;
+ /*update the device when single stream to multiple device is handled*/
+ if (device == DEVICE_OUT_ALL) {
+ port_id = PRIMARY_I2S_RX | SLIMBUS_0_RX | HDMI_RX |
+ INT_BT_SCO_RX | INT_FM_RX |
+ RT_PROXY_PORT_001_RX |
+ AFE_PORT_ID_PRIMARY_PCM_RX |
+ MI2S_RX | SECONDARY_I2S_RX |
+ SLIMBUS_1_RX | SLIMBUS_4_RX | SLIMBUS_3_RX |
+ AFE_PORT_ID_SECONDARY_MI2S_RX;
+ } else {
+ /* update port_id based on the device */
+ }
+ return port_id;
+}
+
+int msm_dolby_dap_param_to_set_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* not used while setting the parameters */
+ return 0;
+}
+
+int msm_dolby_dap_param_to_set_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0, port_id, copp_idx;
+ uint32_t idx, j;
+ uint32_t device = ucontrol->value.integer.value[0];
+ uint32_t param_id = ucontrol->value.integer.value[1];
+ uint32_t offset = ucontrol->value.integer.value[2];
+ uint32_t length = ucontrol->value.integer.value[3];
+
+ dolby_dap_params_states.port_ids_dolby_can_be_enabled =
+ msm_dolby_dap_map_device_to_port_id(device);
+ for (idx = 0; idx < ALL_DOLBY_PARAMS; idx++) {
+ /*paramid from user space*/
+ if (param_id == dolby_dap_params_id[idx])
+ break;
+ }
+ if (idx > ALL_DOLBY_PARAMS-1) {
+ pr_err("%s: invalid param id 0x%x to set\n", __func__,
+ param_id);
+ return -EINVAL;
+ }
+ switch (idx) {
+ case DOLBY_COMMIT_ALL_IDX: {
+ /* COMIIT ALL: Send all parameters to DSP */
+ pr_debug("%s: COMMIT_ALL recvd\n", __func__);
+ for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
+ port_id = dolby_dap_params_states.port_id[idx];
+ copp_idx =
+ dolby_dap_params_states.copp_idx[idx];
+ if ((copp_idx > 0) &&
+ (copp_idx < MAX_COPPS_PER_PORT) &&
+ (port_id != DOLBY_INVALID_PORT_ID))
+ rc |= msm_dolby_dap_send_cached_params(
+ port_id,
+ copp_idx,
+ 0);
+ }
+ }
+ break;
+ case DOLBY_COMMIT_IDX: {
+ pr_debug("%s: COMMIT recvd\n", __func__);
+ /* COMMIT: Send only modified parameters to DSP */
+ for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
+ port_id = dolby_dap_params_states.port_id[idx];
+ copp_idx =
+ dolby_dap_params_states.copp_idx[idx];
+ if ((copp_idx > 0) &&
+ (copp_idx < MAX_COPPS_PER_PORT) &&
+ (port_id == DOLBY_INVALID_PORT_ID))
+ rc |= msm_dolby_dap_send_cached_params(
+ port_id,
+ copp_idx,
+ 1);
+ }
+ }
+ break;
+ case DOLBY_USE_CACHE_IDX: {
+ pr_debug("%s: USE CACHE recvd val: %ld\n", __func__,
+ ucontrol->value.integer.value[4]);
+ dolby_dap_params_states.use_cache =
+ ucontrol->value.integer.value[4];
+ }
+ break;
+ case DOLBY_AUTO_ENDP_IDX: {
+ pr_debug("%s: AUTO_ENDP recvd val: %ld\n", __func__,
+ ucontrol->value.integer.value[4]);
+ dolby_dap_params_states.auto_endp =
+ ucontrol->value.integer.value[4];
+ }
+ break;
+ case DOLBY_AUTO_ENDDEP_IDX: {
+ pr_debug("%s: USE_ENDDEP_PARAMS recvd val: %ld\n",
+ __func__, ucontrol->value.integer.value[4]);
+ dolby_dap_params_states.enddep_params =
+ ucontrol->value.integer.value[4];
+ }
+ break;
+ default: {
+ /* cache the parameters */
+ dolby_dap_params_modified[idx] += 1;
+ dolby_dap_params_length[idx] = length;
+ pr_debug("%s: param recvd deviceId=0x%x paramId=0x%x offset=%d length=%d\n",
+ __func__, device, param_id, offset, length);
+ for (j = 0; j < length; j++) {
+ dolby_dap_params_value[
+ dolby_dap_params_offset[idx] +
+ offset + j]
+ = ucontrol->value.integer.value[4+j];
+ pr_debug("value[%d]: %ld\n", j,
+ ucontrol->value.integer.value[4+j]);
+ }
+ }
+ }
+
+ return rc;
+}
+
+int msm_dolby_dap_param_to_get_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0, i, index;
+ char *params_value;
+ int *update_params_value;
+ uint32_t params_length = DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM *
+ sizeof(uint32_t);
+ uint32_t param_payload_len =
+ DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
+ int port_id = dolby_dap_params_get.port_id, copp_idx;
+
+ if (port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s, port_id not set, do not query ADM\n", __func__);
+ return -EINVAL;
+ }
+ index = adm_validate_and_get_port_index(port_id);
+ if (index < 0) {
+ pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
+ port_id);
+ return -EINVAL;
+ }
+ copp_idx = dolby_dap_params_states.copp_idx[index];
+ if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_debug("%s: get params called before copp open.copp_idx:%d\n",
+ __func__, copp_idx);
+ return -EINVAL;
+ }
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value)
+ return -ENOMEM;
+
+ if (dolby_dap_params_get.param_id == DOLBY_PARAM_ID_VER) {
+ rc = adm_get_params(port_id, copp_idx,
+ DOLBY_BUNDLE_MODULE_ID, DOLBY_PARAM_ID_VER,
+ params_length + param_payload_len,
+ params_value);
+ } else {
+ for (i = 0; i < MAX_DOLBY_PARAMS; i++)
+ if (dolby_dap_params_id[i] ==
+ dolby_dap_params_get.param_id)
+ break;
+ if (i > MAX_DOLBY_PARAMS-1) {
+ pr_err("%s: invalid param id to set", __func__);
+ rc = -EINVAL;
+ } else {
+ params_length = (dolby_dap_params_length[i] +
+ DOLBY_PARAM_PAYLOAD_SIZE) *
+ sizeof(uint32_t);
+ rc = adm_get_params(port_id, copp_idx,
+ DOLBY_BUNDLE_MODULE_ID,
+ dolby_dap_params_id[i],
+ params_length + param_payload_len,
+ params_value);
+ }
+ }
+ if (rc) {
+ pr_err("%s: get parameters failed rc:%d\n", __func__, rc);
+ kfree(params_value);
+ return -EINVAL;
+ }
+ update_params_value = (int *)params_value;
+ ucontrol->value.integer.value[0] = dolby_dap_params_get.device_id;
+ ucontrol->value.integer.value[1] = dolby_dap_params_get.param_id;
+ ucontrol->value.integer.value[2] = dolby_dap_params_get.offset;
+ ucontrol->value.integer.value[3] = dolby_dap_params_get.length;
+
+ pr_debug("%s: FROM DSP value[0] 0x%x value[1] %d value[2] 0x%x\n",
+ __func__, update_params_value[0],
+ update_params_value[1], update_params_value[2]);
+ for (i = 0; i < dolby_dap_params_get.length; i++) {
+ ucontrol->value.integer.value[DOLBY_PARAM_PAYLOAD_SIZE+i] =
+ update_params_value[i];
+ pr_debug("value[%d]:%d\n", i, update_params_value[i]);
+ }
+ pr_debug("%s: Returning param_id=0x%x offset=%d length=%d\n",
+ __func__, dolby_dap_params_get.param_id,
+ dolby_dap_params_get.offset,
+ dolby_dap_params_get.length);
+ kfree(params_value);
+ return 0;
+}
+
+int msm_dolby_dap_param_to_get_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int port_id, idx, copp_idx;
+
+ dolby_dap_params_get.device_id = ucontrol->value.integer.value[0];
+ port_id = msm_dolby_dap_map_device_to_port_id(
+ dolby_dap_params_get.device_id);
+ for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
+ port_id = dolby_dap_params_states.port_id[idx];
+ copp_idx = dolby_dap_params_states.copp_idx[idx];
+ if ((copp_idx < 0) ||
+ (copp_idx >= MAX_COPPS_PER_PORT) ||
+ (port_id == DOLBY_INVALID_PORT_ID))
+ continue;
+ else
+ break;
+ }
+ if (idx == AFE_MAX_PORTS)
+ port_id = SLIMBUS_0_RX;
+ dolby_dap_params_get.port_id = port_id;
+ dolby_dap_params_get.param_id = ucontrol->value.integer.value[1];
+ dolby_dap_params_get.offset = ucontrol->value.integer.value[2];
+ dolby_dap_params_get.length = ucontrol->value.integer.value[3];
+ pr_debug("%s: param_id=0x%x offset=%d length=%d\n", __func__,
+ dolby_dap_params_get.param_id, dolby_dap_params_get.offset,
+ dolby_dap_params_get.length);
+ return 0;
+}
+
+int msm_dolby_dap_param_visualizer_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t length = dolby_dap_params_value[DOLBY_PARAM_VCNB_OFFSET];
+ char *visualizer_data;
+ int i, rc;
+ int *update_visualizer_data;
+ uint32_t offset, params_length =
+ (2*length + DOLBY_VIS_PARAM_HEADER_SIZE)*sizeof(uint32_t);
+ uint32_t param_payload_len =
+ DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
+ int port_id, copp_idx, idx;
+
+ for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
+ port_id = dolby_dap_params_states.port_id[idx];
+ copp_idx = dolby_dap_params_states.copp_idx[idx];
+ if ((copp_idx < 0) ||
+ (copp_idx >= MAX_COPPS_PER_PORT) ||
+ (port_id == DOLBY_INVALID_PORT_ID))
+ continue;
+ else
+ break;
+ }
+ if (idx == AFE_MAX_PORTS) {
+ pr_debug("%s, port_id not set, returning error", __func__);
+ ucontrol->value.integer.value[0] = 0;
+ return -EINVAL;
+ }
+ visualizer_data = kzalloc(params_length, GFP_KERNEL);
+ if (!visualizer_data)
+ return -ENOMEM;
+
+ offset = 0;
+ params_length = length * sizeof(uint32_t);
+ rc = adm_get_params(port_id, copp_idx, DOLBY_BUNDLE_MODULE_ID,
+ DOLBY_PARAM_ID_VCBG,
+ params_length + param_payload_len,
+ visualizer_data + offset);
+ if (rc) {
+ pr_err("%s: get parameters failed\n", __func__);
+ kfree(visualizer_data);
+ return -EINVAL;
+ }
+
+ offset = length * sizeof(uint32_t);
+ rc = adm_get_params(port_id, copp_idx, DOLBY_BUNDLE_MODULE_ID,
+ DOLBY_PARAM_ID_VCBE,
+ params_length + param_payload_len,
+ visualizer_data + offset);
+ if (rc) {
+ pr_err("%s: get parameters failed\n", __func__);
+ kfree(visualizer_data);
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] = 2*length;
+ pr_debug("%s: visualizer data length %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ update_visualizer_data = (int *)visualizer_data;
+ for (i = 0; i < 2*length; i++) {
+ ucontrol->value.integer.value[1+i] = update_visualizer_data[i];
+ pr_debug("value[%d] %d\n", i, update_visualizer_data[i]);
+ }
+ kfree(visualizer_data);
+ return 0;
+}
+
+int msm_dolby_dap_param_visualizer_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* not used while getting the visualizer data */
+ return 0;
+}
+
+int msm_dolby_dap_endpoint_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* not used while setting the endpoint */
+ return 0;
+}
+
+int msm_dolby_dap_endpoint_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int device = ucontrol->value.integer.value[0];
+
+ dolby_dap_params_states.device = device;
+ return 0;
+}
+
+int msm_dolby_dap_security_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* not used while setting the manfr id*/
+ return 0;
+}
+
+int msm_dolby_dap_security_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int manufacturer_id = ucontrol->value.integer.value[0];
+
+ core_set_dolby_manufacturer_id(manufacturer_id);
+ return 0;
+}
+
+int msm_dolby_dap_license_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ core_get_license_status(DOLBY_DS1_LICENSE_ID);
+ return 0;
+}
+
+int msm_dolby_dap_license_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return core_set_license(ucontrol->value.integer.value[0],
+ DOLBY_DS1_LICENSE_ID);
+}
+
+static const struct snd_kcontrol_new dolby_license_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DS1 License", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, 1, msm_dolby_dap_license_control_get,
+ msm_dolby_dap_license_control_put),
+};
+
+static const struct snd_kcontrol_new dolby_security_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DS1 Security", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, 1, msm_dolby_dap_security_control_get,
+ msm_dolby_dap_security_control_put),
+};
+
+static const struct snd_kcontrol_new dolby_dap_param_to_set_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DS1 DAP Set Param", SND_SOC_NOPM, 0, 0xFFFFFFFF,
+ 0, 128, msm_dolby_dap_param_to_set_control_get,
+ msm_dolby_dap_param_to_set_control_put),
+};
+
+static const struct snd_kcontrol_new dolby_dap_param_to_get_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DS1 DAP Get Param", SND_SOC_NOPM, 0, 0xFFFFFFFF,
+ 0, 128, msm_dolby_dap_param_to_get_control_get,
+ msm_dolby_dap_param_to_get_control_put),
+};
+
+static const struct snd_kcontrol_new dolby_dap_param_visualizer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DS1 DAP Get Visualizer", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, 41, msm_dolby_dap_param_visualizer_control_get,
+ msm_dolby_dap_param_visualizer_control_put),
+};
+
+static const struct snd_kcontrol_new dolby_dap_param_end_point_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DS1 DAP Endpoint", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, 1, msm_dolby_dap_endpoint_control_get,
+ msm_dolby_dap_endpoint_control_put),
+};
+
+void msm_dolby_dap_add_controls(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform,
+ dolby_license_controls,
+ ARRAY_SIZE(dolby_license_controls));
+
+ snd_soc_add_platform_controls(platform,
+ dolby_security_controls,
+ ARRAY_SIZE(dolby_security_controls));
+
+ snd_soc_add_platform_controls(platform,
+ dolby_dap_param_to_set_controls,
+ ARRAY_SIZE(dolby_dap_param_to_set_controls));
+
+ snd_soc_add_platform_controls(platform,
+ dolby_dap_param_to_get_controls,
+ ARRAY_SIZE(dolby_dap_param_to_get_controls));
+
+ snd_soc_add_platform_controls(platform,
+ dolby_dap_param_visualizer_controls,
+ ARRAY_SIZE(dolby_dap_param_visualizer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ dolby_dap_param_end_point_controls,
+ ARRAY_SIZE(dolby_dap_param_end_point_controls));
+}
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
new file mode 100644
index 0000000..ca6310a
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_DOLBY_DAP_CONFIG_H_
+#define _MSM_DOLBY_DAP_CONFIG_H_
+
+#include <sound/soc.h>
+#include "msm-dolby-common.h"
+
+#ifdef CONFIG_DOLBY_DAP
+/* DOLBY DOLBY GUIDS */
+#define DOLBY_ADM_COPP_TOPOLOGY_ID 0x0001033B
+#define NUM_DOLBY_ENDP_DEVICE 23
+
+#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS 3
+#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET 0
+#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH 1
+#define DOLBY_ENDDEP_PARAM_DVLI_OFFSET (DOLBY_ENDDEP_PARAM_DVLO_OFFSET + \
+ DOLBY_ENDDEP_PARAM_DVLO_LENGTH)
+#define DOLBY_ENDDEP_PARAM_DVLI_LENGTH 1
+#define DOLBY_ENDDEP_PARAM_VMB_OFFSET (DOLBY_ENDDEP_PARAM_DVLI_OFFSET + \
+ DOLBY_ENDDEP_PARAM_DVLI_LENGTH)
+#define DOLBY_ENDDEP_PARAM_VMB_LENGTH 1
+#define DOLBY_ENDDEP_PARAM_LENGTH (DOLBY_ENDDEP_PARAM_DVLO_LENGTH + \
+ DOLBY_ENDDEP_PARAM_DVLI_LENGTH + DOLBY_ENDDEP_PARAM_VMB_LENGTH)
+
+#define MAX_DOLBY_PARAMS 47
+#define MAX_DOLBY_CTRL_PARAMS 5
+#define ALL_DOLBY_PARAMS (MAX_DOLBY_PARAMS + \
+ MAX_DOLBY_CTRL_PARAMS)
+#define DOLBY_COMMIT_ALL_IDX MAX_DOLBY_PARAMS
+#define DOLBY_COMMIT_IDX (MAX_DOLBY_PARAMS+1)
+#define DOLBY_USE_CACHE_IDX (MAX_DOLBY_PARAMS+2)
+#define DOLBY_AUTO_ENDP_IDX (MAX_DOLBY_PARAMS+3)
+#define DOLBY_AUTO_ENDDEP_IDX (MAX_DOLBY_PARAMS+4)
+
+/* DOLBY device definitions */
+enum {
+ DOLBY_ENDP_INT_SPEAKERS = 0,
+ DOLBY_ENDP_EXT_SPEAKERS,
+ DOLBY_ENDP_HEADPHONES,
+ DOLBY_ENDP_HDMI,
+ DOLBY_ENDP_SPDIF,
+ DOLBY_ENDP_DLNA,
+ DOLBY_ENDP_ANALOG,
+};
+
+/* DOLBY device definitions end */
+
+struct dolby_dap_params {
+ uint32_t value[TOTAL_LENGTH_DOLBY_PARAM + MAX_DOLBY_PARAMS];
+} __packed;
+
+int msm_dolby_dap_init(int port_id, int copp_idx, int channels,
+ bool is_custom_stereo_on);
+void msm_dolby_dap_deinit(int port_id);
+void msm_dolby_dap_add_controls(struct snd_soc_platform *platform);
+int dolby_dap_set_custom_stereo_onoff(int port_id, int copp_idx,
+ bool is_custom_stereo_enabled);
+/* Dolby DOLBY end */
+#else
+int msm_dolby_dap_init(int port_id, int copp_idx, int channels,
+ bool is_custom_stereo_on)
+{
+ return 0;
+}
+void msm_dolby_dap_deinit(int port_id) { }
+void msm_dolby_dap_add_controls(struct snd_soc_platform *platform) { }
+int dolby_dap_set_custom_stereo_onoff(int port_id, int copp_idx,
+ bool is_custom_stereo_enabled)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
new file mode 100644
index 0000000..40ea49c
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
@@ -0,0 +1,2299 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <sound/control.h>
+#include <sound/q6adm-v2.h>
+
+#include "msm-ds2-dap-config.h"
+#include "msm-pcm-routing-v2.h"
+#include <sound/q6core.h>
+
+
+#ifdef CONFIG_DOLBY_DS2
+
+/* ramp up/down for 30ms */
+#define DOLBY_SOFT_VOLUME_PERIOD 40
+/* Step value 0ms or 0us */
+#define DOLBY_SOFT_VOLUME_STEP 1000
+#define DOLBY_ADDITIONAL_RAMP_WAIT 10
+#define SOFT_VOLUME_PARAM_SIZE 3
+#define PARAM_PAYLOAD_SIZE 3
+
+enum {
+ DOLBY_SOFT_VOLUME_CURVE_LINEAR = 0,
+ DOLBY_SOFT_VOLUME_CURVE_EXP,
+ DOLBY_SOFT_VOLUME_CURVE_LOG,
+};
+
+#define VOLUME_ZERO_GAIN 0x0
+#define VOLUME_UNITY_GAIN 0x2000
+/* Wait time for module enable/disble */
+#define DOLBY_MODULE_ENABLE_PERIOD 50
+
+/* DOLBY device definitions end */
+enum {
+ DOLBY_OFF_CACHE = 0,
+ DOLBY_SPEAKER_CACHE,
+ DOLBY_HEADPHONE_CACHE,
+ DOLBY_HDMI_CACHE,
+ DOLBY_WFD_CACHE,
+ DOLBY_FM_CACHE,
+ DOLBY_MAX_CACHE,
+};
+
+enum {
+ DAP_SOFT_BYPASS = 0,
+ DAP_HARD_BYPASS,
+};
+
+enum {
+ MODULE_DISABLE = 0,
+ MODULE_ENABLE,
+};
+/* dolby param ids to/from dsp */
+static uint32_t ds2_dap_params_id[MAX_DS2_PARAMS] = {
+ DOLBY_PARAM_ID_VDHE, DOLBY_PARAM_ID_VSPE, DOLBY_PARAM_ID_DSSF,
+ DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLE,
+ DOLBY_PARAM_ID_DVMC, DOLBY_PARAM_ID_DVME, DOLBY_PARAM_ID_IENB,
+ DOLBY_PARAM_ID_IEBF, DOLBY_PARAM_ID_IEON, DOLBY_PARAM_ID_DEON,
+ DOLBY_PARAM_ID_NGON, DOLBY_PARAM_ID_GEON, DOLBY_PARAM_ID_GENB,
+ DOLBY_PARAM_ID_GEBF, DOLBY_PARAM_ID_AONB, DOLBY_PARAM_ID_AOBF,
+ DOLBY_PARAM_ID_AOBG, DOLBY_PARAM_ID_AOON, DOLBY_PARAM_ID_ARNB,
+ DOLBY_PARAM_ID_ARBF, DOLBY_PARAM_ID_PLB, DOLBY_PARAM_ID_PLMD,
+ DOLBY_PARAM_ID_DHSB, DOLBY_PARAM_ID_DHRG, DOLBY_PARAM_ID_DSSB,
+ DOLBY_PARAM_ID_DSSA, DOLBY_PARAM_ID_DVLA, DOLBY_PARAM_ID_IEBT,
+ DOLBY_PARAM_ID_IEA, DOLBY_PARAM_ID_DEA, DOLBY_PARAM_ID_DED,
+ DOLBY_PARAM_ID_GEBG, DOLBY_PARAM_ID_AOCC, DOLBY_PARAM_ID_ARBI,
+ DOLBY_PARAM_ID_ARBL, DOLBY_PARAM_ID_ARBH, DOLBY_PARAM_ID_AROD,
+ DOLBY_PARAM_ID_ARTP, DOLBY_PARAM_ID_VMON, DOLBY_PARAM_ID_VMB,
+ DOLBY_PARAM_ID_VCNB, DOLBY_PARAM_ID_VCBF, DOLBY_PARAM_ID_PREG,
+ DOLBY_PARAM_ID_VEN, DOLBY_PARAM_ID_PSTG, DOLBY_PARAM_ID_INIT_ENDP,
+};
+
+/* modifed state: 0x00000000 - Not updated
+ * > 0x00000000 && < 0x00010000
+ * Updated and not committed to DSP
+ * 0x00010001 - Updated and committed to DSP
+ * > 0x00010001 - Modified the committed value
+ */
+/* param offset */
+static uint32_t ds2_dap_params_offset[MAX_DS2_PARAMS] = {
+ DOLBY_PARAM_VDHE_OFFSET, DOLBY_PARAM_VSPE_OFFSET,
+ DOLBY_PARAM_DSSF_OFFSET, DOLBY_PARAM_DVLI_OFFSET,
+ DOLBY_PARAM_DVLO_OFFSET, DOLBY_PARAM_DVLE_OFFSET,
+ DOLBY_PARAM_DVMC_OFFSET, DOLBY_PARAM_DVME_OFFSET,
+ DOLBY_PARAM_IENB_OFFSET, DOLBY_PARAM_IEBF_OFFSET,
+ DOLBY_PARAM_IEON_OFFSET, DOLBY_PARAM_DEON_OFFSET,
+ DOLBY_PARAM_NGON_OFFSET, DOLBY_PARAM_GEON_OFFSET,
+ DOLBY_PARAM_GENB_OFFSET, DOLBY_PARAM_GEBF_OFFSET,
+ DOLBY_PARAM_AONB_OFFSET, DOLBY_PARAM_AOBF_OFFSET,
+ DOLBY_PARAM_AOBG_OFFSET, DOLBY_PARAM_AOON_OFFSET,
+ DOLBY_PARAM_ARNB_OFFSET, DOLBY_PARAM_ARBF_OFFSET,
+ DOLBY_PARAM_PLB_OFFSET, DOLBY_PARAM_PLMD_OFFSET,
+ DOLBY_PARAM_DHSB_OFFSET, DOLBY_PARAM_DHRG_OFFSET,
+ DOLBY_PARAM_DSSB_OFFSET, DOLBY_PARAM_DSSA_OFFSET,
+ DOLBY_PARAM_DVLA_OFFSET, DOLBY_PARAM_IEBT_OFFSET,
+ DOLBY_PARAM_IEA_OFFSET, DOLBY_PARAM_DEA_OFFSET,
+ DOLBY_PARAM_DED_OFFSET, DOLBY_PARAM_GEBG_OFFSET,
+ DOLBY_PARAM_AOCC_OFFSET, DOLBY_PARAM_ARBI_OFFSET,
+ DOLBY_PARAM_ARBL_OFFSET, DOLBY_PARAM_ARBH_OFFSET,
+ DOLBY_PARAM_AROD_OFFSET, DOLBY_PARAM_ARTP_OFFSET,
+ DOLBY_PARAM_VMON_OFFSET, DOLBY_PARAM_VMB_OFFSET,
+ DOLBY_PARAM_VCNB_OFFSET, DOLBY_PARAM_VCBF_OFFSET,
+ DOLBY_PARAM_PREG_OFFSET, DOLBY_PARAM_VEN_OFFSET,
+ DOLBY_PARAM_PSTG_OFFSET, DOLBY_PARAM_INT_ENDP_OFFSET,
+};
+/* param_length */
+static uint32_t ds2_dap_params_length[MAX_DS2_PARAMS] = {
+ DOLBY_PARAM_VDHE_LENGTH, DOLBY_PARAM_VSPE_LENGTH,
+ DOLBY_PARAM_DSSF_LENGTH, DOLBY_PARAM_DVLI_LENGTH,
+ DOLBY_PARAM_DVLO_LENGTH, DOLBY_PARAM_DVLE_LENGTH,
+ DOLBY_PARAM_DVMC_LENGTH, DOLBY_PARAM_DVME_LENGTH,
+ DOLBY_PARAM_IENB_LENGTH, DOLBY_PARAM_IEBF_LENGTH,
+ DOLBY_PARAM_IEON_LENGTH, DOLBY_PARAM_DEON_LENGTH,
+ DOLBY_PARAM_NGON_LENGTH, DOLBY_PARAM_GEON_LENGTH,
+ DOLBY_PARAM_GENB_LENGTH, DOLBY_PARAM_GEBF_LENGTH,
+ DOLBY_PARAM_AONB_LENGTH, DOLBY_PARAM_AOBF_LENGTH,
+ DOLBY_PARAM_AOBG_LENGTH, DOLBY_PARAM_AOON_LENGTH,
+ DOLBY_PARAM_ARNB_LENGTH, DOLBY_PARAM_ARBF_LENGTH,
+ DOLBY_PARAM_PLB_LENGTH, DOLBY_PARAM_PLMD_LENGTH,
+ DOLBY_PARAM_DHSB_LENGTH, DOLBY_PARAM_DHRG_LENGTH,
+ DOLBY_PARAM_DSSB_LENGTH, DOLBY_PARAM_DSSA_LENGTH,
+ DOLBY_PARAM_DVLA_LENGTH, DOLBY_PARAM_IEBT_LENGTH,
+ DOLBY_PARAM_IEA_LENGTH, DOLBY_PARAM_DEA_LENGTH,
+ DOLBY_PARAM_DED_LENGTH, DOLBY_PARAM_GEBG_LENGTH,
+ DOLBY_PARAM_AOCC_LENGTH, DOLBY_PARAM_ARBI_LENGTH,
+ DOLBY_PARAM_ARBL_LENGTH, DOLBY_PARAM_ARBH_LENGTH,
+ DOLBY_PARAM_AROD_LENGTH, DOLBY_PARAM_ARTP_LENGTH,
+ DOLBY_PARAM_VMON_LENGTH, DOLBY_PARAM_VMB_LENGTH,
+ DOLBY_PARAM_VCNB_LENGTH, DOLBY_PARAM_VCBF_LENGTH,
+ DOLBY_PARAM_PREG_LENGTH, DOLBY_PARAM_VEN_LENGTH,
+ DOLBY_PARAM_PSTG_LENGTH, DOLBY_PARAM_INT_ENDP_LENGTH,
+};
+
+struct ds2_dap_params_s {
+ int32_t params_val[TOTAL_LENGTH_DS2_PARAM];
+ int32_t dap_params_modified[MAX_DS2_PARAMS];
+};
+
+struct audio_rx_cal_data {
+ char aud_proc_data[AUD_PROC_BLOCK_SIZE];
+ int32_t aud_proc_size;
+ char aud_vol_data[AUD_VOL_BLOCK_SIZE];
+ int32_t aud_vol_size;
+};
+
+static struct ds2_dap_params_s ds2_dap_params[DOLBY_MAX_CACHE];
+
+struct ds2_device_mapping {
+ int32_t device_id; /* audio_out_... */
+ int port_id; /* afe port. constant for a target variant. routing-v2*/
+ /*Only one Dolby COPP for a specific port*/
+ int copp_idx; /* idx for the copp port on which ds2 is active */
+ int cache_dev; /* idx to a shared parameter array dependent on device*/
+ uint32_t stream_ref_count;
+ bool active;
+ void *cal_data;
+};
+
+static struct ds2_device_mapping dev_map[DS2_DEVICES_ALL];
+
+struct ds2_dap_params_states_s {
+ bool use_cache;
+ bool dap_bypass;
+ bool dap_bypass_type;
+ bool node_opened;
+ int32_t device;
+ bool custom_stereo_onoff;
+};
+
+static struct ds2_dap_params_states_s ds2_dap_params_states = {true, false,
+ false, DEVICE_NONE};
+
+static int all_supported_devices = EARPIECE|SPEAKER|WIRED_HEADSET|
+ WIRED_HEADPHONE|BLUETOOTH_SCO|AUX_DIGITAL|
+ ANLG_DOCK_HEADSET|DGTL_DOCK_HEADSET|
+ REMOTE_SUBMIX|ANC_HEADSET|ANC_HEADPHONE|
+ PROXY|FM|FM_TX|DEVICE_NONE|
+ BLUETOOTH_SCO_HEADSET|BLUETOOTH_SCO_CARKIT;
+
+
+static void msm_ds2_dap_check_and_update_ramp_wait(int port_id, int copp_idx,
+ int *ramp_wait)
+{
+
+ int32_t *update_params_value = NULL;
+ uint32_t params_length = SOFT_VOLUME_PARAM_SIZE * sizeof(uint32_t);
+ uint32_t param_payload_len = PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
+ int rc = 0;
+
+ update_params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!update_params_value)
+ goto end;
+
+ rc = adm_get_params(port_id, copp_idx,
+ AUDPROC_MODULE_ID_VOL_CTRL,
+ AUDPROC_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS,
+ params_length + param_payload_len,
+ (char *) update_params_value);
+ if (rc == 0) {
+ pr_debug("%s: params_value [0x%x, 0x%x, 0x%x]\n",
+ __func__, update_params_value[0],
+ update_params_value[1],
+ update_params_value[2]);
+ *ramp_wait = update_params_value[0];
+ }
+end:
+ kfree(update_params_value);
+ /*
+ * No error returned as we do not need to error out from dap on/dap
+ * bypass. The default ramp parameter will be used to wait during
+ * ramp down.
+ */
+}
+
+static int msm_ds2_dap_set_vspe_vdhe(int dev_map_idx,
+ bool is_custom_stereo_enabled)
+{
+ int32_t *update_params_value = NULL;
+ int32_t *param_val = NULL;
+ int idx, i, j, rc = 0, cdev;
+ uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
+ 2 * DOLBY_PARAM_PAYLOAD_SIZE) *
+ sizeof(uint32_t);
+
+ if (dev_map_idx < 0 || dev_map_idx >= DS2_DEVICES_ALL) {
+ pr_err("%s: invalid dev map index %d\n", __func__, dev_map_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (dev_map[dev_map_idx].port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s: Invalid port id\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if ((dev_map[dev_map_idx].copp_idx < 0) ||
+ (dev_map[dev_map_idx].copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: Invalid copp_idx\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if ((dev_map[dev_map_idx].port_id != SLIMBUS_0_RX) &&
+ (dev_map[dev_map_idx].port_id != RT_PROXY_PORT_001_RX)) {
+ pr_debug("%s:No Custom stereo for port:0x%x\n",
+ __func__, dev_map[dev_map_idx].port_id);
+ goto end;
+ }
+
+ update_params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!update_params_value) {
+ rc = -ENOMEM;
+ goto end;
+ }
+ params_length = 0;
+ param_val = update_params_value;
+ cdev = dev_map[dev_map_idx].cache_dev;
+ /* for VDHE and VSPE DAP params at index 0 and 1 in table */
+ for (i = 0; i < 2; i++) {
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ = ds2_dap_params_id[i];
+ *update_params_value++ = ds2_dap_params_length[i] *
+ sizeof(uint32_t);
+ idx = ds2_dap_params_offset[i];
+ for (j = 0; j < ds2_dap_params_length[i]; j++) {
+ if (is_custom_stereo_enabled)
+ *update_params_value++ = 0;
+ else
+ *update_params_value++ =
+ ds2_dap_params[cdev].params_val[idx+j];
+ }
+ params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
+ ds2_dap_params_length[i]) *
+ sizeof(uint32_t);
+ }
+
+ pr_debug("%s: valid param length: %d\n", __func__, params_length);
+ if (params_length) {
+ rc = adm_dolby_dap_send_params(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx,
+ (char *)param_val,
+ params_length);
+ if (rc) {
+ pr_err("%s: send vdhe/vspe params failed with rc=%d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+end:
+ kfree(param_val);
+ return rc;
+}
+
+int qti_set_custom_stereo_on(int port_id, int copp_idx,
+ bool is_custom_stereo_on)
+{
+
+ uint16_t op_FL_ip_FL_weight;
+ uint16_t op_FL_ip_FR_weight;
+ uint16_t op_FR_ip_FL_weight;
+ uint16_t op_FR_ip_FR_weight;
+
+ int32_t *update_params_value32 = NULL, rc = 0;
+ int32_t *param_val = NULL;
+ int16_t *update_params_value16 = 0;
+ uint32_t params_length_bytes = CUSTOM_STEREO_PAYLOAD_SIZE *
+ sizeof(uint32_t);
+ uint32_t avail_length = params_length_bytes;
+
+ if ((port_id != SLIMBUS_0_RX) &&
+ (port_id != RT_PROXY_PORT_001_RX)) {
+ pr_debug("%s:No Custom stereo for port:0x%x\n",
+ __func__, port_id);
+ goto skip_send_cmd;
+ }
+
+ pr_debug("%s: port 0x%x, copp_idx %d, is_custom_stereo_on %d\n",
+ __func__, port_id, copp_idx, is_custom_stereo_on);
+ if (is_custom_stereo_on) {
+ op_FL_ip_FL_weight =
+ Q14_GAIN_ZERO_POINT_FIVE;
+ op_FL_ip_FR_weight =
+ Q14_GAIN_ZERO_POINT_FIVE;
+ op_FR_ip_FL_weight =
+ Q14_GAIN_ZERO_POINT_FIVE;
+ op_FR_ip_FR_weight =
+ Q14_GAIN_ZERO_POINT_FIVE;
+ } else {
+ op_FL_ip_FL_weight = Q14_GAIN_UNITY;
+ op_FL_ip_FR_weight = 0;
+ op_FR_ip_FL_weight = 0;
+ op_FR_ip_FR_weight = Q14_GAIN_UNITY;
+ }
+
+ update_params_value32 = kzalloc(params_length_bytes, GFP_KERNEL);
+ if (!update_params_value32) {
+ rc = -ENOMEM;
+ goto skip_send_cmd;
+ }
+ param_val = update_params_value32;
+ if (avail_length < 2 * sizeof(uint32_t))
+ goto skip_send_cmd;
+ *update_params_value32++ = MTMX_MODULE_ID_DEFAULT_CHMIXER;
+ *update_params_value32++ = DEFAULT_CHMIXER_PARAM_ID_COEFF;
+ avail_length = avail_length - (2 * sizeof(uint32_t));
+
+ update_params_value16 = (int16_t *)update_params_value32;
+ if (avail_length < 10 * sizeof(uint16_t))
+ goto skip_send_cmd;
+ *update_params_value16++ = CUSTOM_STEREO_CMD_PARAM_SIZE;
+ /* for alignment only*/
+ *update_params_value16++ = 0;
+ /* index is 32-bit param in little endian*/
+ *update_params_value16++ = CUSTOM_STEREO_INDEX_PARAM;
+ *update_params_value16++ = 0;
+ /* for stereo mixing num out ch*/
+ *update_params_value16++ = CUSTOM_STEREO_NUM_OUT_CH;
+ /* for stereo mixing num in ch*/
+ *update_params_value16++ = CUSTOM_STEREO_NUM_IN_CH;
+
+ /* Out ch map FL/FR*/
+ *update_params_value16++ = PCM_CHANNEL_FL;
+ *update_params_value16++ = PCM_CHANNEL_FR;
+
+ /* In ch map FL/FR*/
+ *update_params_value16++ = PCM_CHANNEL_FL;
+ *update_params_value16++ = PCM_CHANNEL_FR;
+ avail_length = avail_length - (10 * sizeof(uint16_t));
+ /* weighting coefficients as name suggests,
+ * mixing will be done according to these coefficients
+ */
+ if (avail_length < 4 * sizeof(uint16_t))
+ goto skip_send_cmd;
+ *update_params_value16++ = op_FL_ip_FL_weight;
+ *update_params_value16++ = op_FL_ip_FR_weight;
+ *update_params_value16++ = op_FR_ip_FL_weight;
+ *update_params_value16++ = op_FR_ip_FR_weight;
+ avail_length = avail_length - (4 * sizeof(uint16_t));
+ if (params_length_bytes != 0) {
+ rc = adm_dolby_dap_send_params(port_id, copp_idx,
+ (char *)param_val,
+ params_length_bytes);
+ if (rc) {
+ pr_err("%s: send params failed rc=%d\n", __func__, rc);
+ rc = -EINVAL;
+ goto skip_send_cmd;
+ }
+ }
+ kfree(param_val);
+ return 0;
+skip_send_cmd:
+ pr_err("%s: insufficient memory, send cmd failed\n",
+ __func__);
+ kfree(param_val);
+ return rc;
+}
+static int dap_set_custom_stereo_onoff(int dev_map_idx,
+ bool is_custom_stereo_enabled)
+{
+
+ int32_t *update_params_value = NULL, rc = 0;
+ int32_t *param_val = NULL;
+ uint32_t params_length_bytes = (TOTAL_LENGTH_DOLBY_PARAM +
+ DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t);
+ if ((dev_map[dev_map_idx].port_id != SLIMBUS_0_RX) &&
+ (dev_map[dev_map_idx].port_id != RT_PROXY_PORT_001_RX)) {
+ pr_debug("%s:No Custom stereo for port:0x%x\n",
+ __func__, dev_map[dev_map_idx].port_id);
+ goto end;
+ }
+
+ if ((dev_map[dev_map_idx].copp_idx < 0) ||
+ (dev_map[dev_map_idx].copp_idx >= MAX_COPPS_PER_PORT)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* DAP custom stereo */
+ msm_ds2_dap_set_vspe_vdhe(dev_map_idx,
+ is_custom_stereo_enabled);
+ update_params_value = kzalloc(params_length_bytes, GFP_KERNEL);
+ if (!update_params_value) {
+ pr_err("%s: params memory alloc failed\n", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+ params_length_bytes = 0;
+ param_val = update_params_value;
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ = DOLBY_ENABLE_CUSTOM_STEREO;
+ *update_params_value++ = sizeof(uint32_t);
+ if (is_custom_stereo_enabled)
+ *update_params_value++ = 1;
+ else
+ *update_params_value++ = 0;
+ params_length_bytes += (DOLBY_PARAM_PAYLOAD_SIZE + 1) *
+ sizeof(uint32_t);
+ pr_debug("%s: valid param length: %d\n", __func__, params_length_bytes);
+ if (params_length_bytes) {
+ rc = adm_dolby_dap_send_params(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx,
+ (char *)param_val,
+ params_length_bytes);
+ if (rc) {
+ pr_err("%s: custom stereo param failed with rc=%d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+end:
+ kfree(param_val);
+ return rc;
+
+}
+
+
+static int set_custom_stereo_onoff(int dev_map_idx,
+ bool is_custom_stereo_enabled)
+{
+ int rc = 0;
+
+ pr_debug("%s: map index %d, custom stereo %d\n", __func__, dev_map_idx,
+ is_custom_stereo_enabled);
+
+ if (dev_map_idx < 0 || dev_map_idx >= DS2_DEVICES_ALL) {
+ pr_err("%s: invalid dev map index %d\n", __func__, dev_map_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (dev_map[dev_map_idx].port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s: invalid port id\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if ((dev_map[dev_map_idx].copp_idx < 0) ||
+ (dev_map[dev_map_idx].copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: invalid copp idx\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (ds2_dap_params_states.dap_bypass == true &&
+ ds2_dap_params_states.dap_bypass_type == DAP_HARD_BYPASS) {
+
+ rc = qti_set_custom_stereo_on(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx,
+ is_custom_stereo_enabled);
+ if (rc < 0) {
+ pr_err("%s:qti_set_custom_stereo_on_copp failed C.S %d",
+ __func__, is_custom_stereo_enabled);
+ }
+ goto end;
+
+ }
+
+ if (ds2_dap_params_states.dap_bypass == false) {
+ rc = dap_set_custom_stereo_onoff(dev_map_idx,
+ is_custom_stereo_enabled);
+ if (rc < 0) {
+ pr_err("%s:qti_set_custom_stereo_on_copp failed C.S %d",
+ __func__, is_custom_stereo_enabled);
+ }
+ goto end;
+ }
+end:
+ return rc;
+}
+
+static int msm_ds2_dap_alloc_and_store_cal_data(int dev_map_idx, int path,
+ int perf_mode)
+{
+ int rc = 0;
+ struct audio_rx_cal_data *aud_cal_data;
+
+ pr_debug("%s: path %d, perf_mode %d, dev_map_idx %d\n",
+ __func__, path, perf_mode, dev_map_idx);
+
+ if (dev_map_idx < 0 || dev_map_idx >= DS2_DEVICES_ALL) {
+ pr_err("%s: invalid dev map index %d\n", __func__, dev_map_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ aud_cal_data = kzalloc(sizeof(struct audio_rx_cal_data), GFP_KERNEL);
+ if (!aud_cal_data) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ rc = adm_store_cal_data(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx, path, perf_mode,
+ ADM_AUDPROC_CAL, aud_cal_data->aud_proc_data,
+ &aud_cal_data->aud_proc_size);
+ if (rc < 0) {
+ pr_err("%s: store cal data err %d\n", __func__, rc);
+ kfree(aud_cal_data);
+ goto end;
+ }
+
+ rc = adm_store_cal_data(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx, path, perf_mode,
+ ADM_AUDVOL_CAL, aud_cal_data->aud_vol_data,
+ &aud_cal_data->aud_vol_size);
+ if (rc < 0) {
+ pr_err("%s: store cal data err %d\n", __func__, rc);
+ kfree(aud_cal_data);
+ goto end;
+ }
+
+ dev_map[dev_map_idx].cal_data = (void *)aud_cal_data;
+
+end:
+ pr_debug("%s: ret %d\n", __func__, rc);
+ return rc;
+}
+
+static int msm_ds2_dap_free_cal_data(int dev_map_idx)
+{
+ int rc = 0;
+ struct audio_rx_cal_data *aud_cal_data;
+
+ pr_debug("%s: dev_map_idx %d\n", __func__, dev_map_idx);
+ if (dev_map_idx < 0 || dev_map_idx >= DS2_DEVICES_ALL) {
+ pr_err("%s: invalid dev map index %d\n", __func__, dev_map_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+ aud_cal_data = (struct audio_rx_cal_data *)
+ dev_map[dev_map_idx].cal_data;
+ kfree(aud_cal_data);
+ dev_map[dev_map_idx].cal_data = NULL;
+
+end:
+ return rc;
+}
+
+static int msm_ds2_dap_send_cal_data(int dev_map_idx)
+{
+ int rc = 0;
+ struct audio_rx_cal_data *aud_cal_data = NULL;
+
+ pr_debug("%s: devmap index %d\n", __func__, dev_map_idx);
+ if (dev_map_idx < 0 || dev_map_idx >= DS2_DEVICES_ALL) {
+ pr_err("%s: invalid dev map index %d\n", __func__, dev_map_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (dev_map[dev_map_idx].cal_data == NULL) {
+ pr_err("%s: No valid calibration data stored for idx %d\n",
+ __func__, dev_map_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* send aud proc cal */
+ aud_cal_data = (struct audio_rx_cal_data *)
+ dev_map[dev_map_idx].cal_data;
+ rc = adm_send_calibration(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx,
+ ADM_PATH_PLAYBACK, 0,
+ ADM_AUDPROC_CAL,
+ aud_cal_data->aud_proc_data,
+ aud_cal_data->aud_proc_size);
+ if (rc < 0) {
+ pr_err("%s: adm_send_calibration failed %d\n", __func__, rc);
+ goto end;
+ }
+
+ /* send aud volume cal*/
+ rc = adm_send_calibration(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx,
+ ADM_PATH_PLAYBACK, 0,
+ ADM_AUDVOL_CAL,
+ aud_cal_data->aud_vol_data,
+ aud_cal_data->aud_vol_size);
+ if (rc < 0)
+ pr_err("%s: adm_send_calibration failed %d\n", __func__, rc);
+end:
+ pr_debug("%s: return %d\n", __func__, rc);
+ return rc;
+}
+
+static inline int msm_ds2_dap_can_enable_module(int32_t module_id)
+{
+ if (module_id == MTMX_MODULE_ID_DEFAULT_CHMIXER ||
+ module_id == AUDPROC_MODULE_ID_RESAMPLER ||
+ module_id == AUDPROC_MODULE_ID_VOL_CTRL) {
+ return false;
+ }
+ return true;
+}
+
+static int msm_ds2_dap_init_modules_in_topology(int dev_map_idx)
+{
+ int rc = 0, i = 0, port_id, copp_idx;
+ /* Account for 32 bit integer allocation */
+ int32_t param_sz = (ADM_GET_TOPO_MODULE_LIST_LENGTH / sizeof(uint32_t));
+ int32_t *update_param_val = NULL;
+
+ if (dev_map_idx < 0 || dev_map_idx >= DS2_DEVICES_ALL) {
+ pr_err("%s: invalid dev map index %d\n", __func__, dev_map_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ port_id = dev_map[dev_map_idx].port_id;
+ copp_idx = dev_map[dev_map_idx].copp_idx;
+ pr_debug("%s: port_id 0x%x copp_idx %d\n", __func__, port_id, copp_idx);
+ update_param_val = kzalloc(ADM_GET_TOPO_MODULE_LIST_LENGTH, GFP_KERNEL);
+ if (!update_param_val) {
+ pr_err("%s, param memory alloc failed\n", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ if (!ds2_dap_params_states.dap_bypass) {
+ /* get modules from dsp */
+ rc = adm_get_pp_topo_module_list(port_id, copp_idx,
+ ADM_GET_TOPO_MODULE_LIST_LENGTH,
+ (char *)update_param_val);
+ if (rc < 0) {
+ pr_err("%s:topo list port %d, err %d,copp_idx %d\n",
+ __func__, port_id, copp_idx, rc);
+ goto end;
+ }
+
+ if (update_param_val[0] > (param_sz - 1)) {
+ pr_err("%s:max modules exp/ret [%d: %d]\n",
+ __func__, (param_sz - 1),
+ update_param_val[0]);
+ rc = -EINVAL;
+ goto end;
+ }
+ /* Turn off modules */
+ for (i = 1; i < update_param_val[0]; i++) {
+ if (!msm_ds2_dap_can_enable_module(
+ update_param_val[i]) ||
+ (update_param_val[i] == DS2_MODULE_ID)) {
+ pr_debug("%s: Do not enable/disable %d\n",
+ __func__, update_param_val[i]);
+ continue;
+ }
+
+ pr_debug("%s: param disable %d\n",
+ __func__, update_param_val[i]);
+ adm_param_enable(port_id, copp_idx, update_param_val[i],
+ MODULE_DISABLE);
+ }
+ } else {
+ msm_ds2_dap_send_cal_data(dev_map_idx);
+
+ }
+ adm_param_enable(port_id, copp_idx, DS2_MODULE_ID,
+ !ds2_dap_params_states.dap_bypass);
+end:
+ kfree(update_param_val);
+ return rc;
+}
+
+static bool msm_ds2_dap_check_is_param_modified(int32_t *dap_params_modified,
+ int32_t idx, int32_t commit)
+{
+ if ((dap_params_modified[idx] == 0) ||
+ (commit &&
+ ((dap_params_modified[idx] & 0x00010000) &&
+ ((dap_params_modified[idx] & 0x0000FFFF) <= 1)))) {
+ pr_debug("%s: not modified at idx %d\n", __func__, idx);
+ return false;
+ }
+ pr_debug("%s: modified at idx %d\n", __func__, idx);
+ return true;
+}
+
+static int msm_ds2_dap_map_device_to_dolby_cache_devices(int32_t device_id)
+{
+ int32_t cache_dev = -1;
+
+ switch (device_id) {
+ case DEVICE_NONE:
+ cache_dev = DOLBY_OFF_CACHE;
+ break;
+ case EARPIECE:
+ case SPEAKER:
+ cache_dev = DOLBY_SPEAKER_CACHE;
+ break;
+ case WIRED_HEADSET:
+ case WIRED_HEADPHONE:
+ case ANLG_DOCK_HEADSET:
+ case DGTL_DOCK_HEADSET:
+ case ANC_HEADSET:
+ case ANC_HEADPHONE:
+ case BLUETOOTH_SCO:
+ case BLUETOOTH_SCO_HEADSET:
+ case BLUETOOTH_SCO_CARKIT:
+ cache_dev = DOLBY_HEADPHONE_CACHE;
+ break;
+ case FM:
+ case FM_TX:
+ cache_dev = DOLBY_FM_CACHE;
+ break;
+ case AUX_DIGITAL:
+ cache_dev = DOLBY_HDMI_CACHE;
+ break;
+ case PROXY:
+ case REMOTE_SUBMIX:
+ cache_dev = DOLBY_WFD_CACHE;
+ break;
+ default:
+ pr_err("%s: invalid cache device\n", __func__);
+ }
+ pr_debug("%s: cache device %d\n", __func__, cache_dev);
+ return cache_dev;
+}
+
+static int msm_ds2_dap_update_num_devices(struct dolby_param_data *dolby_data,
+ int32_t *num_device, int32_t *dev_arr,
+ int32_t array_size)
+{
+ int32_t idx = 0;
+ int supported_devices = 0;
+
+ if (!array_size) {
+ pr_err("%s: array size zero\n", __func__);
+ return -EINVAL;
+ }
+
+ if (dolby_data->device_id == DEVICE_OUT_ALL ||
+ dolby_data->device_id == DEVICE_OUT_DEFAULT)
+ supported_devices = all_supported_devices;
+ else
+ supported_devices = dolby_data->device_id;
+
+ if ((idx < array_size) && (supported_devices & EARPIECE))
+ dev_arr[idx++] = EARPIECE;
+ if ((idx < array_size) && (supported_devices & SPEAKER))
+ dev_arr[idx++] = SPEAKER;
+ if ((idx < array_size) && (supported_devices & WIRED_HEADSET))
+ dev_arr[idx++] = WIRED_HEADSET;
+ if ((idx < array_size) && (supported_devices & WIRED_HEADPHONE))
+ dev_arr[idx++] = WIRED_HEADPHONE;
+ if ((idx < array_size) && (supported_devices & BLUETOOTH_SCO))
+ dev_arr[idx++] = BLUETOOTH_SCO;
+ if ((idx < array_size) && (supported_devices & BLUETOOTH_SCO_CARKIT))
+ dev_arr[idx++] = BLUETOOTH_SCO_CARKIT;
+ if ((idx < array_size) && (supported_devices & BLUETOOTH_SCO_HEADSET))
+ dev_arr[idx++] = BLUETOOTH_SCO_HEADSET;
+ if ((idx < array_size) && (supported_devices & AUX_DIGITAL))
+ dev_arr[idx++] = AUX_DIGITAL;
+ if ((idx < array_size) && (supported_devices & ANLG_DOCK_HEADSET))
+ dev_arr[idx++] = ANLG_DOCK_HEADSET;
+ if ((idx < array_size) && (supported_devices & DGTL_DOCK_HEADSET))
+ dev_arr[idx++] = DGTL_DOCK_HEADSET;
+ if ((idx < array_size) && (supported_devices & REMOTE_SUBMIX))
+ dev_arr[idx++] = REMOTE_SUBMIX;
+ if ((idx < array_size) && (supported_devices & ANC_HEADSET))
+ dev_arr[idx++] = ANC_HEADSET;
+ if ((idx < array_size) && (supported_devices & ANC_HEADPHONE))
+ dev_arr[idx++] = ANC_HEADPHONE;
+ if ((idx < array_size) && (supported_devices & PROXY))
+ dev_arr[idx++] = PROXY;
+ if ((idx < array_size) && (supported_devices & FM))
+ dev_arr[idx++] = FM;
+ if ((idx < array_size) && (supported_devices & FM_TX))
+ dev_arr[idx++] = FM_TX;
+ /* CHECK device none separately */
+ if ((idx < array_size) && (supported_devices == DEVICE_NONE))
+ dev_arr[idx++] = DEVICE_NONE;
+ pr_debug("%s: dev id 0x%x, idx %d\n", __func__,
+ supported_devices, idx);
+ *num_device = idx;
+ return 0;
+}
+
+static int msm_ds2_dap_get_port_id(
+ int32_t device_id, int32_t be_id)
+{
+ struct msm_pcm_routing_bdai_data bedais;
+ int port_id = DOLBY_INVALID_PORT_ID;
+ int port_type = 0;
+
+ if (be_id < 0) {
+ port_id = -1;
+ goto end;
+ }
+
+ msm_pcm_routing_get_bedai_info(be_id, &bedais);
+ pr_debug("%s: be port_id %d\n", __func__, bedais.port_id);
+ port_id = bedais.port_id;
+ port_type = afe_get_port_type(bedais.port_id);
+ if (port_type != MSM_AFE_PORT_TYPE_RX)
+ port_id = DOLBY_INVALID_PORT_ID;
+end:
+ pr_debug("%s: device_id 0x%x, be_id %d, port_id %d\n",
+ __func__, device_id, be_id, port_id);
+ return port_id;
+}
+
+static int msm_ds2_dap_update_dev_map_port_id(int32_t device_id, int port_id)
+{
+ int i;
+
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ if (dev_map[i].device_id == device_id)
+ dev_map[i].port_id = port_id;
+ }
+ pr_debug("%s: port_id %d, device_id 0x%x\n",
+ __func__, port_id, device_id);
+ return 0;
+}
+
+static int msm_ds2_dap_handle_bypass_wait(int port_id, int copp_idx,
+ int wait_time)
+{
+ int ret = 0;
+
+ adm_set_wait_parameters(port_id, copp_idx);
+ msm_pcm_routing_release_lock();
+ ret = adm_wait_timeout(port_id, copp_idx, wait_time);
+ msm_pcm_routing_acquire_lock();
+ /* Reset the parameters if wait has timed out */
+ if (ret == 0)
+ adm_reset_wait_parameters(port_id, copp_idx);
+ return ret;
+}
+
+static int msm_ds2_dap_handle_bypass(struct dolby_param_data *dolby_data)
+{
+ int rc = 0, i = 0, j = 0;
+ /*Account for 32 bit integer allocation */
+ int32_t param_sz = (ADM_GET_TOPO_MODULE_LIST_LENGTH / sizeof(uint32_t));
+ int32_t *mod_list = NULL;
+ int port_id = 0, copp_idx = -1;
+ bool cs_onoff = ds2_dap_params_states.custom_stereo_onoff;
+ int ramp_wait = DOLBY_SOFT_VOLUME_PERIOD;
+
+ pr_debug("%s: bypass type %d bypass %d custom stereo %d\n", __func__,
+ ds2_dap_params_states.dap_bypass_type,
+ ds2_dap_params_states.dap_bypass,
+ ds2_dap_params_states.custom_stereo_onoff);
+ mod_list = kzalloc(ADM_GET_TOPO_MODULE_LIST_LENGTH, GFP_KERNEL);
+ if (!mod_list) {
+ pr_err("%s: param memory alloc failed\n", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ pr_debug("%s: active dev %d\n", __func__, dev_map[i].active);
+ if (dev_map[i].active) {
+ port_id = dev_map[i].port_id;
+ copp_idx = dev_map[i].copp_idx;
+
+ if (port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s: invalid port\n", __func__);
+ rc = 0;
+ goto end;
+ }
+
+ if ((copp_idx < 0) ||
+ (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: Invalid copp_idx\n", __func__);
+ rc = 0;
+ goto end;
+ }
+
+ /* getmodules from dsp */
+ rc = adm_get_pp_topo_module_list(port_id, copp_idx,
+ ADM_GET_TOPO_MODULE_LIST_LENGTH,
+ (char *)mod_list);
+ if (rc < 0) {
+ pr_err("%s:adm get topo list port %d",
+ __func__, port_id);
+ pr_err("copp_idx %d, err %d\n",
+ copp_idx, rc);
+ goto end;
+ }
+ if (mod_list[0] > (param_sz - 1)) {
+ pr_err("%s:max modules exp/ret [%d: %d]\n",
+ __func__, (param_sz - 1),
+ mod_list[0]);
+ rc = -EINVAL;
+ goto end;
+ }
+ /*
+ * get ramp parameters
+ * check for change in ramp parameters
+ * update ramp wait
+ */
+ msm_ds2_dap_check_and_update_ramp_wait(port_id,
+ copp_idx,
+ &ramp_wait);
+
+ /* Mute before switching modules */
+ rc = adm_set_volume(port_id, copp_idx,
+ VOLUME_ZERO_GAIN);
+ if (rc < 0) {
+ /*
+ * Not Fatal can continue bypass operations.
+ * Do not need to block playback
+ */
+ pr_info("%s :Set volume port_id %d",
+ __func__, port_id);
+ pr_info("copp_idx %d, error %d\n",
+ copp_idx, rc);
+ }
+
+ rc = msm_ds2_dap_handle_bypass_wait(port_id, copp_idx,
+ (ramp_wait +
+ DOLBY_ADDITIONAL_RAMP_WAIT));
+ if (rc == -EINTR) {
+ pr_info("%s:bypass interrupted-ignore,port %d",
+ __func__, port_id);
+ pr_info("copp_idx %d\n", copp_idx);
+ rc = 0;
+ continue;
+ }
+
+ /* if dap bypass is set */
+ if (ds2_dap_params_states.dap_bypass) {
+ /* Turn off dap module */
+ adm_param_enable(port_id, copp_idx,
+ DS2_MODULE_ID, MODULE_DISABLE);
+ /*
+ * If custom stereo is on at the time of bypass,
+ * switch off custom stereo on dap and turn on
+ * custom stereo on qti channel mixer.
+ */
+ if (cs_onoff) {
+ rc = dap_set_custom_stereo_onoff(i,
+ !cs_onoff);
+ if (rc < 0) {
+ pr_info("%s:D_CS i %d,rc %d\n",
+ __func__, i, rc);
+ }
+ rc = qti_set_custom_stereo_on(port_id,
+ copp_idx,
+ cs_onoff);
+ if (rc < 0) {
+ pr_info("%s:Q_CS port id 0x%x",
+ __func__, port_id);
+ pr_info("copp idx %d, rc %d\n",
+ copp_idx, rc);
+ }
+ }
+ /* Add adm api to resend calibration on port */
+ rc = msm_ds2_dap_send_cal_data(i);
+ if (rc < 0) {
+ /*
+ * Not fatal,continue bypass operations.
+ * Do not need to block playback
+ */
+ pr_info("%s:send cal err %d index %d\n",
+ __func__, rc, i);
+ }
+ } else {
+ /* Turn off qti modules */
+ for (j = 1; j < mod_list[0]; j++) {
+ if (!msm_ds2_dap_can_enable_module(
+ mod_list[j]) ||
+ mod_list[j] ==
+ DS2_MODULE_ID)
+ continue;
+ pr_debug("%s: param disable %d\n",
+ __func__, mod_list[j]);
+ adm_param_enable(port_id, copp_idx,
+ mod_list[j],
+ MODULE_DISABLE);
+ }
+
+ /* Enable DAP modules */
+ pr_debug("%s:DS2 param enable\n", __func__);
+ adm_param_enable(port_id, copp_idx,
+ DS2_MODULE_ID, MODULE_ENABLE);
+ /*
+ * If custom stereo is on at the time of dap on,
+ * switch off custom stereo on qti channel mixer
+ * and turn on custom stereo on DAP.
+ * mixer(qti).
+ */
+ if (cs_onoff) {
+ rc = qti_set_custom_stereo_on(port_id,
+ copp_idx,
+ !cs_onoff);
+ if (rc < 0) {
+ pr_info("%s:Q_CS port_id 0x%x",
+ __func__, port_id);
+ pr_info("copp_idx %d rc %d\n",
+ copp_idx, rc);
+ }
+ rc = dap_set_custom_stereo_onoff(i,
+ cs_onoff);
+ if (rc < 0) {
+ pr_info("%s:D_CS i %d,rc %d\n",
+ __func__, i, rc);
+ }
+ }
+ }
+
+ rc = msm_ds2_dap_handle_bypass_wait(port_id, copp_idx,
+ DOLBY_MODULE_ENABLE_PERIOD);
+ if (rc == -EINTR) {
+ pr_info("%s:bypass interrupted port_id %d copp_idx %d\n",
+ __func__, port_id, copp_idx);
+ /* Interrupted ignore bypass */
+ rc = 0;
+ continue;
+ }
+
+ /* set volume to unity gain after module on/off */
+ rc = adm_set_volume(port_id, copp_idx,
+ VOLUME_UNITY_GAIN);
+ if (rc < 0) {
+ /*
+ * Not Fatal can continue bypass operations.
+ * Do not need to block playback
+ */
+ pr_info("%s: Set vol port %d copp %d, rc %d\n",
+ __func__, port_id, copp_idx, rc);
+ rc = 0;
+ }
+ }
+ }
+
+end:
+ kfree(mod_list);
+ pr_debug("%s:return rc=%d\n", __func__, rc);
+ return rc;
+}
+
+static int msm_ds2_dap_send_end_point(int dev_map_idx, int endp_idx)
+{
+ int rc = 0;
+ int32_t *update_params_value = NULL, *params_value = NULL;
+ uint32_t params_length = (DOLBY_PARAM_INT_ENDP_LENGTH +
+ DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t);
+ int cache_device = 0;
+ struct ds2_dap_params_s *ds2_ap_params_obj = NULL;
+ int32_t *modified_param = NULL;
+
+ if (dev_map_idx < 0 || dev_map_idx >= DS2_DEVICES_ALL) {
+ pr_err("%s: invalid dev map index %d\n", __func__, dev_map_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+ cache_device = dev_map[dev_map_idx].cache_dev;
+
+ ds2_ap_params_obj = &ds2_dap_params[cache_device];
+ pr_debug("%s: cache dev %d, dev_map_idx %d\n", __func__,
+ cache_device, dev_map_idx);
+ pr_debug("%s: endp - %pK %pK\n", __func__,
+ &ds2_dap_params[cache_device], ds2_ap_params_obj);
+
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ if (dev_map[dev_map_idx].port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s: invalid port\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if ((dev_map[dev_map_idx].copp_idx < 0) ||
+ (dev_map[dev_map_idx].copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: Invalid copp_idx\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ update_params_value = params_value;
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ = DOLBY_PARAM_ID_INIT_ENDP;
+ *update_params_value++ = DOLBY_PARAM_INT_ENDP_LENGTH * sizeof(uint32_t);
+ *update_params_value++ = ds2_ap_params_obj->params_val[
+ ds2_dap_params_offset[endp_idx]];
+ pr_debug("%s: off %d, length %d\n", __func__,
+ ds2_dap_params_offset[endp_idx],
+ ds2_dap_params_length[endp_idx]);
+ pr_debug("%s: param 0x%x, param val %d\n", __func__,
+ ds2_dap_params_id[endp_idx], ds2_ap_params_obj->
+ params_val[ds2_dap_params_offset[endp_idx]]);
+ rc = adm_dolby_dap_send_params(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx,
+ (char *)params_value, params_length);
+ if (rc) {
+ pr_err("%s: send dolby params failed rc %d\n", __func__, rc);
+ rc = -EINVAL;
+ }
+ modified_param = ds2_ap_params_obj->dap_params_modified;
+ if (modified_param == NULL) {
+ pr_err("%s: modified param structure invalid\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (msm_ds2_dap_check_is_param_modified(modified_param, endp_idx, 0))
+ ds2_ap_params_obj->dap_params_modified[endp_idx] = 0x00010001;
+
+end:
+ kfree(params_value);
+ return rc;
+}
+
+static int msm_ds2_dap_send_cached_params(int dev_map_idx,
+ int commit)
+{
+ int32_t *update_params_value = NULL, *params_value = NULL;
+ uint32_t idx, i, j, ret = 0;
+ uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
+ (MAX_DS2_PARAMS - 1) *
+ DOLBY_PARAM_PAYLOAD_SIZE) *
+ sizeof(uint32_t);
+ int cache_device = 0;
+ struct ds2_dap_params_s *ds2_ap_params_obj = NULL;
+ int32_t *modified_param = NULL;
+
+ if (dev_map_idx < 0 || dev_map_idx >= DS2_DEVICES_ALL) {
+ pr_err("%s: invalid dev map index %d\n", __func__, dev_map_idx);
+ ret = -EINVAL;
+ goto end;
+ }
+ cache_device = dev_map[dev_map_idx].cache_dev;
+
+ /* Use off profile cache in only for soft bypass */
+ if (ds2_dap_params_states.dap_bypass_type == DAP_SOFT_BYPASS &&
+ ds2_dap_params_states.dap_bypass == true) {
+ pr_debug("%s: use bypass cache 0\n", __func__);
+ cache_device = dev_map[0].cache_dev;
+ }
+
+ ds2_ap_params_obj = &ds2_dap_params[cache_device];
+ pr_debug("%s: cached param - %pK %pK, cache_device %d\n", __func__,
+ &ds2_dap_params[cache_device], ds2_ap_params_obj,
+ cache_device);
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value) {
+ pr_err("%s: params memory alloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ if (dev_map[dev_map_idx].port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s: invalid port id\n", __func__);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if ((dev_map[dev_map_idx].copp_idx < 0) ||
+ (dev_map[dev_map_idx].copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: Invalid copp_idx\n", __func__);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ update_params_value = params_value;
+ params_length = 0;
+ for (i = 0; i < (MAX_DS2_PARAMS-1); i++) {
+ /*get the pointer to the param modified array in the cache*/
+ modified_param = ds2_ap_params_obj->dap_params_modified;
+ if (modified_param == NULL) {
+ pr_err("%s: modified param structure invalid\n",
+ __func__);
+ ret = -EINVAL;
+ goto end;
+ }
+ if (!msm_ds2_dap_check_is_param_modified(modified_param, i,
+ commit))
+ continue;
+ *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
+ *update_params_value++ = ds2_dap_params_id[i];
+ *update_params_value++ = ds2_dap_params_length[i] *
+ sizeof(uint32_t);
+ idx = ds2_dap_params_offset[i];
+ for (j = 0; j < ds2_dap_params_length[i]; j++) {
+ *update_params_value++ =
+ ds2_ap_params_obj->params_val[idx+j];
+ pr_debug("%s: id 0x%x,val %d\n", __func__,
+ ds2_dap_params_id[i],
+ ds2_ap_params_obj->params_val[idx+j]);
+ }
+ params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
+ ds2_dap_params_length[i]) * sizeof(uint32_t);
+ }
+
+ pr_debug("%s: valid param length: %d\n", __func__, params_length);
+ if (params_length) {
+ ret = adm_dolby_dap_send_params(dev_map[dev_map_idx].port_id,
+ dev_map[dev_map_idx].copp_idx,
+ (char *)params_value,
+ params_length);
+ if (ret) {
+ pr_err("%s: send dolby params failed ret %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto end;
+ }
+ for (i = 0; i < MAX_DS2_PARAMS-1; i++) {
+ /*get pointer to the param modified array in the cache*/
+ modified_param = ds2_ap_params_obj->dap_params_modified;
+ if (modified_param == NULL) {
+ pr_err("%s: modified param struct invalid\n",
+ __func__);
+ ret = -EINVAL;
+ goto end;
+ }
+ if (!msm_ds2_dap_check_is_param_modified(
+ modified_param, i, commit))
+ continue;
+ ds2_ap_params_obj->dap_params_modified[i] = 0x00010001;
+ }
+ }
+end:
+ kfree(params_value);
+ return ret;
+}
+
+static int msm_ds2_dap_commit_params(struct dolby_param_data *dolby_data,
+ int commit)
+{
+ int ret = 0, i, idx;
+ struct ds2_dap_params_s *ds2_ap_params_obj = NULL;
+ int32_t *modified_param = NULL;
+
+ /* Do not commit params if in hard bypass */
+ if (ds2_dap_params_states.dap_bypass_type == DAP_HARD_BYPASS &&
+ ds2_dap_params_states.dap_bypass == true) {
+ pr_debug("%s: called in bypass", __func__);
+ ret = -EINVAL;
+ goto end;
+ }
+ for (idx = 0; idx < MAX_DS2_PARAMS; idx++) {
+ if (ds2_dap_params_id[idx] == DOLBY_PARAM_ID_INIT_ENDP)
+ break;
+ }
+ if (idx >= MAX_DS2_PARAMS || idx < 0) {
+ pr_err("%s: index of DS2 Param not found idx %d\n",
+ __func__, idx);
+ ret = -EINVAL;
+ goto end;
+ }
+ pr_debug("%s: found endp - idx %d 0x%x\n", __func__, idx,
+ ds2_dap_params_id[idx]);
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ pr_debug("%s:dev[0x%x,0x%x],i:%d,active:%d,bypass:%d,type:%d\n",
+ __func__, dolby_data->device_id, dev_map[i].device_id,
+ i, dev_map[i].active, ds2_dap_params_states.dap_bypass,
+ ds2_dap_params_states.dap_bypass_type);
+
+ if (((dev_map[i].device_id & ds2_dap_params_states.device) ||
+ ((ds2_dap_params_states.dap_bypass_type ==
+ DAP_SOFT_BYPASS) &&
+ (ds2_dap_params_states.dap_bypass == true))) &&
+ (dev_map[i].active == true)) {
+
+ /*get ptr to the cache storing the params for device*/
+ if ((ds2_dap_params_states.dap_bypass_type ==
+ DAP_SOFT_BYPASS) &&
+ (ds2_dap_params_states.dap_bypass == true))
+ ds2_ap_params_obj =
+ &ds2_dap_params[dev_map[0].cache_dev];
+ else
+ ds2_ap_params_obj =
+ &ds2_dap_params[dev_map[i].cache_dev];
+
+ /*get the pointer to the param modified array in cache*/
+ modified_param = ds2_ap_params_obj->dap_params_modified;
+ if (modified_param == NULL) {
+ pr_err("%s: modified_param NULL\n", __func__);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ /*
+ * Send the endp param if use cache is set
+ * or if param is modified
+ */
+ if (!commit || msm_ds2_dap_check_is_param_modified(
+ modified_param, idx, commit)) {
+ msm_ds2_dap_send_end_point(i, idx);
+ commit = 0;
+ }
+ ret = msm_ds2_dap_send_cached_params(i, commit);
+ if (ret < 0) {
+ pr_err("%s: send cached param %d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+ }
+end:
+ return ret;
+}
+
+static int msm_ds2_dap_handle_commands(u32 cmd, void *arg)
+{
+ int ret = 0, port_id = 0;
+ int32_t data;
+ struct dolby_param_data *dolby_data = (struct dolby_param_data *)arg;
+
+ if (get_user(data, &dolby_data->data[0])) {
+ pr_debug("%s error getting data\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+
+ pr_debug("%s: param_id %d,be_id %d,device_id 0x%x,length %d,data %d\n",
+ __func__, dolby_data->param_id, dolby_data->be_id,
+ dolby_data->device_id, dolby_data->length, data);
+
+ switch (dolby_data->param_id) {
+ case DAP_CMD_COMMIT_ALL:
+ msm_ds2_dap_commit_params(dolby_data, 0);
+ break;
+
+ case DAP_CMD_COMMIT_CHANGED:
+ msm_ds2_dap_commit_params(dolby_data, 1);
+ break;
+
+ case DAP_CMD_USE_CACHE_FOR_INIT:
+ ds2_dap_params_states.use_cache = data;
+ break;
+
+ case DAP_CMD_SET_BYPASS:
+ pr_debug("%s: bypass %d bypass type %d, data %d\n", __func__,
+ ds2_dap_params_states.dap_bypass,
+ ds2_dap_params_states.dap_bypass_type,
+ data);
+ /* Do not perform bypass operation if bypass state is same*/
+ if (ds2_dap_params_states.dap_bypass == data)
+ break;
+ ds2_dap_params_states.dap_bypass = data;
+ /* hard bypass */
+ if (ds2_dap_params_states.dap_bypass_type == DAP_HARD_BYPASS)
+ msm_ds2_dap_handle_bypass(dolby_data);
+ /* soft bypass */
+ msm_ds2_dap_commit_params(dolby_data, 0);
+ break;
+
+ case DAP_CMD_SET_BYPASS_TYPE:
+ if (data == true)
+ ds2_dap_params_states.dap_bypass_type =
+ DAP_HARD_BYPASS;
+ else
+ ds2_dap_params_states.dap_bypass_type =
+ DAP_SOFT_BYPASS;
+ pr_debug("%s: bypass type %d", __func__,
+ ds2_dap_params_states.dap_bypass_type);
+ break;
+
+ case DAP_CMD_SET_ACTIVE_DEVICE:
+ pr_debug("%s: DAP_CMD_SET_ACTIVE_DEVICE length %d\n",
+ __func__, dolby_data->length);
+ /* TODO: need to handle multiple instance*/
+ ds2_dap_params_states.device |= dolby_data->device_id;
+ port_id = msm_ds2_dap_get_port_id(
+ dolby_data->device_id,
+ dolby_data->be_id);
+ pr_debug("%s: device id 0x%x all_dev 0x%x port_id %d\n",
+ __func__, dolby_data->device_id,
+ ds2_dap_params_states.device, port_id);
+ msm_ds2_dap_update_dev_map_port_id(dolby_data->device_id,
+ port_id);
+ if (port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s: invalid port id %d\n", __func__, port_id);
+ ret = -EINVAL;
+ goto end;
+ }
+ break;
+ }
+end:
+ return ret;
+
+}
+
+static int msm_ds2_dap_set_param(u32 cmd, void *arg)
+{
+ int rc = 0, idx, i, j, off, port_id = 0, cdev = 0;
+ int32_t num_device = 0;
+ int32_t data = 0;
+ int32_t dev_arr[DS2_DSP_SUPPORTED_ENDP_DEVICE] = {0};
+ struct dolby_param_data *dolby_data = (struct dolby_param_data *)arg;
+
+ rc = msm_ds2_dap_update_num_devices(dolby_data, &num_device, dev_arr,
+ DS2_DSP_SUPPORTED_ENDP_DEVICE);
+ if (num_device == 0 || rc < 0) {
+ pr_err("%s: num devices 0\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+ for (i = 0; i < num_device; i++) {
+ port_id = msm_ds2_dap_get_port_id(dev_arr[i],
+ dolby_data->be_id);
+ if (port_id != DOLBY_INVALID_PORT_ID)
+ msm_ds2_dap_update_dev_map_port_id(dev_arr[i], port_id);
+
+ cdev = msm_ds2_dap_map_device_to_dolby_cache_devices(
+ dev_arr[i]);
+ if (cdev < 0 || cdev >= DOLBY_MAX_CACHE) {
+ pr_err("%s: Invalid cache device %d for device 0x%x\n",
+ __func__, cdev, dev_arr[i]);
+ rc = -EINVAL;
+ goto end;
+ }
+ pr_debug("%s:port:%d,be:%d,dev:0x%x,cdev:%d,param:0x%x,len:%d\n"
+ , __func__, port_id, dolby_data->be_id, dev_arr[i],
+ cdev, dolby_data->param_id, dolby_data->length);
+ for (idx = 0; idx < MAX_DS2_PARAMS; idx++) {
+ /*paramid from user space*/
+ if (dolby_data->param_id == ds2_dap_params_id[idx])
+ break;
+ }
+ if (idx > MAX_DS2_PARAMS-1) {
+ pr_err("%s: invalid param id 0x%x at idx %d\n",
+ __func__, dolby_data->param_id, idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ off = ds2_dap_params_offset[idx];
+ if ((dolby_data->length <= 0) ||
+ (dolby_data->length > TOTAL_LENGTH_DS2_PARAM - off)) {
+ pr_err("%s: invalid length %d at idx %d\n",
+ __func__, dolby_data->length, idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* cache the parameters */
+ ds2_dap_params[cdev].dap_params_modified[idx] += 1;
+ for (j = 0; j < dolby_data->length; j++) {
+ if (get_user(data, &dolby_data->data[j])) {
+ pr_debug("%s:error getting data\n", __func__);
+ rc = -EFAULT;
+ goto end;
+ }
+ ds2_dap_params[cdev].params_val[off + j] = data;
+ pr_debug("%s:off %d,val[i/p:o/p]-[%d / %d]\n",
+ __func__, off, data,
+ ds2_dap_params[cdev].
+ params_val[off + j]);
+ }
+ }
+end:
+ return rc;
+}
+
+static int msm_ds2_dap_get_param(u32 cmd, void *arg)
+{
+ int rc = 0, i, port_id = 0, copp_idx = -1;
+ struct dolby_param_data *dolby_data = (struct dolby_param_data *)arg;
+ int32_t *update_params_value = NULL, *params_value = NULL;
+ uint32_t params_length = DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM *
+ sizeof(uint32_t);
+ uint32_t param_payload_len =
+ DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
+
+ /* Return error on get param in soft or hard bypass */
+ if (ds2_dap_params_states.dap_bypass == true) {
+ pr_err("%s: called in bypass_type %d bypass %d\n", __func__,
+ ds2_dap_params_states.dap_bypass_type,
+ ds2_dap_params_states.dap_bypass);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* Return if invalid length */
+ if ((dolby_data->length >
+ (DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM - DOLBY_PARAM_PAYLOAD_SIZE)) ||
+ (dolby_data->length <= 0)) {
+ pr_err("Invalid length %d", dolby_data->length);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ if ((dev_map[i].active) &&
+ (dev_map[i].device_id & dolby_data->device_id)) {
+ port_id = dev_map[i].port_id;
+ copp_idx = dev_map[i].copp_idx;
+ break;
+ }
+ }
+
+ if (port_id == DOLBY_INVALID_PORT_ID) {
+ pr_err("%s: Invalid port\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: Invalid copp_idx\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ pr_debug("%s: port_id 0x%x, copp_idx %d, dev_map[i].device_id %x\n",
+ __func__, port_id, copp_idx, dev_map[i].device_id);
+
+ params_value = kzalloc(params_length + param_payload_len,
+ GFP_KERNEL);
+ if (!params_value) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ if (dolby_data->param_id == DOLBY_PARAM_ID_VER) {
+ rc = adm_get_params(port_id, copp_idx,
+ DOLBY_BUNDLE_MODULE_ID,
+ DOLBY_PARAM_ID_VER,
+ params_length + param_payload_len,
+ (char *)params_value);
+ } else {
+ for (i = 0; i < MAX_DS2_PARAMS; i++)
+ if (ds2_dap_params_id[i] ==
+ dolby_data->param_id)
+ break;
+ if (i > MAX_DS2_PARAMS-1) {
+ pr_err("%s: invalid param id 0x%x at id %d\n", __func__,
+ dolby_data->param_id, i);
+ rc = -EINVAL;
+ goto end;
+ } else {
+ params_length =
+ ds2_dap_params_length[i] * sizeof(uint32_t);
+
+ rc = adm_get_params(port_id, copp_idx,
+ DOLBY_BUNDLE_MODULE_ID,
+ ds2_dap_params_id[i],
+ params_length +
+ param_payload_len,
+ (char *)params_value);
+ }
+ }
+ if (rc) {
+ pr_err("%s: get parameters failed rc %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto end;
+ }
+ update_params_value = params_value;
+ if (copy_to_user((void *)dolby_data->data,
+ &update_params_value[DOLBY_PARAM_PAYLOAD_SIZE],
+ (dolby_data->length * sizeof(uint32_t)))) {
+ pr_err("%s: error getting param\n", __func__);
+ rc = -EFAULT;
+ goto end;
+ }
+end:
+ kfree(params_value);
+ return rc;
+}
+
+static int msm_ds2_dap_param_visualizer_control_get(u32 cmd, void *arg)
+{
+ int32_t *visualizer_data = NULL;
+ int i = 0, ret = 0, port_id = -1, cache_dev = -1, copp_idx = -1;
+ int32_t *update_visualizer_data = NULL;
+ struct dolby_param_data *dolby_data = (struct dolby_param_data *)arg;
+ uint32_t offset, length, params_length;
+ uint32_t param_payload_len =
+ DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
+
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ if ((dev_map[i].active)) {
+ port_id = dev_map[i].port_id;
+ cache_dev = dev_map[i].cache_dev;
+ copp_idx = dev_map[i].copp_idx;
+ break;
+ }
+ }
+
+ if (port_id == DOLBY_INVALID_PORT_ID ||
+ (copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
+ ret = 0;
+ dolby_data->length = 0;
+ pr_err("%s: no device active\n", __func__);
+ goto end;
+ }
+
+ length = ds2_dap_params[cache_dev].params_val[DOLBY_PARAM_VCNB_OFFSET];
+
+ if (length > DOLBY_PARAM_VCNB_MAX_LENGTH || length <= 0) {
+ ret = 0;
+ dolby_data->length = 0;
+ pr_err("%s Incorrect VCNB length", __func__);
+ }
+
+ params_length = (2*length + DOLBY_VIS_PARAM_HEADER_SIZE) *
+ sizeof(uint32_t);
+
+ visualizer_data = kzalloc(params_length, GFP_KERNEL);
+ if (!visualizer_data) {
+ ret = -ENOMEM;
+ dolby_data->length = 0;
+ goto end;
+ }
+ memset(visualizer_data, 0x0, params_length);
+
+ /* Return error on get param in soft or hard bypass */
+ if (ds2_dap_params_states.dap_bypass == true) {
+ pr_debug("%s: visualizer called in bypass, return 0\n",
+ __func__);
+ ret = 0;
+ dolby_data->length = 0;
+ goto end;
+ }
+
+ offset = 0;
+ params_length = length * sizeof(uint32_t);
+ ret = adm_get_params(port_id, copp_idx,
+ DOLBY_BUNDLE_MODULE_ID,
+ DOLBY_PARAM_ID_VCBG,
+ params_length + param_payload_len,
+ (((char *)(visualizer_data)) + offset));
+ if (ret) {
+ pr_err("%s: get parameters failed ret %d\n", __func__, ret);
+ ret = -EINVAL;
+ dolby_data->length = 0;
+ goto end;
+ }
+ offset = length * sizeof(uint32_t);
+ ret = adm_get_params(port_id, copp_idx,
+ DOLBY_BUNDLE_MODULE_ID,
+ DOLBY_PARAM_ID_VCBE,
+ params_length + param_payload_len,
+ (((char *)(visualizer_data)) + offset));
+ if (ret) {
+ pr_err("%s: get parameters failed ret %d\n", __func__, ret);
+ ret = -EINVAL;
+ dolby_data->length = 0;
+ goto end;
+ }
+ update_visualizer_data = visualizer_data;
+ dolby_data->length = 2 * length;
+
+ if (copy_to_user((void *)dolby_data->data,
+ (void *)update_visualizer_data,
+ (dolby_data->length * sizeof(uint32_t)))) {
+ pr_err("%s: copy to user failed for data\n", __func__);
+ dolby_data->length = 0;
+ ret = -EFAULT;
+ goto end;
+ }
+
+end:
+ kfree(visualizer_data);
+ return ret;
+}
+
+int msm_ds2_dap_set_security_control(u32 cmd, void *arg)
+{
+ struct dolby_param_license *dolby_license =
+ ((struct dolby_param_license *)arg);
+ pr_debug("%s: dmid %d license key %d\n", __func__,
+ dolby_license->dmid, dolby_license->license_key);
+ core_set_dolby_manufacturer_id(dolby_license->dmid);
+ core_set_license(dolby_license->license_key, DOLBY_DS1_LICENSE_ID);
+ return 0;
+}
+
+int msm_ds2_dap_update_port_parameters(struct snd_hwdep *hw, struct file *file,
+ bool open)
+{
+ int i = 0, dev_id = 0;
+
+ pr_debug("%s: open %d\n", __func__, open);
+ ds2_dap_params_states.node_opened = open;
+ ds2_dap_params_states.dap_bypass = true;
+ ds2_dap_params_states.dap_bypass_type = 0;
+ ds2_dap_params_states.use_cache = 0;
+ ds2_dap_params_states.device = 0;
+ ds2_dap_params_states.custom_stereo_onoff = 0;
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ if (i == 0)
+ dev_map[i].device_id = 0;
+ else {
+ dev_id = (1 << (i-1));
+ if (all_supported_devices & dev_id)
+ dev_map[i].device_id = dev_id;
+ else
+ continue;
+ }
+ dev_map[i].cache_dev =
+ msm_ds2_dap_map_device_to_dolby_cache_devices(
+ dev_map[i].device_id);
+ if (dev_map[i].cache_dev < 0 ||
+ dev_map[i].cache_dev >= DOLBY_MAX_CACHE)
+ pr_err("%s: Invalid cache device %d for device 0x%x\n",
+ __func__,
+ dev_map[i].cache_dev,
+ dev_map[i].device_id);
+ dev_map[i].port_id = -1;
+ dev_map[i].active = false;
+ dev_map[i].stream_ref_count = 0;
+ dev_map[i].cal_data = NULL;
+ dev_map[i].copp_idx = -1;
+ pr_debug("%s: device_id 0x%x, cache_dev %d act %d\n", __func__,
+ dev_map[i].device_id, dev_map[i].cache_dev,
+ dev_map[i].active);
+ }
+ return 0;
+
+}
+
+int msm_ds2_dap_ioctl_shared(struct snd_hwdep *hw, struct file *file,
+ u32 cmd, void *arg)
+{
+ int ret = 0;
+
+ pr_debug("%s: cmd: 0x%x\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_DEVDEP_DAP_IOCTL_SET_PARAM:
+ ret = msm_ds2_dap_set_param(cmd, arg);
+ break;
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_PARAM:
+ ret = msm_ds2_dap_get_param(cmd, arg);
+ break;
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_COMMAND:
+ ret = msm_ds2_dap_handle_commands(cmd, arg);
+ break;
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_LICENSE:
+ ret = msm_ds2_dap_set_security_control(cmd, arg);
+ break;
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER:
+ ret = msm_ds2_dap_param_visualizer_control_get(cmd, arg);
+ break;
+ default:
+ pr_err("%s: called with invalid control 0x%x\n", __func__, cmd);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+int msm_ds2_dap_ioctl(struct snd_hwdep *hw, struct file *file,
+ u32 cmd, void *arg)
+{
+
+ int ret = 0;
+
+ pr_debug("%s: cmd: 0x%x\n", __func__, cmd);
+ if (!arg) {
+ pr_err("%s: Invalid params event status\n", __func__);
+ ret = -EINVAL;
+ goto end;
+ }
+ switch (cmd) {
+ case SNDRV_DEVDEP_DAP_IOCTL_SET_PARAM:
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_COMMAND: {
+ struct dolby_param_data dolby_data;
+
+ if (copy_from_user((void *)&dolby_data, (void *)arg,
+ sizeof(struct dolby_param_data))) {
+ pr_err("%s: Copy from user failed\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+ ret = msm_ds2_dap_ioctl_shared(hw, file, cmd, &dolby_data);
+ break;
+ }
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_LICENSE: {
+ struct dolby_param_license dolby_license;
+
+ if (copy_from_user((void *)&dolby_license, (void *)arg,
+ sizeof(struct dolby_param_license))) {
+ pr_err("%s: Copy from user failed\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+ ret = msm_ds2_dap_ioctl_shared(hw, file, cmd, &dolby_license);
+ break;
+ }
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_PARAM:
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER: {
+ struct dolby_param_data dolby_data;
+
+ if (copy_from_user((void *)&dolby_data, (void *)arg,
+ sizeof(struct dolby_param_data))) {
+ pr_err("%s: Copy from user failed\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+ ret = msm_ds2_dap_ioctl_shared(hw, file, cmd, &dolby_data);
+ if (ret < 0)
+ pr_err("%s: ioctl cmd %d returned err %d\n",
+ __func__, cmd, ret);
+ if (copy_to_user((void *)arg, &dolby_data,
+ sizeof(struct dolby_param_data))) {
+ pr_err("%s: Copy to user failed\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+ break;
+ }
+ default:
+ pr_err("%s: called with invalid control 0x%x\n", __func__, cmd);
+ ret = -EINVAL;
+ }
+end:
+ return ret;
+
+}
+#ifdef CONFIG_COMPAT
+int msm_ds2_dap_compat_ioctl(struct snd_hwdep *hw, struct file *file,
+ u32 cmd, void *arg)
+{
+ int ret = 0;
+
+ pr_debug("%s: cmd: 0x%x\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_DEVDEP_DAP_IOCTL_SET_PARAM32:
+ cmd = SNDRV_DEVDEP_DAP_IOCTL_SET_PARAM;
+ goto handle_set_ioctl;
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_COMMAND32:
+ cmd = SNDRV_DEVDEP_DAP_IOCTL_DAP_COMMAND;
+handle_set_ioctl:
+ {
+ struct dolby_param_data32 dolby_data32;
+ struct dolby_param_data dolby_data;
+
+ memset(&dolby_data32, 0, sizeof(dolby_data32));
+ memset(&dolby_data, 0, sizeof(dolby_data));
+ if (copy_from_user(&dolby_data32, (void *)arg,
+ sizeof(struct dolby_param_data32))) {
+ pr_err("%s: Copy from user failed\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+ dolby_data.version = dolby_data32.version;
+ dolby_data.device_id = dolby_data32.device_id;
+ dolby_data.be_id = dolby_data32.be_id;
+ dolby_data.param_id = dolby_data32.param_id;
+ dolby_data.length = dolby_data32.length;
+ dolby_data.data = compat_ptr(dolby_data32.data);
+
+ ret = msm_ds2_dap_ioctl_shared(hw, file, cmd, &dolby_data);
+ break;
+ }
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_PARAM32:
+ cmd = SNDRV_DEVDEP_DAP_IOCTL_GET_PARAM;
+ goto handle_get_ioctl;
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER32:
+ cmd = SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER;
+handle_get_ioctl:
+ {
+ struct dolby_param_data32 dolby_data32;
+ struct dolby_param_data dolby_data;
+
+ memset(&dolby_data32, 0, sizeof(dolby_data32));
+ memset(&dolby_data, 0, sizeof(dolby_data));
+ if (copy_from_user(&dolby_data32, (void *)arg,
+ sizeof(struct dolby_param_data32))) {
+ pr_err("%s: Copy from user failed\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+ dolby_data.version = dolby_data32.version;
+ dolby_data.device_id = dolby_data32.device_id;
+ dolby_data.be_id = dolby_data32.be_id;
+ dolby_data.param_id = dolby_data32.param_id;
+ dolby_data.length = dolby_data32.length;
+ dolby_data.data = compat_ptr(dolby_data32.data);
+
+ ret = msm_ds2_dap_ioctl_shared(hw, file, cmd, &dolby_data);
+ if (ret < 0)
+ pr_err("%s: ioctl cmd %d, returned err %d\n",
+ __func__, cmd, ret);
+ dolby_data32.length = dolby_data.length;
+ if (copy_to_user((void *)arg, &dolby_data32,
+ sizeof(struct dolby_param_data32))) {
+ pr_err("%s: Copy to user failed\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+ break;
+ }
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_LICENSE32: {
+ struct dolby_param_license32 dolby_license32;
+ struct dolby_param_license dolby_license;
+
+ cmd = SNDRV_DEVDEP_DAP_IOCTL_DAP_LICENSE;
+ if (copy_from_user((void *)&dolby_license32, (void *)arg,
+ sizeof(struct dolby_param_license32))) {
+ pr_err("%s: Copy from user failed\n", __func__);
+ ret = -EFAULT;
+ goto end;
+ }
+ dolby_license.dmid = dolby_license32.dmid;
+ dolby_license.license_key = dolby_license32.license_key;
+ ret = msm_ds2_dap_ioctl_shared(hw, file, cmd, &dolby_license);
+ break;
+ }
+ default:
+ pr_err("%s: called with invalid control 0x%x\n",
+ __func__, cmd);
+ ret = -EINVAL;
+ }
+end:
+ return ret;
+
+}
+#endif
+
+int msm_ds2_dap_init(int port_id, int copp_idx, int channels,
+ bool is_custom_stereo_on)
+{
+ int ret = 0, idx = -1, i;
+ struct dolby_param_data dolby_data;
+
+ struct audproc_softvolume_params softvol = {
+ .period = DOLBY_SOFT_VOLUME_PERIOD,
+ .step = DOLBY_SOFT_VOLUME_STEP,
+ .rampingcurve = DOLBY_SOFT_VOLUME_CURVE_EXP,
+ };
+
+ pr_debug("%s: port id %d, copp_idx %d\n", __func__, port_id, copp_idx);
+
+ if (port_id != DOLBY_INVALID_PORT_ID) {
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ if ((dev_map[i].port_id == port_id) &&
+ /* device part of active device */
+ (dev_map[i].device_id &
+ ds2_dap_params_states.device)) {
+ idx = i;
+ /* Give priority to headset in case of
+ * combo device
+ */
+ if (dev_map[i].device_id == SPEAKER)
+ continue;
+ else
+ break;
+ }
+ }
+ if (idx < 0) {
+ pr_err("%s: invalid index for port %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto end;
+ }
+ pr_debug("%s:index %d, dev[0x%x,0x%x]\n", __func__, idx,
+ dev_map[idx].device_id, ds2_dap_params_states.device);
+ dev_map[idx].active = true;
+ dev_map[idx].copp_idx = copp_idx;
+ dolby_data.param_id = DOLBY_COMMIT_ALL_TO_DSP;
+ dolby_data.length = 0;
+ dolby_data.data = NULL;
+ dolby_data.device_id = dev_map[idx].device_id;
+ pr_debug("%s: idx %d, active %d, dev id 0x%x, ref count %d\n",
+ __func__, idx, dev_map[idx].active,
+ dev_map[idx].device_id,
+ dev_map[idx].stream_ref_count);
+ if (dev_map[idx].stream_ref_count == 0) {
+ /*perform next 3 func only if hard bypass enabled*/
+ if (ds2_dap_params_states.dap_bypass_type ==
+ DAP_HARD_BYPASS) {
+ ret = msm_ds2_dap_alloc_and_store_cal_data(idx,
+ ADM_PATH_PLAYBACK, 0);
+ if (ret < 0) {
+ pr_err("%s: Failed to alloc and store cal data for idx %d, device %d, copp_idx %d",
+ __func__,
+ idx, dev_map[idx].device_id,
+ dev_map[idx].copp_idx);
+ dev_map[idx].active = false;
+ dev_map[idx].copp_idx = -1;
+ goto end;
+ }
+
+ ret = adm_set_softvolume(port_id, copp_idx,
+ &softvol);
+ if (ret < 0) {
+ pr_err("%s: Soft volume ret error %d\n",
+ __func__, ret);
+ dev_map[idx].active = false;
+ dev_map[idx].copp_idx = -1;
+ goto end;
+ }
+
+ ret = msm_ds2_dap_init_modules_in_topology(
+ idx);
+ if (ret < 0) {
+ pr_err("%s: Failed to init modules in topolofy for idx %d, device %d, copp_idx %d\n",
+ __func__, idx,
+ dev_map[idx].device_id,
+ dev_map[idx].copp_idx);
+ dev_map[idx].active = false;
+ dev_map[idx].copp_idx = -1;
+ goto end;
+ }
+ }
+
+ ret = msm_ds2_dap_commit_params(&dolby_data, 0);
+ if (ret < 0) {
+ pr_debug("%s: commit params ret %d\n",
+ __func__, ret);
+ ret = 0;
+ }
+ }
+ dev_map[idx].stream_ref_count++;
+ if (is_custom_stereo_on) {
+ ds2_dap_params_states.custom_stereo_onoff =
+ is_custom_stereo_on;
+ set_custom_stereo_onoff(idx,
+ is_custom_stereo_on);
+ }
+ }
+
+end:
+ return ret;
+}
+
+void msm_ds2_dap_deinit(int port_id)
+{
+ /*
+ * Get the active port corrresponding to the active device
+ * Check if this is same as incoming port
+ * Set it to invalid
+ */
+ int idx = -1, i;
+
+ pr_debug("%s: port_id %d\n", __func__, port_id);
+ if (port_id != DOLBY_INVALID_PORT_ID) {
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ /* Active port */
+ if ((dev_map[i].port_id == port_id) &&
+ /* device part of active device */
+ (dev_map[i].device_id &
+ ds2_dap_params_states.device) &&
+ /*
+ * Need this check to avoid race condition of
+ * active device being set and playback
+ * instance opened
+ */
+ /* active device*/
+ dev_map[i].active) {
+ idx = i;
+ if (dev_map[i].device_id == SPEAKER)
+ continue;
+ else
+ break;
+ }
+ }
+ if (idx < 0) {
+ pr_err("%s: invalid index for port %d\n",
+ __func__, port_id);
+ return;
+ }
+ pr_debug("%s:index %d, dev [0x%x, 0x%x]\n", __func__, idx,
+ dev_map[idx].device_id, ds2_dap_params_states.device);
+ dev_map[idx].stream_ref_count--;
+ if (dev_map[idx].stream_ref_count == 0) {
+ /*perform next func only if hard bypass enabled*/
+ if (ds2_dap_params_states.dap_bypass_type ==
+ DAP_HARD_BYPASS) {
+ msm_ds2_dap_free_cal_data(idx);
+ }
+ ds2_dap_params_states.device &= ~dev_map[idx].device_id;
+ dev_map[idx].active = false;
+ dev_map[idx].copp_idx = -1;
+ }
+ pr_debug("%s:idx %d, active %d, dev id 0x%x ref count %d\n",
+ __func__, idx, dev_map[idx].active,
+ dev_map[idx].device_id, dev_map[idx].stream_ref_count);
+ }
+}
+
+int msm_ds2_dap_set_custom_stereo_onoff(int port_id, int copp_idx,
+ bool is_custom_stereo_enabled)
+{
+ int idx = -1, rc = 0, i;
+
+ pr_debug("%s: port_id %d\n", __func__, port_id);
+ if (port_id != DOLBY_INVALID_PORT_ID) {
+ for (i = 0; i < DS2_DEVICES_ALL; i++) {
+ if ((dev_map[i].port_id == port_id) &&
+ /* device part of active device */
+ (dev_map[i].device_id &
+ ds2_dap_params_states.device)) {
+ idx = i;
+ if (dev_map[i].device_id == SPEAKER)
+ continue;
+ else
+ break;
+ }
+ }
+ if (idx < 0) {
+ pr_err("%s: invalid index for port %d\n",
+ __func__, port_id);
+ return rc;
+ }
+ ds2_dap_params_states.custom_stereo_onoff =
+ is_custom_stereo_enabled;
+ rc = set_custom_stereo_onoff(idx,
+ is_custom_stereo_enabled);
+ if (rc < 0) {
+ pr_err("%s: Custom stereo err %d on port %d\n",
+ __func__, rc, port_id);
+ }
+ }
+ return rc;
+}
+
+#else
+
+static int msm_ds2_dap_alloc_and_store_cal_data(int dev_map_idx, int path,
+ int perf_mode)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_free_cal_data(int dev_map_idx)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_send_cal_data(int dev_map_idx)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_can_enable_module(int32_t module_id)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_init_modules_in_topology(int dev_map_idx)
+{
+ return 0;
+}
+
+static bool msm_ds2_dap_check_is_param_modified(int32_t *dap_params_modified,
+ int32_t idx, int32_t commit)
+{
+ return false;
+}
+
+
+static int msm_ds2_dap_map_device_to_dolby_cache_devices(int32_t device_id)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_update_num_devices(struct dolby_param_data *dolby_data,
+ int32_t *num_device, int32_t *dev_arr,
+ int32_t array_size)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_commit_params(struct dolby_param_data *dolby_data,
+ int commit)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_handle_commands(u32 cmd, void *arg)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_set_param(u32 cmd, void *arg)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_get_param(u32 cmd, void *arg)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_send_end_point(int dev_map_idx, int endp_idx)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_send_cached_params(int dev_map_idx,
+ int commit)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_set_vspe_vdhe(int dev_map_idx,
+ bool is_custom_stereo_enabled)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_param_visualizer_control_get(
+ u32 cmd, void *arg,
+ struct msm_pcm_routing_bdai_data *bedais)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_set_security_control(u32 cmd, void *arg)
+{
+ return 0
+}
+
+static int msm_ds2_dap_update_dev_map_port_id(int32_t device_id, int port_id)
+{
+ return 0;
+}
+
+static int32_t msm_ds2_dap_get_port_id(
+ int32_t device_id, int32_t be_id)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_handle_bypass(struct dolby_param_data *dolby_data)
+{
+ return 0;
+}
+
+static int msm_ds2_dap_handle_bypass_wait(int port_id, int copp_idx,
+ int wait_time)
+{
+ return 0;
+}
+
+static int dap_set_custom_stereo_onoff(int dev_map_idx,
+ bool is_custom_stereo_enabled)
+{
+ return 0;
+}
+int qti_set_custom_stereo_on(int port_id, int copp_idx,
+ bool is_custom_stereo_on)
+{
+ return 0;
+}
+int set_custom_stereo_onoff(int dev_map_idx,
+ bool is_custom_stereo_enabled)
+{
+ return 0;
+}
+int msm_ds2_dap_ioctl_shared(struct snd_hwdep *hw, struct file *file,
+ u32 cmd, void *arg)
+{
+ return 0;
+}
+#endif /*CONFIG_DOLBY_DS2*/
diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.h b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.h
new file mode 100644
index 0000000..f2c2069
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.h
@@ -0,0 +1,121 @@
+/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_DS2_DAP_CONFIG_H_
+#define _MSM_DS2_DAP_CONFIG_H_
+
+#include <sound/soc.h>
+#include "msm-dolby-common.h"
+#include <sound/hwdep.h>
+#include <uapi/sound/devdep_params.h>
+
+#ifdef CONFIG_COMPAT
+struct dolby_param_data32 {
+ s32 version;
+ s32 device_id;
+ s32 be_id;
+ s32 param_id;
+ s32 length;
+ compat_uptr_t data;
+};
+
+struct dolby_param_license32 {
+ compat_uptr_t dmid;
+ compat_uptr_t license_key;
+};
+
+
+#define SNDRV_DEVDEP_DAP_IOCTL_SET_PARAM32\
+ _IOWR('U', 0x10, struct dolby_param_data32)
+#define SNDRV_DEVDEP_DAP_IOCTL_GET_PARAM32\
+ _IOR('U', 0x11, struct dolby_param_data32)
+#define SNDRV_DEVDEP_DAP_IOCTL_DAP_COMMAND32\
+ _IOWR('U', 0x13, struct dolby_param_data32)
+#define SNDRV_DEVDEP_DAP_IOCTL_DAP_LICENSE32\
+ _IOWR('U', 0x14, struct dolby_param_license32)
+#define SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER32\
+ _IOR('U', 0x15, struct dolby_param_data32)
+#endif
+
+#ifdef CONFIG_DOLBY_DS2
+/* DOLBY DOLBY GUIDS */
+#define DS2_MODULE_ID 0x00010775
+
+#define DS2_DSP_SUPPORTED_ENDP_DEVICE 17
+#define DS2_DEVICES_ALL 32 /* enum val is 4 bytes */
+
+enum {
+
+ DAP_CMD_COMMIT_ALL = 0,
+ DAP_CMD_COMMIT_CHANGED = 1,
+ DAP_CMD_USE_CACHE_FOR_INIT = 2,
+ DAP_CMD_SET_BYPASS = 3,
+ DAP_CMD_SET_ACTIVE_DEVICE = 4,
+ DAP_CMD_SET_BYPASS_TYPE = 5,
+};
+
+#define DOLBY_PARAM_INT_ENDP_LENGTH 1
+#define DOLBY_PARAM_INT_ENDP_OFFSET (DOLBY_PARAM_PSTG_OFFSET + \
+ DOLBY_PARAM_PSTG_LENGTH)
+#define MAX_DS2_PARAMS 48
+#define MAX_DS2_CTRL_PARAMS 4
+#define ALL_DS2_PARAMS (MAX_DS2_PARAMS + \
+ MAX_DS2_CTRL_PARAMS)
+#define TOTAL_LENGTH_DS2_PARAM (TOTAL_LENGTH_DOLBY_PARAM + 1)
+
+int msm_ds2_dap_update_port_parameters(struct snd_hwdep *hw, struct file *file,
+ bool open);
+int msm_ds2_dap_ioctl(struct snd_hwdep *hw, struct file *file,
+ u32 cmd, void *arg);
+int msm_ds2_dap_compat_ioctl(struct snd_hwdep *hw,
+ struct file *file,
+ u32 cmd, void *arg);
+int msm_ds2_dap_init(int port_id, int copp_idx, int channels,
+ bool is_custom_stereo_on);
+void msm_ds2_dap_deinit(int port_id);
+int msm_ds2_dap_set_custom_stereo_onoff(int port_id, int copp_idx,
+ bool is_custom_stereo_enabled);
+/* Dolby DOLBY end */
+#else
+
+static inline void msm_ds2_dap_update_port_parameters(struct snd_hwdep *hw,
+ struct file *file,
+ bool open)
+{
+}
+
+static inline int msm_ds2_dap_ioctl(struct snd_hwdep *hw, struct file *file,
+ u32 cmd, void *arg)
+{
+ return 0;
+}
+
+static inline int msm_ds2_dap_compat_ioctl(struct snd_hwdep *hw,
+ struct file *file,
+ u32 cmd, void *arg)
+{
+ return 0;
+}
+static inline int msm_ds2_dap_init(int port_id, int copp_idx, int channels,
+ bool is_custom_stereo_on)
+{
+ return 0;
+}
+
+static inline void msm_ds2_dap_deinit(int port_id) { }
+
+static inline int msm_ds2_dap_set_custom_stereo_onoff(int port_id, int copp_idx,
+ bool is_custom_stereo_enabled)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dts-eagle.c b/sound/soc/msm/qdsp6v2/msm-dts-eagle.c
new file mode 100644
index 0000000..5ad55dc
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dts-eagle.c
@@ -0,0 +1,1659 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/msm_ion.h>
+#include <linux/mm.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/vmalloc.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/q6adm-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6audio-v2.h>
+#include <sound/audio_effects.h>
+#include <sound/hwdep.h>
+#include <sound/msm-dts-eagle.h>
+#include <sound/q6core.h>
+
+#include "msm-pcm-routing-v2.h"
+
+#define ION_MEM_SIZE 131072
+#define DEPC_MAX_SIZE 524288
+
+#define MPST AUDPROC_MODULE_ID_DTS_HPX_POSTMIX
+#define MPRE AUDPROC_MODULE_ID_DTS_HPX_PREMIX
+
+#define eagle_vol_dbg(fmt, ...) \
+ pr_debug("DTS_EAGLE_DRIVER_VOLUME: " fmt "\n", ##__VA_ARGS__)
+#define eagle_vol_err(fmt, ...) \
+ pr_err("DTS_EAGLE_DRIVER_VOLUME: " fmt "\n", ##__VA_ARGS__)
+#define eagle_drv_dbg(fmt, ...) \
+ pr_debug("DTS_EAGLE_DRIVER: " fmt "\n", ##__VA_ARGS__)
+#define eagle_drv_err(fmt, ...) \
+ pr_err("DTS_EAGLE_DRIVER: " fmt "\n", ##__VA_ARGS__)
+#define eagle_precache_dbg(fmt, ...) \
+ pr_debug("DTS_EAGLE_DRIVER_SENDCACHE_PRE: " fmt "\n", ##__VA_ARGS__)
+#define eagle_precache_err(fmt, ...) \
+ pr_err("DTS_EAGLE_DRIVER_SENDCACHE_PRE: " fmt "\n", ##__VA_ARGS__)
+#define eagle_postcache_dbg(fmt, ...) \
+ pr_debug("DTS_EAGLE_DRIVER_SENDCACHE_POST: " fmt "\n", ##__VA_ARGS__)
+#define eagle_postcache_err(fmt, ...) \
+ pr_err("DTS_EAGLE_DRIVER_SENDCACHE_POST: " fmt "\n", ##__VA_ARGS__)
+#define eagle_ioctl_dbg(fmt, ...) \
+ pr_debug("DTS_EAGLE_DRIVER_IOCTL: " fmt "\n", ##__VA_ARGS__)
+#define eagle_ioctl_err(fmt, ...) \
+ pr_err("DTS_EAGLE_DRIVER_IOCTL: " fmt "\n", ##__VA_ARGS__)
+#define eagle_asm_dbg(fmt, ...) \
+ pr_debug("DTS_EAGLE_DRIVER_ASM: " fmt "\n", ##__VA_ARGS__)
+#define eagle_asm_err(fmt, ...) \
+ pr_err("DTS_EAGLE_DRIVER_ASM: " fmt "\n", ##__VA_ARGS__)
+#define eagle_adm_dbg(fmt, ...) \
+ pr_debug("DTS_EAGLE_DRIVER_ADM: " fmt "\n", ##__VA_ARGS__)
+#define eagle_adm_err(fmt, ...) \
+ pr_err("DTS_EAGLE_DRIVER_ADM: " fmt "\n", ##__VA_ARGS__)
+#define eagle_enable_dbg(fmt, ...) \
+ pr_debug("DTS_EAGLE_ENABLE: " fmt "\n", ##__VA_ARGS__)
+#define eagle_enable_err(fmt, ...) \
+ pr_err("DTS_EAGLE_ENABLE: " fmt "\n", ##__VA_ARGS__)
+#define eagle_ioctl_info(fmt, ...) \
+ pr_err("DTS_EAGLE_IOCTL: " fmt "\n", ##__VA_ARGS__)
+
+enum {
+ AUDIO_DEVICE_OUT_EARPIECE = 0,
+ AUDIO_DEVICE_OUT_SPEAKER,
+ AUDIO_DEVICE_OUT_WIRED_HEADSET,
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,
+ AUDIO_DEVICE_OUT_AUX_DIGITAL,
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET,
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,
+ AUDIO_DEVICE_OUT_USB_ACCESSORY,
+ AUDIO_DEVICE_OUT_USB_DEVICE,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_DEVICE_OUT_ANC_HEADSET,
+ AUDIO_DEVICE_OUT_ANC_HEADPHONE,
+ AUDIO_DEVICE_OUT_PROXY,
+ AUDIO_DEVICE_OUT_FM,
+ AUDIO_DEVICE_OUT_FM_TX,
+
+ AUDIO_DEVICE_OUT_COUNT
+};
+
+#define AUDIO_DEVICE_COMBO 0x400000 /* bit 23 */
+
+enum { /* cache block */
+ CB_0 = 0,
+ CB_1,
+ CB_2,
+ CB_3,
+ CB_4,
+ CB_5,
+ CB_6,
+ CB_7,
+
+ CB_COUNT
+};
+
+enum { /* cache block description */
+ CBD_DEV_MASK = 0,
+ CBD_OFFSG,
+ CBD_CMD0,
+ CBD_SZ0,
+ CBD_OFFS1,
+ CBD_CMD1,
+ CBD_SZ1,
+ CBD_OFFS2,
+ CBD_CMD2,
+ CBD_SZ2,
+ CBD_OFFS3,
+ CBD_CMD3,
+ CBD_SZ3,
+
+ CBD_COUNT,
+};
+
+static s32 _fx_logN(s32 x)
+{
+ s32 t, y = 0xa65af;
+
+ if (x < 0x00008000) {
+ x <<= 16; y -= 0xb1721; }
+ if (x < 0x00800000) {
+ x <<= 8; y -= 0x58b91; }
+ if (x < 0x08000000) {
+ x <<= 4; y -= 0x2c5c8; }
+ if (x < 0x20000000) {
+ x <<= 2; y -= 0x162e4; }
+ if (x < 0x40000000) {
+ x <<= 1; y -= 0x0b172; }
+ t = x + (x >> 1);
+ if ((t & 0x80000000) == 0) {
+ x = t; y -= 0x067cd; }
+ t = x + (x >> 2);
+ if ((t & 0x80000000) == 0) {
+ x = t; y -= 0x03920; }
+ t = x + (x >> 3);
+ if ((t & 0x80000000) == 0) {
+ x = t; y -= 0x01e27; }
+ t = x + (x >> 4);
+ if ((t & 0x80000000) == 0) {
+ x = t; y -= 0x00f85; }
+ t = x + (x >> 5);
+ if ((t & 0x80000000) == 0) {
+ x = t; y -= 0x007e1; }
+ t = x + (x >> 6);
+ if ((t & 0x80000000) == 0) {
+ x = t; y -= 0x003f8; }
+ t = x + (x >> 7);
+ if ((t & 0x80000000) == 0) {
+ x = t; y -= 0x001fe; }
+ x = 0x80000000 - x;
+ y -= x >> 15;
+ return y;
+}
+
+static inline void *_getd(struct dts_eagle_param_desc *depd)
+{
+ return (void *)(((char *)depd) + sizeof(struct dts_eagle_param_desc));
+}
+
+static int _ref_cnt;
+/* dts eagle parameter cache */
+static char *_depc;
+static u32 _depc_size;
+static s32 _c_bl[CB_COUNT][CBD_COUNT];
+static u32 _device_primary;
+static u32 _device_all;
+/* ION states */
+static struct ion_client *_ion_client;
+static struct ion_handle *_ion_handle;
+static struct param_outband _po;
+static struct audio_client *_ac_NT;
+static struct ion_client *_ion_client_NT;
+static struct ion_handle *_ion_handle_NT;
+static struct param_outband _po_NT;
+
+#define SEC_BLOB_MAX_CNT 10
+#define SEC_BLOB_MAX_SIZE 0x4004 /*extra 4 for size*/
+static char *_sec_blob[SEC_BLOB_MAX_CNT];
+
+/* multi-copp support */
+static int _cidx[AFE_MAX_PORTS] = {-1};
+
+/* volume controls */
+#define VOL_CMD_CNT_MAX 10
+static u32 _vol_cmd_cnt;
+static s32 **_vol_cmds;
+struct vol_cmds_d {
+ s32 d[4];
+};
+static struct vol_cmds_d *_vol_cmds_d;
+static const s32 _log10_10_inv_x20 = 0x0008af84;
+
+/* hpx master control */
+static u32 _is_hpx_enabled;
+
+static void _volume_cmds_free(void)
+{
+ int i;
+
+ for (i = 0; i < _vol_cmd_cnt; i++)
+ kfree(_vol_cmds[i]);
+ _vol_cmd_cnt = 0;
+ kfree(_vol_cmds);
+ kfree(_vol_cmds_d);
+ _vol_cmds = NULL;
+ _vol_cmds_d = NULL;
+}
+
+static s32 _volume_cmds_alloc1(s32 size)
+{
+ _volume_cmds_free();
+ _vol_cmd_cnt = size;
+ _vol_cmds = kzalloc(_vol_cmd_cnt * sizeof(int *), GFP_KERNEL);
+ if (_vol_cmds) {
+ _vol_cmds_d = kzalloc(_vol_cmd_cnt * sizeof(struct vol_cmds_d),
+ GFP_KERNEL);
+ }
+ if (_vol_cmds_d)
+ return 0;
+ _volume_cmds_free();
+ return -ENOMEM;
+}
+
+/* assumes size is equal or less than 0xFFF */
+static s32 _volume_cmds_alloc2(s32 idx, s32 size)
+{
+ kfree(_vol_cmds[idx]);
+ _vol_cmds[idx] = kzalloc(size, GFP_KERNEL);
+ if (_vol_cmds[idx])
+ return 0;
+ _vol_cmds_d[idx].d[0] = 0;
+ return -ENOMEM;
+}
+
+static void _init_cb_descs(void)
+{
+ int i;
+
+ for (i = 0; i < CB_COUNT; i++) {
+ _c_bl[i][CBD_DEV_MASK] = 0;
+ _c_bl[i][CBD_OFFSG] = _c_bl[i][CBD_OFFS1] =
+ _c_bl[i][CBD_OFFS2] = _c_bl[i][CBD_OFFS3] =
+ 0xFFFFFFFF;
+ _c_bl[i][CBD_CMD0] = _c_bl[i][CBD_SZ0] =
+ _c_bl[i][CBD_CMD1] = _c_bl[i][CBD_SZ1] =
+ _c_bl[i][CBD_CMD2] = _c_bl[i][CBD_SZ2] =
+ _c_bl[i][CBD_CMD3] = _c_bl[i][CBD_SZ3] = 0;
+ }
+}
+
+static u32 _get_dev_mask_for_pid(int pid)
+{
+ switch (pid) {
+ case SLIMBUS_0_RX:
+ return (1 << AUDIO_DEVICE_OUT_EARPIECE) |
+ (1 << AUDIO_DEVICE_OUT_SPEAKER) |
+ (1 << AUDIO_DEVICE_OUT_WIRED_HEADSET) |
+ (1 << AUDIO_DEVICE_OUT_WIRED_HEADPHONE) |
+ (1 << AUDIO_DEVICE_OUT_ANC_HEADSET) |
+ (1 << AUDIO_DEVICE_OUT_ANC_HEADPHONE);
+ /* fallthrough */
+ case INT_BT_SCO_RX:
+ return (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+ /* fallthrough */
+ case RT_PROXY_PORT_001_RX:
+ return (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) |
+ (1 << AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) |
+ (1 << AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) |
+ (1 << AUDIO_DEVICE_OUT_USB_ACCESSORY) |
+ (1 << AUDIO_DEVICE_OUT_USB_DEVICE) |
+ (1 << AUDIO_DEVICE_OUT_PROXY);
+ /* fallthrough */
+ case HDMI_RX:
+ return 1 << AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ case INT_FM_RX:
+ return 1 << AUDIO_DEVICE_OUT_FM;
+ case INT_FM_TX:
+ return 1 << AUDIO_DEVICE_OUT_FM_TX;
+ default:
+ return 0;
+ }
+}
+
+static int _get_pid_from_dev(u32 device)
+{
+ if (device & (1 << AUDIO_DEVICE_OUT_EARPIECE) ||
+ device & (1 << AUDIO_DEVICE_OUT_SPEAKER) ||
+ device & (1 << AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ device & (1 << AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+ device & (1 << AUDIO_DEVICE_OUT_ANC_HEADSET) ||
+ device & (1 << AUDIO_DEVICE_OUT_ANC_HEADPHONE)) {
+ return SLIMBUS_0_RX;
+ } else if (device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) ||
+ device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
+ device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
+ return INT_BT_SCO_RX;
+ } else if (device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) ||
+ device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) ||
+ device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
+ device & (1 << AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) ||
+ device & (1 << AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ||
+ device & (1 << AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
+ device & (1 << AUDIO_DEVICE_OUT_USB_DEVICE) ||
+ device & (1 << AUDIO_DEVICE_OUT_PROXY)) {
+ return RT_PROXY_PORT_001_RX;
+ } else if (device & (1 << AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+ return HDMI_RX;
+ } else if (device & (1 << AUDIO_DEVICE_OUT_FM)) {
+ return INT_FM_RX;
+ } else if (device & (1 << AUDIO_DEVICE_OUT_FM_TX)) {
+ return INT_FM_TX;
+ }
+ return 0;
+}
+
+static s32 _get_cb_for_dev(int device)
+{
+ s32 i;
+
+ if (device & AUDIO_DEVICE_COMBO) {
+ for (i = 0; i < CB_COUNT; i++) {
+ if ((_c_bl[i][CBD_DEV_MASK] & device) == device)
+ return i;
+ }
+ } else {
+ for (i = 0; i < CB_COUNT; i++) {
+ if ((_c_bl[i][CBD_DEV_MASK] & device) &&
+ !(_c_bl[i][CBD_DEV_MASK] & AUDIO_DEVICE_COMBO))
+ return i;
+ }
+ }
+ eagle_drv_err("%s: device %i not found", __func__, device);
+ return -EINVAL;
+}
+
+static int _is_port_open_and_eagle(int pid)
+{
+ if (msm_routing_check_backend_enabled(pid))
+ return 1;
+ return 1;
+}
+
+static int _isNTDevice(u32 device)
+{
+ if (device &
+ ((1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) |
+ (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) |
+ (1 << AUDIO_DEVICE_OUT_AUX_DIGITAL)))
+ return 1;
+ return 0;
+}
+
+static void _reg_ion_mem(void)
+{
+ int rc;
+
+ rc = msm_audio_ion_alloc("DTS_EAGLE", &_ion_client, &_ion_handle,
+ ION_MEM_SIZE, &_po.paddr, &_po.size, &_po.kvaddr);
+ if (rc)
+ eagle_drv_err("%s: msm audio ion alloc failed with %i",
+ __func__, rc);
+}
+
+static void _unreg_ion_mem(void)
+{
+ int rc;
+
+ rc = msm_audio_ion_free(_ion_client, _ion_handle);
+ if (rc)
+ eagle_drv_err("%s: msm audio ion alloc failed with %i",
+ __func__, rc);
+}
+
+static void _reg_ion_mem_NT(void)
+{
+ int rc;
+
+ eagle_drv_dbg("%s: NT ion mem", __func__);
+ rc = msm_audio_ion_alloc("DTS_EAGLE", &_ion_client_NT,
+ &_ion_handle_NT, ION_MEM_SIZE,
+ &_po_NT.paddr, &_po_NT.size, &_po_NT.kvaddr);
+ if (rc) {
+ eagle_drv_err("%s: msm audio ion alloc failed", __func__);
+ return;
+ }
+ rc = q6asm_memory_map(_ac_NT, _po_NT.paddr,
+ IN, _po_NT.size, 1);
+ if (rc < 0) {
+ eagle_drv_err("%s: memory map failed", __func__);
+ msm_audio_ion_free(_ion_client_NT, _ion_handle_NT);
+ _ion_client_NT = NULL;
+ _ion_handle_NT = NULL;
+ }
+}
+
+static void _unreg_ion_mem_NT(void)
+{
+ int rc;
+
+ rc = q6asm_memory_unmap(_ac_NT, _po_NT.paddr, IN);
+ if (rc < 0)
+ eagle_drv_err("%s: mem unmap failed", __func__);
+ rc = msm_audio_ion_free(_ion_client_NT, _ion_handle_NT);
+ if (rc < 0)
+ eagle_drv_err("%s: mem free failed", __func__);
+
+ _ion_client_NT = NULL;
+ _ion_handle_NT = NULL;
+}
+
+static struct audio_client *_getNTDeviceAC(void)
+{
+ return _ac_NT;
+}
+
+static void _set_audioclient(struct audio_client *ac)
+{
+ _ac_NT = ac;
+ _reg_ion_mem_NT();
+}
+
+static void _clear_audioclient(void)
+{
+ _unreg_ion_mem_NT();
+ _ac_NT = NULL;
+}
+
+
+static int _sendcache_pre(struct audio_client *ac)
+{
+ uint32_t offset, size;
+ int32_t cidx, cmd, err = 0;
+
+ cidx = _get_cb_for_dev(_device_primary);
+ if (cidx < 0) {
+ eagle_precache_err("%s: no cache for primary device %i found",
+ __func__, _device_primary);
+ return -EINVAL;
+ }
+ offset = _c_bl[cidx][CBD_OFFSG];
+ cmd = _c_bl[cidx][CBD_CMD0];
+ size = _c_bl[cidx][CBD_SZ0];
+ /* check for integer overflow */
+ if (offset > (UINT_MAX - size))
+ err = -EINVAL;
+ if ((_depc_size == 0) || !_depc || (size == 0) ||
+ cmd == 0 || ((offset + size) > _depc_size) || (err != 0)) {
+ eagle_precache_err("%s: primary device %i cache index %i general error - cache size = %u, cache ptr = %pK, offset = %u, size = %u, cmd = %i",
+ __func__, _device_primary, cidx, _depc_size, _depc,
+ offset, size, cmd);
+ return -EINVAL;
+ }
+
+ if ((offset < (UINT_MAX - 124)) && ((offset + 124) < _depc_size))
+ eagle_precache_dbg("%s: first 6 integers %i %i %i %i %i %i (30th %i)",
+ __func__, *((int *)&_depc[offset]),
+ *((int *)&_depc[offset+4]),
+ *((int *)&_depc[offset+8]),
+ *((int *)&_depc[offset+12]),
+ *((int *)&_depc[offset+16]),
+ *((int *)&_depc[offset+20]),
+ *((int *)&_depc[offset+120]));
+ eagle_precache_dbg("%s: sending full data block to port, with cache index = %d device mask 0x%X, param = 0x%X, offset = %u, and size = %u",
+ __func__, cidx, _c_bl[cidx][CBD_DEV_MASK], cmd, offset, size);
+
+ if (q6asm_dts_eagle_set(ac, cmd, size, (void *)&_depc[offset],
+ NULL, MPRE))
+ eagle_precache_err("%s: q6asm_dts_eagle_set failed with id = %d and size = %u",
+ __func__, cmd, size);
+ else
+ eagle_precache_dbg("%s: q6asm_dts_eagle_set succeeded with id = %d and size = %u",
+ __func__, cmd, size);
+ return 0;
+}
+
+static int _sendcache_post(int port_id, int copp_idx, int topology)
+{
+ int cidx = -1, cmd, mask, index, err = 0;
+ uint32_t offset, size;
+
+ if (port_id == -1) {
+ cidx = _get_cb_for_dev(_device_primary);
+ if (cidx < 0) {
+ eagle_postcache_err("%s: no cache for primary device %i found. Port id was 0x%X",
+ __func__, _device_primary, port_id);
+ return -EINVAL;
+ }
+ goto NT_MODE_GOTO;
+ }
+
+ index = adm_validate_and_get_port_index(port_id);
+ if (index < 0) {
+ eagle_postcache_err("%s: Invalid port idx %d port_id %#x",
+ __func__, index, port_id);
+ return -EINVAL;
+ }
+ eagle_postcache_dbg("%s: valid port idx %d for port_id %#x set to %i",
+ __func__, index, port_id, copp_idx);
+ _cidx[index] = copp_idx;
+
+ mask = _get_dev_mask_for_pid(port_id);
+ if (mask & _device_primary) {
+ cidx = _get_cb_for_dev(_device_primary);
+ if (cidx < 0) {
+ eagle_postcache_err("%s: no cache for primary device %i found. Port id was 0x%X",
+ __func__, _device_primary, port_id);
+ return -EINVAL;
+ }
+ } else if (mask & _device_all) {
+ cidx = _get_cb_for_dev(_device_all);
+ if (cidx < 0) {
+ eagle_postcache_err("%s: no cache for combo device %i found. Port id was 0x%X",
+ __func__, _device_all, port_id);
+ return -EINVAL;
+ }
+ } else {
+ eagle_postcache_err("%s: port id 0x%X not for primary or combo device %i",
+ __func__, port_id, _device_primary);
+ return -EINVAL;
+ }
+
+NT_MODE_GOTO:
+ offset = _c_bl[cidx][CBD_OFFSG] + _c_bl[cidx][CBD_OFFS2];
+ cmd = _c_bl[cidx][CBD_CMD2];
+ size = _c_bl[cidx][CBD_SZ2];
+
+ /* check for integer overflow */
+ if (offset > (UINT_MAX - size))
+ err = -EINVAL;
+ if ((_depc_size == 0) || !_depc || (err != 0) || (size == 0) ||
+ (cmd == 0) || (offset + size) > _depc_size) {
+ eagle_postcache_err("%s: primary device %i cache index %i port_id 0x%X general error - cache size = %u, cache ptr = %pK, offset = %u, size = %u, cmd = %i",
+ __func__, _device_primary, cidx, port_id,
+ _depc_size, _depc, offset, size, cmd);
+ return -EINVAL;
+ }
+
+ if ((offset < (UINT_MAX - 24)) && ((offset + 24) < _depc_size))
+ eagle_postcache_dbg("%s: first 6 integers %i %i %i %i %i %i",
+ __func__, *((int *)&_depc[offset]),
+ *((int *)&_depc[offset+4]),
+ *((int *)&_depc[offset+8]),
+ *((int *)&_depc[offset+12]),
+ *((int *)&_depc[offset+16]),
+ *((int *)&_depc[offset+20]));
+ eagle_postcache_dbg("%s: sending full data block to port, with cache index = %d device mask 0x%X, port_id = 0x%X, param = 0x%X, offset = %u, and size = %u",
+ __func__, cidx, _c_bl[cidx][CBD_DEV_MASK], port_id, cmd,
+ offset, size);
+
+ if (_ac_NT) {
+ eagle_postcache_dbg("%s: NT Route detected", __func__);
+ if (q6asm_dts_eagle_set(_getNTDeviceAC(), cmd, size,
+ (void *)&_depc[offset],
+ &_po_NT, MPST))
+ eagle_postcache_err("%s: q6asm_dts_eagle_set failed with id = 0x%X and size = %u",
+ __func__, cmd, size);
+ } else if (adm_dts_eagle_set(port_id, copp_idx, cmd,
+ (void *)&_depc[offset], size) < 0)
+ eagle_postcache_err("%s: adm_dts_eagle_set failed with id = 0x%X and size = %u",
+ __func__, cmd, size);
+ else
+ eagle_postcache_dbg("%s: adm_dts_eagle_set succeeded with id = 0x%X and size = %u",
+ __func__, cmd, size);
+ return 0;
+}
+
+static int _enable_post_get_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = _is_hpx_enabled;
+ return 0;
+}
+
+static int _enable_post_put_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = 0, be_index = 0, port_id, topology;
+ int flag = ucontrol->value.integer.value[0];
+ struct msm_pcm_routing_bdai_data msm_bedai;
+
+ eagle_drv_dbg("%s: flag %d", __func__, flag);
+
+ _is_hpx_enabled = flag ? true : false;
+ msm_pcm_routing_acquire_lock();
+ /* send cache postmix params when hpx is set On */
+ for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) {
+ msm_pcm_routing_get_bedai_info(be_index, &msm_bedai);
+ port_id = msm_bedai.port_id;
+ if (!(((port_id == SLIMBUS_0_RX) ||
+ (port_id == RT_PROXY_PORT_001_RX)) &&
+ msm_bedai.active))
+ continue;
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
+ topology = adm_get_topology_for_port_copp_idx(
+ port_id, idx);
+ if (topology ==
+ ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) {
+ msm_dts_eagle_enable_adm(port_id, idx,
+ _is_hpx_enabled);
+ }
+ }
+ }
+ msm_pcm_routing_release_lock();
+ return 0;
+}
+
+static const struct snd_kcontrol_new _hpx_enabled_controls[] = {
+ SOC_SINGLE_EXT("Set HPX OnOff", SND_SOC_NOPM, 0, 1, 0,
+ _enable_post_get_control, _enable_post_put_control)
+};
+
+/**
+ * msm_dts_ion_memmap() - helper function to map ION memory
+ * @po_: Out of band memory structure used as memory.
+ *
+ * Assign already allocated ION memory for mapping it to dsp.
+ *
+ * Return: No return value.
+ */
+void msm_dts_ion_memmap(struct param_outband *po_)
+{
+ po_->size = ION_MEM_SIZE;
+ po_->kvaddr = _po.kvaddr;
+ po_->paddr = _po.paddr;
+}
+
+/**
+ * msm_dts_eagle_enable_asm() - Enable/disable dts module
+ * @ac: Enable/disable module in ASM session associated with this audio client.
+ * @enable: Enable/disable the dts module.
+ * @module: module id.
+ *
+ * Enable/disable specified dts module id in asm.
+ *
+ * Return: Return failure if any.
+ */
+int msm_dts_eagle_enable_asm(struct audio_client *ac, u32 enable, int module)
+{
+ int ret = 0;
+
+ eagle_enable_dbg("%s: enable = %i on module %i",
+ __func__, enable, module);
+ _is_hpx_enabled = enable;
+ ret = q6asm_dts_eagle_set(ac, AUDPROC_PARAM_ID_ENABLE,
+ sizeof(enable), &enable,
+ NULL, module);
+ if (_is_hpx_enabled) {
+ if (module == MPRE)
+ _sendcache_pre(ac);
+ else if (module == MPST)
+ _sendcache_post(-1, 0, 0);
+ }
+ return ret;
+}
+
+/**
+ * msm_dts_eagle_enable_adm() - Enable/disable dts module in adm
+ * @port_id: Send enable/disable param to this port id.
+ * @copp_idx: Send enable/disable param to the relevant copp.
+ * @enable: Enable/disable the dts module.
+ *
+ * Enable/disable dts module in adm.
+ *
+ * Return: Return failure if any.
+ */
+int msm_dts_eagle_enable_adm(int port_id, int copp_idx, u32 enable)
+{
+ int ret = 0;
+
+ eagle_enable_dbg("%s: enable = %i", __func__, enable);
+ _is_hpx_enabled = enable;
+ ret = adm_dts_eagle_set(port_id, copp_idx, AUDPROC_PARAM_ID_ENABLE,
+ (char *)&enable, sizeof(enable));
+ if (_is_hpx_enabled)
+ _sendcache_post(port_id, copp_idx, MPST);
+ return ret;
+}
+
+/**
+ * msm_dts_eagle_add_controls() - Add mixer control to Enable/Disable DTS HPX
+ * @platform: Add mixer controls to this platform.
+ *
+ * Add mixer control to Enable/Disable DTS HPX module in ADM.
+ *
+ * Return: No return value.
+ */
+void msm_dts_eagle_add_controls(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, _hpx_enabled_controls,
+ ARRAY_SIZE(_hpx_enabled_controls));
+}
+
+/**
+ * msm_dts_eagle_set_stream_gain() - Set stream gain to DTS Premix module
+ * @ac: Set stream gain to ASM session associated with this audio client.
+ * @lgain: Left gain value.
+ * @rgain: Right gain value.
+ *
+ * Set stream gain to DTS Premix module in ASM.
+ *
+ * Return: failure or success.
+ */
+int msm_dts_eagle_set_stream_gain(struct audio_client *ac, int lgain, int rgain)
+{
+ u32 i, val;
+ s32 idx, err = 0;
+
+ eagle_vol_dbg("%s: - entry: vol_cmd_cnt = %u, lgain = %i, rgain = %i",
+ __func__, _vol_cmd_cnt, lgain, rgain);
+
+ if (_depc_size == 0) {
+ eagle_vol_dbg("%s: driver cache not initialized", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < _vol_cmd_cnt; i++) {
+ if (_vol_cmds_d[i].d[0] & 0x8000) {
+ idx = (sizeof(struct dts_eagle_param_desc)/sizeof(int))
+ + (_vol_cmds_d[i].d[0] & 0x3FF);
+ val = _fx_logN(((s32)(lgain+rgain)) << 2);
+ val = ((long long)val * _log10_10_inv_x20) >> 16;
+ _vol_cmds[i][idx] = (s32)clamp((int)(((long long)val *
+ _vol_cmds_d[i].d[1]) >> 16),
+ _vol_cmds_d[i].d[2],
+ _vol_cmds_d[i].d[3]);
+ eagle_vol_dbg("%s: loop %u cmd desc found %i, idx = %i. volume info: lgain = %i, rgain = %i, volume = %i (scale %i, min %i, max %i)",
+ __func__, i, _vol_cmds_d[i].d[0], idx, lgain,
+ rgain, _vol_cmds[i][idx], _vol_cmds_d[i].d[1],
+ _vol_cmds_d[i].d[2], _vol_cmds_d[i].d[3]);
+ }
+ idx = _get_cb_for_dev(_device_primary);
+ if (idx < 0) {
+ eagle_vol_err("%s: no cache for primary device %i found",
+ __func__, _device_primary);
+ return -EINVAL;
+ }
+ val = _c_bl[idx][CBD_OFFSG] + _vol_cmds[i][2];
+ /* check for integer overflow */
+ if (val > (UINT_MAX - _vol_cmds[i][1]))
+ err = -EINVAL;
+ if ((err != 0) || ((val + _vol_cmds[i][1]) > _depc_size)) {
+ eagle_vol_err("%s: volume size (%u) + offset (%i) out of bounds %i",
+ __func__, val, _vol_cmds[i][1], _depc_size);
+ return -EINVAL;
+ }
+ memcpy((void *)&_depc[val], &_vol_cmds[i][4], _vol_cmds[i][1]);
+ if (q6asm_dts_eagle_set(ac, _vol_cmds[i][0],
+ _vol_cmds[i][1], (void *)&_depc[val], NULL, MPRE))
+ eagle_vol_err("%s: loop %u - volume set failed with id 0x%X, size %i, offset %i, cmd_desc %i, scale %i, min %i, max %i, data(...) %i",
+ __func__, i, _vol_cmds[i][0], _vol_cmds[i][1],
+ _vol_cmds[i][2], _vol_cmds_d[i].d[0],
+ _vol_cmds_d[i].d[1], _vol_cmds_d[i].d[2],
+ _vol_cmds_d[i].d[3], _vol_cmds[i][4]);
+ else
+ eagle_vol_dbg("%s: loop %u - volume set succeeded with id 0x%X, size %i, offset %i, cmd_desc %i, scale %i, min %i, max %i, data(...) %i",
+ __func__, i, _vol_cmds[i][0], _vol_cmds[i][1],
+ _vol_cmds[i][2], _vol_cmds_d[i].d[0],
+ _vol_cmds_d[i].d[1], _vol_cmds_d[i].d[2],
+ _vol_cmds_d[i].d[3], _vol_cmds[i][4]);
+ }
+ return 0;
+}
+
+/**
+ * msm_dts_eagle_handle_asm() - Set or Get params from ASM
+ * @depd: DTS Eagle Params structure.
+ * @buf: Buffer to get queried param value.
+ * @for_pre: For premix module or postmix module.
+ * @get: Getting param from DSP or setting param.
+ * @ac: Set/Get from ASM session associated with this audio client.
+ * @po: Out of band memory to set or get postmix params.
+ *
+ * Set or Get params from modules in ASM session.
+ *
+ * Return: Return failure if any.
+ */
+int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd, char *buf,
+ bool for_pre, bool get, struct audio_client *ac,
+ struct param_outband *po)
+{
+ struct dts_eagle_param_desc depd_ = {0};
+ s32 ret = 0, isALSA = 0, err = 0, i, mod = for_pre ? MPRE : MPST;
+ u32 offset;
+
+ eagle_asm_dbg("%s: set/get asm", __func__);
+
+ /* special handling for ALSA route, to accommodate 64 bit platforms */
+ if (depd == NULL) {
+ long *arg_ = (long *)buf;
+
+ depd = &depd_;
+ depd->id = (u32)*arg_++;
+ depd->size = (u32)*arg_++;
+ depd->offset = (s32)*arg_++;
+ depd->device = (u32)*arg_++;
+ buf = (char *)arg_;
+ isALSA = 1;
+ }
+
+ if (depd->size & 1) {
+ eagle_asm_err("%s: parameter size %u is not a multiple of 2",
+ __func__, depd->size);
+ return -EINVAL;
+ }
+
+ if (get) {
+ void *buf_, *buf_m = NULL;
+
+ eagle_asm_dbg("%s: get requested", __func__);
+ if (depd->offset == -1) {
+ eagle_asm_dbg("%s: get from dsp requested", __func__);
+ if (depd->size > 0 && depd->size <= DEPC_MAX_SIZE) {
+ buf_ = buf_m = vzalloc(depd->size);
+ } else {
+ eagle_asm_err("%s: get size %u invalid",
+ __func__, depd->size);
+ return -EINVAL;
+ }
+ if (!buf_m) {
+ eagle_asm_err("%s: out of memory", __func__);
+ return -ENOMEM;
+ } else if (q6asm_dts_eagle_get(ac, depd->id,
+ depd->size, buf_m,
+ po, mod) < 0) {
+ eagle_asm_err("%s: asm get failed", __func__);
+ ret = -EFAULT;
+ goto DTS_EAGLE_IOCTL_GET_PARAM_PRE_EXIT;
+ }
+ eagle_asm_dbg("%s: get result: param id 0x%x value %d size %u",
+ __func__, depd->id, *(int *)buf_m, depd->size);
+ } else {
+ s32 tgt = _get_cb_for_dev(depd->device);
+
+ if (tgt < 0) {
+ eagle_asm_err("%s: no cache for device %u found",
+ __func__, depd->device);
+ return -EINVAL;
+ }
+ offset = _c_bl[tgt][CBD_OFFSG] + depd->offset;
+ /* check for integer overflow */
+ if (offset > (UINT_MAX - depd->size))
+ err = -EINVAL;
+ if ((err != 0) || (offset + depd->size) > _depc_size) {
+ eagle_asm_err("%s: invalid size %u and/or offset %u",
+ __func__, depd->size, offset);
+ return -EINVAL;
+ }
+ buf_ = (u32 *)&_depc[offset];
+ }
+ if (isALSA) {
+ if (depd->size == 2) {
+ *(long *)buf = (long)*(__u16 *)buf_;
+ eagle_asm_dbg("%s: asm out 16 bit value %li",
+ __func__, *(long *)buf);
+ } else {
+ s32 *pbuf = (s32 *)buf_;
+ long *bufl = (long *)buf;
+
+ for (i = 0; i < (depd->size >> 2); i++) {
+ *bufl++ = (long)*pbuf++;
+ eagle_asm_dbg("%s: asm out value %li",
+ __func__, *(bufl-1));
+ }
+ }
+ } else {
+ memcpy(buf, buf_, depd->size);
+ }
+DTS_EAGLE_IOCTL_GET_PARAM_PRE_EXIT:
+ vfree(buf_m);
+ return (int)ret;
+ } else {
+ s32 tgt = _get_cb_for_dev(depd->device);
+
+ if (tgt < 0) {
+ eagle_asm_err("%s: no cache for device %u found",
+ __func__, depd->device);
+ return -EINVAL;
+ }
+ offset = _c_bl[tgt][CBD_OFFSG] + depd->offset;
+ /* check for integer overflow */
+ if (offset > (UINT_MAX - depd->size))
+ err = -EINVAL;
+ if ((err != 0) || ((offset + depd->size) > _depc_size)) {
+ eagle_asm_err("%s: invalid size %u and/or offset %u for parameter (cache is size %u)",
+ __func__, depd->size, offset, _depc_size);
+ return -EINVAL;
+ }
+ if (isALSA) {
+ if (depd->size == 2) {
+ *(__u16 *)&_depc[offset] = (__u16)*(long *)buf;
+ eagle_asm_dbg("%s: asm in 16 bit value %li",
+ __func__, *(long *)buf);
+ } else {
+ s32 *pbuf = (s32 *)&_depc[offset];
+ long *bufl = (long *)buf;
+
+ for (i = 0; i < (depd->size >> 2); i++) {
+ *pbuf++ = (s32)*bufl++;
+ eagle_asm_dbg("%s: asm in value %i",
+ __func__, *(pbuf-1));
+ }
+ }
+ } else {
+ memcpy(&_depc[offset], buf, depd->size);
+ }
+ eagle_asm_dbg("%s: param info: param = 0x%X, size = %u, offset = %i, device = %u, cache block %i, global offset = %u, first bytes as integer = %i",
+ __func__, depd->id, depd->size, depd->offset,
+ depd->device,
+ tgt, offset, *(int *)&_depc[offset]);
+ if (q6asm_dts_eagle_set(ac, depd->id, depd->size,
+ (void *)&_depc[offset], po, mod))
+ eagle_asm_err("%s: q6asm_dts_eagle_set failed with id = 0x%X, size = %u, offset = %d",
+ __func__, depd->id, depd->size, depd->offset);
+ else
+ eagle_asm_dbg("%s: q6asm_dts_eagle_set succeeded with id = 0x%X, size = %u, offset = %d",
+ __func__, depd->id, depd->size, depd->offset);
+ }
+
+ return (int)ret;
+}
+
+/**
+ * msm_dts_eagle_handle_adm() - Set or Get params from ADM
+ * @depd: DTS Eagle Params structure used to set or get.
+ * @buf: Buffer to get queried param value in NT mode.
+ * @for_pre: For premix module or postmix module.
+ * @get: Getting param from DSP or setting param.
+ *
+ * Set or Get params from modules in ADM session.
+ *
+ * Return: Return failure if any.
+ */
+int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd, char *buf,
+ bool for_pre, bool get)
+{
+ u32 pid = _get_pid_from_dev(depd->device), cidx;
+ s32 ret = 0;
+
+ eagle_adm_dbg("%s: set/get adm", __func__);
+
+ if (_isNTDevice(depd->device)) {
+ eagle_adm_dbg("%s: NT Route detected", __func__);
+ ret = msm_dts_eagle_handle_asm(depd, buf, for_pre, get,
+ _getNTDeviceAC(), &_po_NT);
+ if (ret < 0)
+ eagle_adm_err("%s: NT Route set failed with id = 0x%X, size = %u, offset = %i, device = %u",
+ __func__, depd->id, depd->size, depd->offset,
+ depd->device);
+ } else if (get) {
+ cidx = adm_validate_and_get_port_index(pid);
+ eagle_adm_dbg("%s: get from qdsp requested (port id 0x%X)",
+ __func__, pid);
+ if (adm_dts_eagle_get(pid, _cidx[cidx], depd->id,
+ buf, depd->size) < 0) {
+ eagle_adm_err("%s: get from qdsp via adm with port id 0x%X failed",
+ __func__, pid);
+ return -EFAULT;
+ }
+ } else if (_is_port_open_and_eagle(pid)) {
+ cidx = adm_validate_and_get_port_index(pid);
+ eagle_adm_dbg("%s: adm_dts_eagle_set called with id = 0x%X, size = %u, offset = %i, device = %u, port id = %u, copp index = %u",
+ __func__, depd->id, depd->size, depd->offset,
+ depd->device, pid, cidx);
+ ret = adm_dts_eagle_set(pid, _cidx[cidx], depd->id,
+ (void *)buf, depd->size);
+ if (ret < 0)
+ eagle_adm_err("%s: adm_dts_eagle_set failed", __func__);
+ else
+ eagle_adm_dbg("%s: adm_dts_eagle_set succeeded",
+ __func__);
+ } else {
+ ret = -EINVAL;
+ eagle_adm_dbg("%s: port id 0x%X not active or not Eagle",
+ __func__, pid);
+ }
+ return (int)ret;
+}
+
+/**
+ * msm_dts_eagle_ioctl() - ioctl handler function
+ * @cmd: cmd to handle.
+ * @arg: argument to the cmd.
+ *
+ * Handle DTS Eagle ioctl cmds.
+ *
+ * Return: Return failure if any.
+ */
+int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg)
+{
+ s32 ret = 0;
+
+ switch (cmd) {
+ case DTS_EAGLE_IOCTL_GET_CACHE_SIZE: {
+ eagle_ioctl_info("%s: called with control 0x%X (get param cache size)",
+ __func__, cmd);
+ if (copy_to_user((void *)arg, &_depc_size,
+ sizeof(_depc_size))) {
+ eagle_ioctl_err("%s: error writing size", __func__);
+ return -EFAULT;
+ }
+ break;
+ }
+ case DTS_EAGLE_IOCTL_SET_CACHE_SIZE: {
+ u32 size = 0;
+
+ eagle_ioctl_info("%s: called with control 0x%X (allocate param cache)",
+ __func__, cmd);
+ if (copy_from_user((void *)&size, (void *)arg, sizeof(size))) {
+ eagle_ioctl_err("%s: error copying size (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, &size, sizeof(size));
+ return -EFAULT;
+ } else if (size > DEPC_MAX_SIZE) {
+ eagle_ioctl_err("%s: cache size %u not allowed (min 0, max %u)",
+ __func__, size, DEPC_MAX_SIZE);
+ return -EINVAL;
+ }
+ if (_depc) {
+ eagle_ioctl_dbg("%s: previous param cache of size %u freed",
+ __func__, _depc_size);
+ _depc_size = 0;
+ vfree(_depc);
+ _depc = NULL;
+ }
+ if (size)
+ _depc = vzalloc(size);
+ else
+ eagle_ioctl_dbg("%s: %u bytes requested for param cache, nothing allocated",
+ __func__, size);
+ if (_depc) {
+ eagle_ioctl_dbg("%s: %u bytes allocated for param cache",
+ __func__, size);
+ _depc_size = size;
+ } else {
+ eagle_ioctl_err("%s: error allocating param cache (vzalloc failed on %u bytes)",
+ __func__, size);
+ _depc_size = 0;
+ return -ENOMEM;
+ }
+ break;
+ }
+ case DTS_EAGLE_IOCTL_GET_PARAM: {
+ struct dts_eagle_param_desc depd;
+ s32 for_pre = 0, get_from_core = 0, err = 0;
+ u32 offset;
+ void *buf, *buf_m = NULL;
+
+ eagle_ioctl_info("%s: control 0x%X (get param)",
+ __func__, cmd);
+ if (copy_from_user((void *)&depd, (void *)arg, sizeof(depd))) {
+ eagle_ioctl_err("%s: error copying dts_eagle_param_desc (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, &depd, sizeof(depd));
+ return -EFAULT;
+ }
+ if (depd.device & DTS_EAGLE_FLAG_IOCTL_PRE) {
+ eagle_ioctl_dbg("%s: using for premix", __func__);
+ for_pre = 1;
+ }
+ if (depd.device & DTS_EAGLE_FLAG_IOCTL_GETFROMCORE) {
+ eagle_ioctl_dbg("%s: 'get from core' requested",
+ __func__);
+ get_from_core = 1;
+ depd.offset = -1;
+ }
+ depd.device &= DTS_EAGLE_FLAG_IOCTL_MASK;
+ if (depd.offset == -1) {
+ if (depd.size > 0 && depd.size <= DEPC_MAX_SIZE) {
+ buf = buf_m = vzalloc(depd.size);
+ } else {
+ eagle_ioctl_err("%s: get size %u invalid",
+ __func__, depd.size);
+ return -EINVAL;
+ }
+ if (!buf_m) {
+ eagle_ioctl_err("%s: out of memory", __func__);
+ return -ENOMEM;
+ }
+ if (get_from_core)
+ ret = core_dts_eagle_get(depd.id, depd.size,
+ buf);
+ else
+ ret = msm_dts_eagle_handle_adm(&depd, buf,
+ for_pre, true);
+ } else {
+ s32 cb = _get_cb_for_dev(depd.device);
+
+ if (cb < 0) {
+ eagle_ioctl_err("%s: no cache for device %u found",
+ __func__, depd.device);
+ return -EINVAL;
+ }
+ offset = _c_bl[cb][CBD_OFFSG] + depd.offset;
+ /* check for integer overflow */
+ if (offset > (UINT_MAX - depd.size))
+ err = -EINVAL;
+ if ((err != 0) ||
+ ((offset + depd.size) > _depc_size)) {
+ eagle_ioctl_err("%s: invalid size %u and/or offset %u",
+ __func__, depd.size, offset);
+ return -EINVAL;
+ }
+ buf = (void *)&_depc[offset];
+ }
+ if (ret < 0)
+ eagle_ioctl_err("%s: error %i getting data", __func__,
+ ret);
+ else if (copy_to_user((void *)(((char *)arg)+sizeof(depd)),
+ buf, depd.size)) {
+ eagle_ioctl_err("%s: error copying get data", __func__);
+ ret = -EFAULT;
+ }
+ vfree(buf_m);
+ break;
+ }
+ case DTS_EAGLE_IOCTL_SET_PARAM: {
+ struct dts_eagle_param_desc depd;
+ s32 just_set_cache = 0, for_pre = 0, err = 0;
+ u32 offset;
+ s32 tgt;
+
+ eagle_ioctl_info("%s: control 0x%X (set param)",
+ __func__, cmd);
+ if (copy_from_user((void *)&depd, (void *)arg, sizeof(depd))) {
+ eagle_ioctl_err("%s: error copying dts_eagle_param_desc (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, &depd, sizeof(depd));
+ return -EFAULT;
+ }
+ if (depd.device & DTS_EAGLE_FLAG_IOCTL_PRE) {
+ eagle_ioctl_dbg("%s: using for premix", __func__);
+ for_pre = 1;
+ }
+ if (depd.device & DTS_EAGLE_FLAG_IOCTL_JUSTSETCACHE) {
+ eagle_ioctl_dbg("%s: 'just set cache' requested",
+ __func__);
+ just_set_cache = 1;
+ }
+ depd.device &= DTS_EAGLE_FLAG_IOCTL_MASK;
+ tgt = _get_cb_for_dev(depd.device);
+ if (tgt < 0) {
+ eagle_ioctl_err("%s: no cache for device %u found",
+ __func__, depd.device);
+ return -EINVAL;
+ }
+ offset = _c_bl[tgt][CBD_OFFSG] + depd.offset;
+ /* check for integer overflow */
+ if (offset > (UINT_MAX - depd.size))
+ err = -EINVAL;
+ if ((err != 0) || ((offset + depd.size) > _depc_size)) {
+ eagle_ioctl_err("%s: invalid size %u and/or offset %u for parameter (target cache block %i with offset %i, global cache is size %u)",
+ __func__, depd.size, offset, tgt,
+ _c_bl[tgt][CBD_OFFSG], _depc_size);
+ return -EINVAL;
+ }
+ if (copy_from_user((void *)&_depc[offset],
+ (void *)(((char *)arg)+sizeof(depd)),
+ depd.size)) {
+ eagle_ioctl_err("%s: error copying param to cache (src:%pK, tgt:%pK, size:%u)",
+ __func__, ((char *)arg)+sizeof(depd),
+ &_depc[offset], depd.size);
+ return -EFAULT;
+ }
+ eagle_ioctl_dbg("%s: param info: param = 0x%X, size = %u, offset = %i, device = %u, cache block %i, global offset = %u, first bytes as integer = %i",
+ __func__, depd.id, depd.size, depd.offset,
+ depd.device, tgt, offset, *(int *)&_depc[offset]);
+ if (!just_set_cache) {
+ ret = msm_dts_eagle_handle_adm(&depd, &_depc[offset],
+ for_pre, false);
+ }
+ break;
+ }
+ case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK: {
+ u32 b_[CBD_COUNT+1], *b = &b_[1], cb;
+
+ eagle_ioctl_info("%s: with control 0x%X (set param cache block)",
+ __func__, cmd);
+ if (copy_from_user((void *)b_, (void *)arg, sizeof(b_))) {
+ eagle_ioctl_err("%s: error copying cache block data (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, b_, sizeof(b_));
+ return -EFAULT;
+ }
+ cb = b_[0];
+ if (cb >= CB_COUNT) {
+ eagle_ioctl_err("%s: cache block %u out of range (max %u)",
+ __func__, cb, CB_COUNT-1);
+ return -EINVAL;
+ }
+ eagle_ioctl_dbg("%s: cache block %i set: devices 0x%X, global offset %i, offsets 1:%u 2:%u 3:%u, cmds/sizes 0:0x%X %u 1:0x%X %u 2:0x%X %u 3:0x%X %u",
+ __func__, cb, _c_bl[cb][CBD_DEV_MASK], _c_bl[cb][CBD_OFFSG],
+ _c_bl[cb][CBD_OFFS1], _c_bl[cb][CBD_OFFS2],
+ _c_bl[cb][CBD_OFFS3], _c_bl[cb][CBD_CMD0], _c_bl[cb][CBD_SZ0],
+ _c_bl[cb][CBD_CMD1], _c_bl[cb][CBD_SZ1], _c_bl[cb][CBD_CMD2],
+ _c_bl[cb][CBD_SZ2], _c_bl[cb][CBD_CMD3], _c_bl[cb][CBD_SZ3]);
+ if ((b[CBD_OFFSG]+b[CBD_OFFS1]+b[CBD_SZ1]) > _depc_size ||
+ (b[CBD_OFFSG]+b[CBD_OFFS2]+b[CBD_SZ2]) > _depc_size ||
+ (b[CBD_OFFSG]+b[CBD_OFFS3]+b[CBD_SZ3]) > _depc_size) {
+ eagle_ioctl_err("%s: cache block bounds out of range",
+ __func__);
+ return -EINVAL;
+ }
+ memcpy(_c_bl[cb], b, sizeof(_c_bl[cb]));
+ break;
+ }
+ case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE: {
+ u32 data[2];
+
+ eagle_ioctl_dbg("%s: with control 0x%X (set active device)",
+ __func__, cmd);
+ if (copy_from_user((void *)data, (void *)arg, sizeof(data))) {
+ eagle_ioctl_err("%s: error copying active device data (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, data, sizeof(data));
+ return -EFAULT;
+ }
+ if (data[1] != 0) {
+ _device_primary = data[0];
+ eagle_ioctl_dbg("%s: primary device %i", __func__,
+ data[0]);
+ } else {
+ _device_all = data[0];
+ eagle_ioctl_dbg("%s: all devices 0x%X", __func__,
+ data[0]);
+ }
+ break;
+ }
+ case DTS_EAGLE_IOCTL_GET_LICENSE: {
+ u32 target = 0, size = 0;
+ s32 size_only;
+
+ eagle_ioctl_dbg("%s: with control 0x%X (get license)",
+ __func__, cmd);
+ if (copy_from_user((void *)&target, (void *)arg,
+ sizeof(target))) {
+ eagle_ioctl_err("%s: error reading license index. (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, &target, sizeof(target));
+ return -EFAULT;
+ }
+ size_only = target & (1<<31) ? 1 : 0;
+ target &= 0x7FFFFFFF;
+ if (target >= SEC_BLOB_MAX_CNT) {
+ eagle_ioctl_err("%s: license index %u out of bounds (max index is %i)",
+ __func__, target, SEC_BLOB_MAX_CNT);
+ return -EINVAL;
+ }
+ if (_sec_blob[target] == NULL) {
+ eagle_ioctl_err("%s: license index %u never initialized",
+ __func__, target);
+ return -EINVAL;
+ }
+ size = ((u32 *)_sec_blob[target])[0];
+ if ((size == 0) || (size > SEC_BLOB_MAX_SIZE)) {
+ eagle_ioctl_err("%s: license size %u for index %u invalid (min size is 1, max size is %u)",
+ __func__, size, target, SEC_BLOB_MAX_SIZE);
+ return -EINVAL;
+ }
+ if (size_only) {
+ eagle_ioctl_dbg("%s: reporting size of license data only",
+ __func__);
+ if (copy_to_user((void *)(((char *)arg)+sizeof(target)),
+ (void *)&size, sizeof(size))) {
+ eagle_ioctl_err("%s: error copying license size",
+ __func__);
+ return -EFAULT;
+ }
+ } else if (copy_to_user((void *)(((char *)arg)+sizeof(target)),
+ (void *)&(((s32 *)_sec_blob[target])[1]), size)) {
+ eagle_ioctl_err("%s: error copying license data",
+ __func__);
+ return -EFAULT;
+ } else {
+ eagle_ioctl_info("%s: license file %u bytes long from license index %u returned to user",
+ __func__, size, target);
+ }
+ break;
+ }
+ case DTS_EAGLE_IOCTL_SET_LICENSE: {
+ u32 target[2] = {0, 0};
+
+ eagle_ioctl_dbg("%s: control 0x%X (set license)", __func__,
+ cmd);
+ if (copy_from_user((void *)target, (void *)arg,
+ sizeof(target))) {
+ eagle_ioctl_err("%s: error reading license index (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, target, sizeof(target));
+ return -EFAULT;
+ }
+ if (target[0] >= SEC_BLOB_MAX_CNT) {
+ eagle_ioctl_err("%s: license index %u out of bounds (max index is %u)",
+ __func__, target[0], SEC_BLOB_MAX_CNT-1);
+ return -EINVAL;
+ }
+ if (target[1] == 0) {
+ eagle_ioctl_dbg("%s: request to free license index %u",
+ __func__, target[0]);
+ kfree(_sec_blob[target[0]]);
+ _sec_blob[target[0]] = NULL;
+ break;
+ }
+ if ((target[1] == 0) || (target[1] >= SEC_BLOB_MAX_SIZE)) {
+ eagle_ioctl_err("%s: license size %u for index %u invalid (min size is 1, max size is %u)",
+ __func__, target[1], target[0],
+ SEC_BLOB_MAX_SIZE);
+ return -EINVAL;
+ }
+ if (_sec_blob[target[0]] != NULL) {
+ if (((u32 *)_sec_blob[target[0]])[1] != target[1]) {
+ eagle_ioctl_dbg("%s: request new size for already allocated license index %u",
+ __func__, target[0]);
+ kfree(_sec_blob[target[0]]);
+ _sec_blob[target[0]] = NULL;
+ }
+ }
+ eagle_ioctl_dbg("%s: allocating %u bytes for license index %u",
+ __func__, target[1], target[0]);
+ _sec_blob[target[0]] = kzalloc(target[1] + 4, GFP_KERNEL);
+ if (!_sec_blob[target[0]]) {
+ eagle_ioctl_err("%s: error allocating license index %u (kzalloc failed on %u bytes)",
+ __func__, target[0], target[1]);
+ return -ENOMEM;
+ }
+ ((u32 *)_sec_blob[target[0]])[0] = target[1];
+ if (copy_from_user(
+ (void *)&(((u32 *)_sec_blob[target[0]])[1]),
+ (void *)(((char *)arg)+sizeof(target)),
+ target[1])) {
+ eagle_ioctl_err("%s: error copying license to index %u, size %u (src:%pK, tgt:%pK, size:%u)",
+ __func__, target[0], target[1],
+ ((char *)arg)+sizeof(target),
+ &(((u32 *)_sec_blob[target[0]])[1]),
+ target[1]);
+ return -EFAULT;
+ }
+ eagle_ioctl_info("%s: license file %u bytes long copied to index license index %u",
+ __func__, target[1], target[0]);
+ break;
+ }
+ case DTS_EAGLE_IOCTL_SEND_LICENSE: {
+ u32 target = 0;
+
+ eagle_ioctl_dbg("%s: control 0x%X (send license)", __func__,
+ cmd);
+ if (copy_from_user((void *)&target, (void *)arg,
+ sizeof(target))) {
+ eagle_ioctl_err("%s: error reading license index (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, &target, sizeof(target));
+ return -EFAULT;
+ }
+ if (target >= SEC_BLOB_MAX_CNT) {
+ eagle_ioctl_err("%s: license index %u out of bounds (max index is %i)",
+ __func__, target, SEC_BLOB_MAX_CNT-1);
+ return -EINVAL;
+ }
+ if (!_sec_blob[target] ||
+ ((u32 *)_sec_blob[target])[0] == 0) {
+ eagle_ioctl_err("%s: license index %u is invalid",
+ __func__, target);
+ return -EINVAL;
+ }
+ if (core_dts_eagle_set(((s32 *)_sec_blob[target])[0],
+ (char *)&((s32 *)_sec_blob[target])[1]) < 0)
+ eagle_ioctl_err("%s: core_dts_eagle_set failed with id = %u",
+ __func__, target);
+ else
+ eagle_ioctl_info("%s: core_dts_eagle_set succeeded with id = %u",
+ __func__, target);
+ break;
+ }
+ case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS: {
+ s32 spec = 0;
+
+ eagle_ioctl_info("%s: control 0x%X (set volume commands)",
+ __func__, cmd);
+ if (copy_from_user((void *)&spec, (void *)arg,
+ sizeof(spec))) {
+ eagle_ioctl_err("%s: error reading volume command specifier (src:%pK, tgt:%pK, size:%zu)",
+ __func__, (void *)arg, &spec, sizeof(spec));
+ return -EFAULT;
+ }
+ if (spec & 0x80000000) {
+ u32 idx = (spec & 0x0000F000) >> 12;
+ s32 size = spec & 0x00000FFF;
+
+ eagle_ioctl_dbg("%s: setting volume command %i size: %i",
+ __func__, idx, size);
+ if (idx >= _vol_cmd_cnt) {
+ eagle_ioctl_err("%s: volume command index %u out of bounds (only %u allocated)",
+ __func__, idx, _vol_cmd_cnt);
+ return -EINVAL;
+ }
+ if (_volume_cmds_alloc2(idx, size) < 0) {
+ eagle_ioctl_err("%s: error allocating memory for volume controls",
+ __func__);
+ return -ENOMEM;
+ }
+ if (copy_from_user((void *)&_vol_cmds_d[idx],
+ (void *)(((char *)arg) + sizeof(int)),
+ sizeof(struct vol_cmds_d))) {
+ eagle_ioctl_err("%s: error reading volume command descriptor (src:%pK, tgt:%pK, size:%zu)",
+ __func__, ((char *)arg) + sizeof(int),
+ &_vol_cmds_d[idx],
+ sizeof(struct vol_cmds_d));
+ return -EFAULT;
+ }
+ eagle_ioctl_dbg("%s: setting volume command %i spec (size %zu): %i %i %i %i",
+ __func__, idx, sizeof(struct vol_cmds_d),
+ _vol_cmds_d[idx].d[0], _vol_cmds_d[idx].d[1],
+ _vol_cmds_d[idx].d[2], _vol_cmds_d[idx].d[3]);
+ if (copy_from_user((void *)_vol_cmds[idx],
+ (void *)(((char *)arg) + (sizeof(int) +
+ sizeof(struct vol_cmds_d))), size)) {
+ eagle_ioctl_err("%s: error reading volume command string (src:%pK, tgt:%pK, size:%i)",
+ __func__, ((char *)arg) + (sizeof(int) +
+ sizeof(struct vol_cmds_d)),
+ _vol_cmds[idx], size);
+ return -EFAULT;
+ }
+ } else {
+ eagle_ioctl_dbg("%s: setting volume command size",
+ __func__);
+ if (spec < 0 || spec > VOL_CMD_CNT_MAX) {
+ eagle_ioctl_err("%s: volume command count %i out of bounds (min 0, max %i)",
+ __func__, spec, VOL_CMD_CNT_MAX);
+ return -EINVAL;
+ } else if (spec == 0) {
+ eagle_ioctl_dbg("%s: request to free volume commands",
+ __func__);
+ _volume_cmds_free();
+ break;
+ }
+ eagle_ioctl_dbg("%s: setting volume command size requested = %i",
+ __func__, spec);
+ if (_volume_cmds_alloc1(spec) < 0) {
+ eagle_ioctl_err("%s: error allocating memory for volume controls",
+ __func__);
+ return -ENOMEM;
+ }
+ }
+ break;
+ }
+ default: {
+ eagle_ioctl_err("%s: control 0x%X (invalid control)",
+ __func__, cmd);
+ ret = -EINVAL;
+ }
+ }
+ return (int)ret;
+}
+
+/**
+ * msm_dts_eagle_compat_ioctl() - To handle 32bit to 64bit ioctl compatibility
+ * @cmd: cmd to handle.
+ * @arg: argument to the cmd.
+ *
+ * Handle DTS Eagle ioctl cmds from 32bit userspace.
+ *
+ * Return: Return failure if any.
+ */
+#ifdef CONFIG_COMPAT
+int msm_dts_eagle_compat_ioctl(unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case DTS_EAGLE_IOCTL_GET_CACHE_SIZE32:
+ cmd = DTS_EAGLE_IOCTL_GET_CACHE_SIZE;
+ break;
+ case DTS_EAGLE_IOCTL_SET_CACHE_SIZE32:
+ cmd = DTS_EAGLE_IOCTL_SET_CACHE_SIZE;
+ break;
+ case DTS_EAGLE_IOCTL_GET_PARAM32:
+ cmd = DTS_EAGLE_IOCTL_GET_PARAM;
+ break;
+ case DTS_EAGLE_IOCTL_SET_PARAM32:
+ cmd = DTS_EAGLE_IOCTL_SET_PARAM;
+ break;
+ case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32:
+ cmd = DTS_EAGLE_IOCTL_SET_CACHE_BLOCK;
+ break;
+ case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32:
+ cmd = DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE;
+ break;
+ case DTS_EAGLE_IOCTL_GET_LICENSE32:
+ cmd = DTS_EAGLE_IOCTL_GET_LICENSE;
+ break;
+ case DTS_EAGLE_IOCTL_SET_LICENSE32:
+ cmd = DTS_EAGLE_IOCTL_SET_LICENSE;
+ break;
+ case DTS_EAGLE_IOCTL_SEND_LICENSE32:
+ cmd = DTS_EAGLE_IOCTL_SEND_LICENSE;
+ break;
+ case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32:
+ cmd = DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS;
+ break;
+ default:
+ break;
+ }
+ return msm_dts_eagle_ioctl(cmd, arg);
+}
+#endif
+/**
+ * msm_dts_eagle_init_pre() - Initialize DTS premix module
+ * @ac: Initialize premix module in the ASM session.
+ *
+ * Initialize DTS premix module on provided ASM session
+ *
+ * Return: Return failure if any.
+ */
+int msm_dts_eagle_init_pre(struct audio_client *ac)
+{
+ return msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
+ AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
+}
+
+/**
+ * msm_dts_eagle_deinit_pre() - Deinitialize DTS premix module
+ * @ac: Deinitialize premix module in the ASM session.
+ *
+ * Deinitialize DTS premix module on provided ASM session
+ *
+ * Return: Currently does nothing so 0.
+ */
+int msm_dts_eagle_deinit_pre(struct audio_client *ac)
+{
+ return 0;
+}
+
+/**
+ * msm_dts_eagle_init_post() - Initialize DTS postmix module
+ * @port_id: Port id for the ADM session.
+ * @copp_idx: Copp idx for the ADM session.
+ *
+ * Initialize DTS postmix module on ADM session
+ *
+ * Return: Return failure if any.
+ */
+int msm_dts_eagle_init_post(int port_id, int copp_idx)
+{
+ return msm_dts_eagle_enable_adm(port_id, copp_idx, _is_hpx_enabled);
+}
+
+/**
+ * msm_dts_eagle_deinit_post() - Deinitialize DTS postmix module
+ * @port_id: Port id for the ADM session.
+ * @topology: Topology in use.
+ *
+ * Deinitialize DTS postmix module on ADM session
+ *
+ * Return: Currently does nothing so 0.
+ */
+int msm_dts_eagle_deinit_post(int port_id, int topology)
+{
+ return 0;
+}
+
+/**
+ * msm_dts_eagle_init_master_module() - Initialize both DTS modules
+ * @ac: Initialize modules in the ASM session.
+ *
+ * Initialize DTS modules on ASM session
+ *
+ * Return: Success.
+ */
+int msm_dts_eagle_init_master_module(struct audio_client *ac)
+{
+ _set_audioclient(ac);
+ msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
+ AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
+ msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
+ AUDPROC_MODULE_ID_DTS_HPX_POSTMIX);
+ return 0;
+}
+
+/**
+ * msm_dts_eagle_deinit_master_module() - Deinitialize both DTS modules
+ * @ac: Deinitialize modules in the ASM session.
+ *
+ * Deinitialize DTS modules on ASM session
+ *
+ * Return: Success.
+ */
+int msm_dts_eagle_deinit_master_module(struct audio_client *ac)
+{
+ msm_dts_eagle_deinit_pre(ac);
+ msm_dts_eagle_deinit_post(-1, 0);
+ _clear_audioclient();
+ return 0;
+}
+
+/**
+ * msm_dts_eagle_is_hpx_on() - Check if HPX effects are On
+ *
+ * Check if HPX effects are On
+ *
+ * Return: On/Off.
+ */
+int msm_dts_eagle_is_hpx_on(void)
+{
+ return _is_hpx_enabled;
+}
+
+/**
+ * msm_dts_eagle_pcm_new() - Create hwdep node
+ * @runtime: snd_soc_pcm_runtime structure.
+ *
+ * Create hwdep node
+ *
+ * Return: Success.
+ */
+int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime)
+{
+ if (!_ref_cnt++) {
+ _init_cb_descs();
+ _reg_ion_mem();
+ }
+ return 0;
+}
+
+/**
+ * msm_dts_eagle_pcm_free() - remove hwdep node
+ * @runtime: snd_soc_pcm_runtime structure.
+ *
+ * Remove hwdep node
+ *
+ * Return: void.
+ */
+void msm_dts_eagle_pcm_free(struct snd_pcm *pcm)
+{
+ if (!--_ref_cnt)
+ _unreg_ion_mem();
+ vfree(_depc);
+}
+
+MODULE_DESCRIPTION("DTS EAGLE platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.c b/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.c
new file mode 100644
index 0000000..5c6f1df
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.c
@@ -0,0 +1,358 @@
+/* Copyright (c) 2012-2014, 2016-2017, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <linux/atomic.h>
+#include <linux/msm_audio_ion.h>
+#include <sound/control.h>
+#include <sound/q6adm-v2.h>
+#include <sound/asound.h>
+#include <sound/msm-dts-eagle.h>
+#include "msm-dts-srs-tm-config.h"
+#include "msm-pcm-routing-v2.h"
+
+static int srs_port_id[AFE_MAX_PORTS] = {-1};
+static int srs_copp_idx[AFE_MAX_PORTS] = {-1};
+static union srs_trumedia_params_u msm_srs_trumedia_params;
+static struct ion_client *ion_client;
+static struct ion_handle *ion_handle;
+static struct param_outband po;
+static atomic_t ref_cnt;
+#define ION_MEM_SIZE (8 * 1024)
+
+static int set_port_id(int port_id, int copp_idx)
+{
+ int index = adm_validate_and_get_port_index(port_id);
+
+ if (index < 0) {
+ pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
+ port_id);
+ return -EINVAL;
+ }
+ srs_port_id[index] = port_id;
+ srs_copp_idx[index] = copp_idx;
+ return 0;
+}
+
+static void msm_dts_srs_tm_send_params(__s32 port_id, __u32 techs)
+{
+ __s32 index = adm_validate_and_get_port_index(port_id);
+
+ if (index < 0) {
+ pr_err("%s: Invalid port idx %d port_id 0x%x\n",
+ __func__, index, port_id);
+ return;
+ }
+ if ((srs_copp_idx[index] < 0) ||
+ (srs_copp_idx[index] >= MAX_COPPS_PER_PORT)) {
+ pr_debug("%s: send params called before copp open. so, caching\n",
+ __func__);
+ return;
+ }
+ pr_debug("SRS %s: called, port_id = %d, techs flags = %u\n",
+ __func__, port_id, techs);
+ /* force all if techs is set to 1 */
+ if (techs == 1)
+ techs = 0xFFFFFFFF;
+
+ if (techs & (1 << SRS_ID_WOWHD))
+ srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_WOWHD,
+ (void *)&msm_srs_trumedia_params.srs_params.wowhd);
+ if (techs & (1 << SRS_ID_CSHP))
+ srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_CSHP,
+ (void *)&msm_srs_trumedia_params.srs_params.cshp);
+ if (techs & (1 << SRS_ID_HPF))
+ srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_HPF,
+ (void *)&msm_srs_trumedia_params.srs_params.hpf);
+ if (techs & (1 << SRS_ID_AEQ))
+ srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_AEQ,
+ (void *)&msm_srs_trumedia_params.srs_params.aeq);
+ if (techs & (1 << SRS_ID_HL))
+ srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_HL,
+ (void *)&msm_srs_trumedia_params.srs_params.hl);
+ if (techs & (1 << SRS_ID_GEQ))
+ srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_GEQ,
+ (void *)&msm_srs_trumedia_params.srs_params.geq);
+ if (techs & (1 << SRS_ID_GLOBAL))
+ srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_GLOBAL,
+ (void *)&msm_srs_trumedia_params.srs_params.global);
+}
+
+
+static int msm_dts_srs_trumedia_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_dts_srs_trumedia_control_set_(int port_id,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ __u16 offset, value, max = sizeof(msm_srs_trumedia_params) >> 1;
+
+ if (SRS_CMD_UPLOAD ==
+ (ucontrol->value.integer.value[0] & SRS_CMD_UPLOAD)) {
+ __u32 techs = ucontrol->value.integer.value[0] & 0xFF;
+ __s32 index = adm_validate_and_get_port_index(port_id);
+
+ if (index < 0) {
+ pr_err("%s: Invalid port idx %d port_id 0x%x\n",
+ __func__, index, port_id);
+ return -EINVAL;
+ }
+ pr_debug("SRS %s: send params request, flag = %u\n",
+ __func__, techs);
+ if (srs_port_id[index] >= 0 && techs)
+ msm_dts_srs_tm_send_params(port_id, techs);
+ return 0;
+ }
+ offset = (__u16)((ucontrol->value.integer.value[0] &
+ SRS_PARAM_OFFSET_MASK) >> 16);
+ value = (__u16)(ucontrol->value.integer.value[0] &
+ SRS_PARAM_VALUE_MASK);
+ if (offset < max) {
+ msm_srs_trumedia_params.raw_params[offset] = value;
+ pr_debug("SRS %s: index set... (max %d, requested %d, value 0x%X)\n",
+ __func__, max, offset, value);
+ } else {
+ pr_err("SRS %s: index out of bounds! (max %d, requested %d)\n",
+ __func__, max, offset);
+ }
+ return 0;
+}
+
+static int msm_dts_srs_trumedia_control_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret, port_id;
+
+ pr_debug("SRS control normal called\n");
+ msm_pcm_routing_acquire_lock();
+ port_id = SLIMBUS_0_RX;
+ ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
+ msm_pcm_routing_release_lock();
+ return ret;
+}
+
+static int msm_dts_srs_trumedia_control_i2s_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret, port_id;
+
+ pr_debug("SRS control I2S called\n");
+ msm_pcm_routing_acquire_lock();
+ port_id = PRIMARY_I2S_RX;
+ ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
+ msm_pcm_routing_release_lock();
+ return ret;
+}
+
+static int msm_dts_srs_trumedia_control_mi2s_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret, port_id;
+
+ pr_debug("SRS control MI2S called\n");
+ msm_pcm_routing_acquire_lock();
+ port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
+ ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
+ msm_pcm_routing_release_lock();
+ return ret;
+}
+
+static int msm_dts_srs_trumedia_control_hdmi_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret, port_id;
+
+ pr_debug("SRS control HDMI called\n");
+ msm_pcm_routing_acquire_lock();
+ port_id = HDMI_RX;
+ ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
+ msm_pcm_routing_release_lock();
+ return ret;
+}
+
+static const struct snd_kcontrol_new lpa_srs_trumedia_controls[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS TruMedia",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw,
+ .get = msm_dts_srs_trumedia_control_get,
+ .put = msm_dts_srs_trumedia_control_set,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
+static const struct snd_kcontrol_new lpa_srs_trumedia_controls_hdmi[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS TruMedia HDMI",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw,
+ .get = msm_dts_srs_trumedia_control_get,
+ .put = msm_dts_srs_trumedia_control_hdmi_set,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
+static const struct snd_kcontrol_new lpa_srs_trumedia_controls_i2s[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS TruMedia I2S",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw,
+ .get = msm_dts_srs_trumedia_control_get,
+ .put = msm_dts_srs_trumedia_control_i2s_set,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
+static const struct snd_kcontrol_new lpa_srs_trumedia_controls_mi2s[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS TruMedia MI2S",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw,
+ .get = msm_dts_srs_trumedia_control_get,
+ .put = msm_dts_srs_trumedia_control_mi2s_set,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {
+ .reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
+void msm_dts_srs_tm_add_controls(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform,
+ lpa_srs_trumedia_controls,
+ ARRAY_SIZE(lpa_srs_trumedia_controls));
+
+ snd_soc_add_platform_controls(platform,
+ lpa_srs_trumedia_controls_hdmi,
+ ARRAY_SIZE(lpa_srs_trumedia_controls_hdmi));
+
+ snd_soc_add_platform_controls(platform,
+ lpa_srs_trumedia_controls_i2s,
+ ARRAY_SIZE(lpa_srs_trumedia_controls_i2s));
+ snd_soc_add_platform_controls(platform,
+ lpa_srs_trumedia_controls_mi2s,
+ ARRAY_SIZE(lpa_srs_trumedia_controls_mi2s));
+}
+
+static int reg_ion_mem(void)
+{
+ int rc;
+
+ rc = msm_audio_ion_alloc("SRS_TRUMEDIA", &ion_client, &ion_handle,
+ ION_MEM_SIZE, &po.paddr, (size_t *)&po.size,
+ &po.kvaddr);
+ if (rc != 0)
+ pr_err("%s: failed to allocate memory.\n", __func__);
+ pr_debug("%s: exited ion_client = %pK, ion_handle = %pK, phys_addr = %lu, length = %d, vaddr = %pK, rc = 0x%x\n",
+ __func__, ion_client, ion_handle, (long)po.paddr,
+ (unsigned int)po.size, po.kvaddr, rc);
+ return rc;
+}
+
+void msm_dts_srs_tm_ion_memmap(struct param_outband *po_)
+{
+ if (po.kvaddr == NULL) {
+ pr_debug("%s: callingreg_ion_mem()\n", __func__);
+ reg_ion_mem();
+ }
+ po_->size = ION_MEM_SIZE;
+ po_->kvaddr = po.kvaddr;
+ po_->paddr = po.paddr;
+}
+
+static void unreg_ion_mem(void)
+{
+ msm_audio_ion_free(ion_client, ion_handle);
+ po.kvaddr = NULL;
+ po.paddr = 0;
+ po.size = 0;
+}
+
+void msm_dts_srs_tm_deinit(int port_id)
+{
+ set_port_id(port_id, -1);
+ atomic_dec(&ref_cnt);
+ if (po.kvaddr != NULL) {
+ if (!atomic_read(&ref_cnt)) {
+ pr_debug("%s: calling unreg_ion_mem()\n", __func__);
+ unreg_ion_mem();
+ }
+ }
+}
+
+void msm_dts_srs_tm_init(int port_id, int copp_idx)
+{
+ int cur_ref_cnt = 0;
+
+ if (set_port_id(port_id, copp_idx) < 0) {
+ pr_err("%s: Invalid port_id: %d\n", __func__, port_id);
+ return;
+ }
+
+ cur_ref_cnt = atomic_read(&ref_cnt);
+ atomic_inc(&ref_cnt);
+ if (!cur_ref_cnt && po.kvaddr == NULL) {
+ pr_debug("%s: calling reg_ion_mem()\n", __func__);
+ if (reg_ion_mem() != 0) {
+ atomic_dec(&ref_cnt);
+ po.kvaddr = NULL;
+ return;
+ }
+ }
+ msm_dts_srs_tm_send_params(port_id, 1);
+}
diff --git a/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.h b/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.h
new file mode 100644
index 0000000..1dd7aed
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_DTS_SRS_TM_CONFIG_H_
+#define _MSM_DTS_SRS_TM_CONFIG_H_
+
+#include <sound/soc.h>
+
+struct param_outband;
+
+#ifdef CONFIG_DTS_SRS_TM
+
+union srs_trumedia_params_u {
+ struct srs_trumedia_params srs_params;
+ __u16 raw_params[1];
+};
+
+void msm_dts_srs_tm_ion_memmap(struct param_outband *po_);
+void msm_dts_srs_tm_init(int port_id, int copp_idx);
+void msm_dts_srs_tm_deinit(int port_id);
+void msm_dts_srs_tm_add_controls(struct snd_soc_platform *platform);
+#else
+static inline void msm_dts_srs_tm_ion_memmap(struct param_outband *po_) { }
+static inline void msm_dts_srs_tm_init(int port_id, int copp_idx) { }
+static inline void msm_dts_srs_tm_deinit(int port_id) { }
+static inline void msm_dts_srs_tm_add_controls(
+ struct snd_soc_platform *platform) { }
+
+#endif
+
+#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
new file mode 100644
index 0000000..b3427a2
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -0,0 +1,1989 @@
+/*
+ * Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/freezer.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/timer.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6lsm.h>
+#include <sound/lsm_params.h>
+#include <sound/pcm_params.h>
+#include "msm-pcm-routing-v2.h"
+
+#define CAPTURE_MIN_NUM_PERIODS 2
+#define CAPTURE_MAX_NUM_PERIODS 8
+#define CAPTURE_MAX_PERIOD_SIZE 4096
+#define CAPTURE_MIN_PERIOD_SIZE 320
+#define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256
+
+#define LAB_BUFFER_ALLOC 1
+#define LAB_BUFFER_DEALLOC 0
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_16000,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
+ CAPTURE_MAX_PERIOD_SIZE,
+ .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = CAPTURE_MIN_NUM_PERIODS,
+ .periods_max = CAPTURE_MAX_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 16000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+struct lsm_priv {
+ struct snd_pcm_substream *substream;
+ struct lsm_client *lsm_client;
+ struct snd_lsm_event_status *event_status;
+ spinlock_t event_lock;
+ wait_queue_head_t event_wait;
+ unsigned long event_avail;
+ atomic_t event_wait_stop;
+ atomic_t buf_count;
+ atomic_t read_abort;
+ wait_queue_head_t period_wait;
+ int appl_cnt;
+ int dma_write;
+};
+
+static int msm_lsm_queue_lab_buffer(struct lsm_priv *prtd, int i)
+{
+ int rc = 0;
+ struct lsm_cmd_read cmd_read;
+ struct snd_soc_pcm_runtime *rtd;
+
+ if (!prtd || !prtd->lsm_client) {
+ pr_err("%s: Invalid params prtd %pK lsm client %pK\n",
+ __func__, prtd, ((!prtd) ? NULL : prtd->lsm_client));
+ return -EINVAL;
+ }
+ if (!prtd->substream || !prtd->substream->private_data) {
+ pr_err("%s: Invalid %s\n", __func__,
+ (!prtd->substream) ? "substream" : "private_data");
+ return -EINVAL;
+ }
+ rtd = prtd->substream->private_data;
+
+ if (!prtd->lsm_client->lab_buffer ||
+ i >= prtd->lsm_client->hw_params.period_count) {
+ dev_err(rtd->dev,
+ "%s: Lab buffer not setup %pK incorrect index %d period count %d\n",
+ __func__, prtd->lsm_client->lab_buffer, i,
+ prtd->lsm_client->hw_params.period_count);
+ return -EINVAL;
+ }
+ cmd_read.buf_addr_lsw =
+ lower_32_bits(prtd->lsm_client->lab_buffer[i].phys);
+ cmd_read.buf_addr_msw =
+ msm_audio_populate_upper_32_bits(
+ prtd->lsm_client->lab_buffer[i].phys);
+ cmd_read.buf_size = prtd->lsm_client->lab_buffer[i].size;
+ cmd_read.mem_map_handle =
+ prtd->lsm_client->lab_buffer[i].mem_map_handle;
+ rc = q6lsm_read(prtd->lsm_client, &cmd_read);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: error in queuing the lab buffer rc %d\n",
+ __func__, rc);
+ return rc;
+}
+
+static int lsm_lab_buffer_sanity(struct lsm_priv *prtd,
+ struct lsm_cmd_read_done *read_done, int *index)
+{
+ int i = 0, rc = -EINVAL;
+ struct snd_soc_pcm_runtime *rtd;
+
+ if (!prtd || !read_done || !index) {
+ pr_err("%s: Invalid params prtd %pK read_done %pK index %pK\n",
+ __func__, prtd, read_done, index);
+ return -EINVAL;
+ }
+
+ if (!prtd->substream || !prtd->substream->private_data) {
+ pr_err("%s: Invalid %s\n", __func__,
+ (!prtd->substream) ? "substream" : "private_data");
+ return -EINVAL;
+ }
+ rtd = prtd->substream->private_data;
+
+ if (!prtd->lsm_client->lab_enable || !prtd->lsm_client->lab_buffer) {
+ dev_err(rtd->dev,
+ "%s: Lab not enabled %d invalid lab buffer %pK\n",
+ __func__, prtd->lsm_client->lab_enable,
+ prtd->lsm_client->lab_buffer);
+ return -EINVAL;
+ }
+ for (i = 0; i < prtd->lsm_client->hw_params.period_count; i++) {
+ if ((lower_32_bits(prtd->lsm_client->lab_buffer[i].phys) ==
+ read_done->buf_addr_lsw) &&
+ (msm_audio_populate_upper_32_bits
+ (prtd->lsm_client->lab_buffer[i].phys) ==
+ read_done->buf_addr_msw) &&
+ (prtd->lsm_client->lab_buffer[i].mem_map_handle ==
+ read_done->mem_map_handle)) {
+ dev_dbg(rtd->dev,
+ "%s: Buffer found %pK memmap handle %d\n",
+ __func__, &prtd->lsm_client->lab_buffer[i].phys,
+ prtd->lsm_client->lab_buffer[i].mem_map_handle);
+ if (read_done->total_size >
+ prtd->lsm_client->lab_buffer[i].size) {
+ dev_err(rtd->dev,
+ "%s: Size mismatch call back size %d actual size %zd\n",
+ __func__, read_done->total_size,
+ prtd->lsm_client->lab_buffer[i].size);
+ rc = -EINVAL;
+ break;
+ } else {
+ *index = i;
+ rc = 0;
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+static void lsm_event_handler(uint32_t opcode, uint32_t token,
+ void *payload, void *priv)
+{
+ unsigned long flags;
+ struct lsm_priv *prtd = priv;
+ struct snd_pcm_substream *substream = prtd->substream;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_lsm_event_status *temp;
+ uint16_t status = 0;
+ uint16_t payload_size = 0;
+ uint16_t index = 0;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: Invalid %s\n", __func__,
+ (!substream) ? "substream" : "private_data");
+ return;
+ }
+ rtd = substream->private_data;
+
+ switch (opcode) {
+ case LSM_DATA_EVENT_READ_DONE: {
+ int rc;
+ struct lsm_cmd_read_done *read_done = payload;
+ int buf_index = 0;
+
+ if (prtd->lsm_client->session != token ||
+ !read_done) {
+ dev_err(rtd->dev,
+ "%s: EVENT_READ_DONE invalid callback, session %d callback %d payload %pK",
+ __func__, prtd->lsm_client->session,
+ token, read_done);
+ return;
+ }
+ if (atomic_read(&prtd->read_abort)) {
+ dev_dbg(rtd->dev,
+ "%s: read abort set skip data\n", __func__);
+ return;
+ }
+ if (!lsm_lab_buffer_sanity(prtd, read_done, &buf_index)) {
+ dev_dbg(rtd->dev,
+ "%s: process read done index %d\n",
+ __func__, buf_index);
+ if (buf_index >=
+ prtd->lsm_client->hw_params.period_count) {
+ dev_err(rtd->dev,
+ "%s: Invalid index %d buf_index max cnt %d\n",
+ __func__, buf_index,
+ prtd->lsm_client->hw_params.period_count);
+ return;
+ }
+ prtd->dma_write += read_done->total_size;
+ atomic_inc(&prtd->buf_count);
+ snd_pcm_period_elapsed(substream);
+ wake_up(&prtd->period_wait);
+ /* queue the next period buffer */
+ buf_index = (buf_index + 1) %
+ prtd->lsm_client->hw_params.period_count;
+ rc = msm_lsm_queue_lab_buffer(prtd, buf_index);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: error in queuing the lab buffer rc %d\n",
+ __func__, rc);
+ } else
+ dev_err(rtd->dev, "%s: Invalid lab buffer returned by dsp\n",
+ __func__);
+ break;
+ }
+
+ case LSM_SESSION_EVENT_DETECTION_STATUS:
+ status = (uint16_t)((uint8_t *)payload)[0];
+ payload_size = (uint16_t)((uint8_t *)payload)[2];
+ index = 4;
+ dev_dbg(rtd->dev,
+ "%s: event detect status = %d payload size = %d\n",
+ __func__, status, payload_size);
+ break;
+
+ case LSM_SESSION_EVENT_DETECTION_STATUS_V2:
+ status = (uint16_t)((uint8_t *)payload)[0];
+ payload_size = (uint16_t)((uint8_t *)payload)[1];
+ index = 2;
+ dev_dbg(rtd->dev,
+ "%s: event detect status = %d payload size = %d\n",
+ __func__, status, payload_size);
+ break;
+ default:
+ break;
+ }
+
+ if (opcode == LSM_SESSION_EVENT_DETECTION_STATUS ||
+ opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2) {
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ temp = krealloc(prtd->event_status,
+ sizeof(struct snd_lsm_event_status) +
+ payload_size, GFP_ATOMIC);
+ if (!temp) {
+ dev_err(rtd->dev, "%s: no memory for event status\n",
+ __func__);
+ return;
+ }
+
+ prtd->event_status = temp;
+ prtd->event_status->status = status;
+ prtd->event_status->payload_size = payload_size;
+ if (likely(prtd->event_status)) {
+ memcpy(prtd->event_status->payload,
+ &((uint8_t *)payload)[index],
+ payload_size);
+ prtd->event_avail = 1;
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ wake_up(&prtd->event_wait);
+ } else {
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ dev_err(rtd->dev,
+ "%s: Couldn't allocate %d bytes of memory\n",
+ __func__, payload_size);
+ }
+ if (substream->timer_running)
+ snd_timer_interrupt(substream->timer, 1);
+ }
+}
+
+static int msm_lsm_lab_buffer_alloc(struct lsm_priv *lsm, int alloc)
+{
+ int ret = 0;
+ struct snd_dma_buffer *dma_buf = NULL;
+
+ if (!lsm) {
+ pr_err("%s: Invalid param lsm %pK\n", __func__, lsm);
+ return -EINVAL;
+ }
+ if (alloc) {
+ if (!lsm->substream) {
+ pr_err("%s: substream is NULL\n", __func__);
+ return -EINVAL;
+ }
+ ret = q6lsm_lab_buffer_alloc(lsm->lsm_client, alloc);
+ if (ret) {
+ pr_err("%s: alloc lab buffer failed ret %d\n",
+ __func__, ret);
+ goto exit;
+ }
+ dma_buf = &lsm->substream->dma_buffer;
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = lsm->substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = lsm->lsm_client->lab_buffer[0].data;
+ dma_buf->addr = lsm->lsm_client->lab_buffer[0].phys;
+ dma_buf->bytes = lsm->lsm_client->hw_params.buf_sz *
+ lsm->lsm_client->hw_params.period_count;
+ snd_pcm_set_runtime_buffer(lsm->substream, dma_buf);
+ } else {
+ ret = q6lsm_lab_buffer_alloc(lsm->lsm_client, alloc);
+ if (ret)
+ pr_err("%s: free lab buffer failed ret %d\n",
+ __func__, ret);
+ kfree(lsm->lsm_client->lab_buffer);
+ lsm->lsm_client->lab_buffer = NULL;
+ }
+exit:
+ return ret;
+}
+
+static int msm_lsm_get_conf_levels(struct lsm_client *client,
+ u8 *conf_levels_ptr)
+{
+ int rc = 0;
+
+ if (client->num_confidence_levels == 0) {
+ pr_debug("%s: no confidence levels provided\n",
+ __func__);
+ client->confidence_levels = NULL;
+ goto done;
+ }
+
+ client->confidence_levels =
+ kzalloc((sizeof(uint8_t) * client->num_confidence_levels),
+ GFP_KERNEL);
+ if (!client->confidence_levels) {
+ pr_err("%s: No memory for confidence\n"
+ "levels num of level from user = %d\n",
+ __func__, client->num_confidence_levels);
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ if (copy_from_user(client->confidence_levels,
+ conf_levels_ptr,
+ client->num_confidence_levels)) {
+ pr_err("%s: copy from user failed, size = %d\n",
+ __func__, client->num_confidence_levels);
+ rc = -EFAULT;
+ goto copy_err;
+ }
+
+ return rc;
+
+copy_err:
+ kfree(client->confidence_levels);
+ client->confidence_levels = NULL;
+done:
+ return rc;
+
+}
+
+static int msm_lsm_set_epd(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int rc = 0;
+ struct snd_lsm_ep_det_thres epd_th;
+
+ if (p_info->param_size != sizeof(epd_th)) {
+ dev_err(rtd->dev,
+ "%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(&epd_th, p_info->param_data,
+ p_info->param_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed, size = %d\n",
+ __func__, p_info->param_size);
+ rc = -EFAULT;
+ goto done;
+ }
+
+ rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+ &epd_th, LSM_ENDPOINT_DETECT_THRESHOLD);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Failed to set epd param, err = %d\n",
+ __func__, rc);
+done:
+ return rc;
+}
+
+static int msm_lsm_set_mode(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_lsm_detect_mode mode;
+ int rc = 0;
+
+ if (p_info->param_size != sizeof(mode)) {
+ dev_err(rtd->dev,
+ "%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(&mode, p_info->param_data,
+ sizeof(mode))) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed, size = %zd\n",
+ __func__, sizeof(mode));
+ rc = -EFAULT;
+ goto done;
+ }
+
+ rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+ &mode, LSM_OPERATION_MODE);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Failed to set det_mode param, err = %d\n",
+ __func__, rc);
+done:
+ return rc;
+}
+
+static int msm_lsm_set_gain(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_lsm_gain gain;
+ int rc = 0;
+
+ if (p_info->param_size != sizeof(gain)) {
+ dev_err(rtd->dev,
+ "%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(&gain, p_info->param_data,
+ sizeof(gain))) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed, size = %zd\n",
+ __func__, sizeof(gain));
+ rc = -EFAULT;
+ goto done;
+ }
+
+ rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+ &gain, LSM_GAIN);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Failed to set det_mode param, err = %d\n",
+ __func__, rc);
+done:
+ return rc;
+}
+
+static int msm_lsm_set_conf(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int rc = 0;
+
+ if (p_info->param_size > MAX_NUM_CONFIDENCE) {
+ dev_err(rtd->dev,
+ "%s: invalid confidence levels %d\n",
+ __func__, p_info->param_size);
+ return -EINVAL;
+ }
+
+ prtd->lsm_client->num_confidence_levels =
+ p_info->param_size;
+ rc = msm_lsm_get_conf_levels(prtd->lsm_client,
+ p_info->param_data);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: get_conf_levels failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+ prtd->lsm_client->confidence_levels,
+ LSM_MIN_CONFIDENCE_LEVELS);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Failed to set min_conf_levels, err = %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static int msm_lsm_reg_model(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int rc = 0;
+ u8 *snd_model_ptr;
+ size_t offset;
+
+ rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
+ p_info->param_size,
+ true);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: snd_model buf alloc failed, size = %d\n",
+ __func__, p_info->param_size);
+ return rc;
+ }
+
+ q6lsm_sm_set_param_data(prtd->lsm_client, p_info, &offset);
+
+ /*
+ * For set_param, advance the sound model data with the
+ * number of bytes required by param_data.
+ */
+ snd_model_ptr = ((u8 *) prtd->lsm_client->sound_model.data) + offset;
+
+ if (copy_from_user(snd_model_ptr,
+ p_info->param_data, p_info->param_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user for snd_model failed, size = %d\n",
+ __func__, p_info->param_size);
+ rc = -EFAULT;
+ goto err_copy;
+ }
+ rc = q6lsm_set_one_param(prtd->lsm_client, p_info, NULL,
+ LSM_REG_SND_MODEL);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: Failed to set sound_model, err = %d\n",
+ __func__, rc);
+ goto err_copy;
+ }
+ return rc;
+
+err_copy:
+ q6lsm_snd_model_buf_free(prtd->lsm_client);
+ return rc;
+}
+
+static int msm_lsm_dereg_model(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int rc = 0;
+
+ rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+ NULL, LSM_DEREG_SND_MODEL);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Failed to set det_mode param, err = %d\n",
+ __func__, rc);
+
+ q6lsm_snd_model_buf_free(prtd->lsm_client);
+
+ return rc;
+}
+
+static int msm_lsm_set_custom(struct snd_pcm_substream *substream,
+ struct lsm_params_info *p_info)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ u8 *data;
+ int rc = 0;
+
+ data = kzalloc(p_info->param_size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (copy_from_user(data, p_info->param_data,
+ p_info->param_size)) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed for custom params, size = %d\n",
+ __func__, p_info->param_size);
+ rc = -EFAULT;
+ goto err_ret;
+ }
+
+ rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+ data, LSM_CUSTOM_PARAMS);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Failed to set custom param, err = %d\n",
+ __func__, rc);
+
+err_ret:
+ kfree(data);
+ return rc;
+}
+
+static int msm_lsm_process_params(struct snd_pcm_substream *substream,
+ struct snd_lsm_module_params *p_data,
+ void *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct lsm_params_info *p_info;
+ int i;
+ int rc = 0;
+
+ p_info = (struct lsm_params_info *) params;
+
+ for (i = 0; i < p_data->num_params; i++) {
+ dev_dbg(rtd->dev,
+ "%s: param (%d), module_id = 0x%x, param_id = 0x%x, param_size = 0x%x, param_type = 0x%x\n",
+ __func__, i, p_info->module_id,
+ p_info->param_id, p_info->param_size,
+ p_info->param_type);
+
+ switch (p_info->param_type) {
+ case LSM_ENDPOINT_DETECT_THRESHOLD:
+ rc = msm_lsm_set_epd(substream, p_info);
+ break;
+ case LSM_OPERATION_MODE:
+ rc = msm_lsm_set_mode(substream, p_info);
+ break;
+ case LSM_GAIN:
+ rc = msm_lsm_set_gain(substream, p_info);
+ break;
+ case LSM_MIN_CONFIDENCE_LEVELS:
+ rc = msm_lsm_set_conf(substream, p_info);
+ break;
+ case LSM_REG_SND_MODEL:
+ rc = msm_lsm_reg_model(substream, p_info);
+ break;
+ case LSM_DEREG_SND_MODEL:
+ rc = msm_lsm_dereg_model(substream, p_info);
+ break;
+ case LSM_CUSTOM_PARAMS:
+ rc = msm_lsm_set_custom(substream, p_info);
+ break;
+ default:
+ dev_err(rtd->dev,
+ "%s: Invalid param_type %d\n",
+ __func__, p_info->param_type);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ pr_err("%s: set_param fail for param_type %d\n",
+ __func__, p_info->param_type);
+ return rc;
+ }
+
+ p_info++;
+ }
+
+ return rc;
+}
+
+static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ unsigned long flags;
+ int ret;
+ struct snd_lsm_sound_model_v2 snd_model_v2;
+ struct snd_lsm_session_data session_data;
+ int rc = 0;
+ int xchg = 0;
+ u32 size = 0;
+ struct snd_pcm_runtime *runtime;
+ struct lsm_priv *prtd;
+ struct snd_lsm_event_status *user = arg;
+ struct snd_lsm_detection_params det_params;
+ uint8_t *confidence_level = NULL;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: Invalid %s\n", __func__,
+ (!substream) ? "substream" : "private_data");
+ return -EINVAL;
+ }
+
+ runtime = substream->runtime;
+ prtd = runtime->private_data;
+ rtd = substream->private_data;
+
+ switch (cmd) {
+ case SNDRV_LSM_SET_SESSION_DATA:
+ dev_dbg(rtd->dev, "%s: set session data\n", __func__);
+ memcpy(&session_data, arg,
+ sizeof(struct snd_lsm_session_data));
+ if (session_data.app_id != LSM_VOICE_WAKEUP_APP_ID_V2) {
+ dev_err(rtd->dev,
+ "%s:Invalid App id %d for Listen client\n",
+ __func__, session_data.app_id);
+ rc = -EINVAL;
+ break;
+ }
+
+ prtd->lsm_client->app_id = session_data.app_id;
+ ret = q6lsm_open(prtd->lsm_client,
+ prtd->lsm_client->app_id);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "%s: lsm open failed, %d\n",
+ __func__, ret);
+ return ret;
+ }
+ prtd->lsm_client->opened = true;
+ dev_dbg(rtd->dev, "%s: Session_ID = %d, APP ID = %d\n",
+ __func__,
+ prtd->lsm_client->session,
+ prtd->lsm_client->app_id);
+ break;
+ case SNDRV_LSM_REG_SND_MODEL_V2:
+ dev_dbg(rtd->dev, "%s: Registering sound model V2\n",
+ __func__);
+ memcpy(&snd_model_v2, arg,
+ sizeof(struct snd_lsm_sound_model_v2));
+ if (snd_model_v2.num_confidence_levels >
+ MAX_NUM_CONFIDENCE) {
+ dev_err(rtd->dev,
+ "%s: Invalid conf_levels = %d, maximum allowed = %d\n",
+ __func__, snd_model_v2.num_confidence_levels,
+ MAX_NUM_CONFIDENCE);
+ rc = -EINVAL;
+ break;
+ }
+ rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
+ snd_model_v2.data_size, false);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: q6lsm buffer alloc failed V2, size %d\n",
+ __func__, snd_model_v2.data_size);
+ break;
+ }
+ if (copy_from_user(prtd->lsm_client->sound_model.data,
+ snd_model_v2.data, snd_model_v2.data_size)) {
+ dev_err(rtd->dev,
+ "%s: copy from user data failed\n"
+ "data %pK size %d\n", __func__,
+ snd_model_v2.data, snd_model_v2.data_size);
+ q6lsm_snd_model_buf_free(prtd->lsm_client);
+ rc = -EFAULT;
+ break;
+ }
+
+ dev_dbg(rtd->dev, "SND Model Magic no byte[0] %x,\n"
+ "byte[1] %x, byte[2] %x byte[3] %x\n",
+ snd_model_v2.data[0], snd_model_v2.data[1],
+ snd_model_v2.data[2], snd_model_v2.data[3]);
+ prtd->lsm_client->num_confidence_levels =
+ snd_model_v2.num_confidence_levels;
+
+ rc = msm_lsm_get_conf_levels(prtd->lsm_client,
+ snd_model_v2.confidence_level);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: get_conf_levels failed, err = %d\n",
+ __func__, rc);
+ break;
+ }
+
+ rc = q6lsm_register_sound_model(prtd->lsm_client,
+ snd_model_v2.detection_mode,
+ snd_model_v2.detect_failure);
+ if (rc < 0) {
+ dev_err(rtd->dev,
+ "%s: Register snd Model v2 failed =%d\n",
+ __func__, rc);
+ kfree(confidence_level);
+ q6lsm_snd_model_buf_free(prtd->lsm_client);
+ }
+
+ kfree(prtd->lsm_client->confidence_levels);
+ prtd->lsm_client->confidence_levels = NULL;
+ break;
+
+ case SNDRV_LSM_SET_PARAMS:
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: %s Invalid argument\n",
+ __func__, "SNDRV_LSM_SET_PARAMS");
+ return -EINVAL;
+ }
+
+ dev_dbg(rtd->dev, "%s: set_params\n", __func__);
+ memcpy(&det_params, arg,
+ sizeof(det_params));
+ if (det_params.num_confidence_levels >
+ MAX_NUM_CONFIDENCE) {
+ rc = -EINVAL;
+ break;
+ }
+
+ prtd->lsm_client->num_confidence_levels =
+ det_params.num_confidence_levels;
+
+ rc = msm_lsm_get_conf_levels(prtd->lsm_client,
+ det_params.conf_level);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: Failed to get conf_levels, err = %d\n",
+ __func__, rc);
+ break;
+ }
+
+ rc = q6lsm_set_data(prtd->lsm_client,
+ det_params.detect_mode,
+ det_params.detect_failure);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Failed to set params, err = %d\n",
+ __func__, rc);
+
+ kfree(prtd->lsm_client->confidence_levels);
+ prtd->lsm_client->confidence_levels = NULL;
+
+ break;
+
+ case SNDRV_LSM_DEREG_SND_MODEL:
+ dev_dbg(rtd->dev, "%s: Deregistering sound model\n",
+ __func__);
+ rc = q6lsm_deregister_sound_model(prtd->lsm_client);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Sound model de-register failed, err = %d\n",
+ __func__, rc);
+ break;
+
+ case SNDRV_LSM_EVENT_STATUS:
+ dev_dbg(rtd->dev, "%s: Get event status\n", __func__);
+ atomic_set(&prtd->event_wait_stop, 0);
+ rc = wait_event_freezable(prtd->event_wait,
+ (cmpxchg(&prtd->event_avail, 1, 0) ||
+ (xchg = atomic_cmpxchg(&prtd->event_wait_stop,
+ 1, 0))));
+ dev_dbg(rtd->dev, "%s: wait_event_freezable %d event_wait_stop %d\n",
+ __func__, rc, xchg);
+ if (!rc && !xchg) {
+ dev_dbg(rtd->dev, "%s: New event available %ld\n",
+ __func__, prtd->event_avail);
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ if (prtd->event_status) {
+ size = sizeof(*(prtd->event_status)) +
+ prtd->event_status->payload_size;
+ spin_unlock_irqrestore(&prtd->event_lock,
+ flags);
+ } else {
+ spin_unlock_irqrestore(&prtd->event_lock,
+ flags);
+ rc = -EINVAL;
+ dev_err(rtd->dev,
+ "%s: prtd->event_status is NULL\n",
+ __func__);
+ break;
+ }
+ if (user->payload_size <
+ prtd->event_status->payload_size) {
+ dev_dbg(rtd->dev,
+ "%s: provided %d bytes isn't enough, needs %d bytes\n",
+ __func__, user->payload_size,
+ prtd->event_status->payload_size);
+ rc = -ENOMEM;
+ } else {
+ memcpy(user, prtd->event_status, size);
+ if (prtd->lsm_client->lab_enable
+ && !prtd->lsm_client->lab_started
+ && prtd->event_status->status ==
+ LSM_VOICE_WAKEUP_STATUS_DETECTED) {
+ atomic_set(&prtd->read_abort, 0);
+ atomic_set(&prtd->buf_count, 0);
+ prtd->appl_cnt = 0;
+ prtd->dma_write = 0;
+ rc = msm_lsm_queue_lab_buffer(prtd,
+ 0);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Queue buffer failed for lab rc = %d\n",
+ __func__, rc);
+ else
+ prtd->lsm_client->lab_started
+ = true;
+ }
+ }
+ } else if (xchg) {
+ dev_dbg(rtd->dev, "%s: Wait aborted\n", __func__);
+ rc = 0;
+ }
+ break;
+
+ case SNDRV_LSM_ABORT_EVENT:
+ dev_dbg(rtd->dev, "%s: Aborting event status wait\n",
+ __func__);
+ atomic_set(&prtd->event_wait_stop, 1);
+ wake_up(&prtd->event_wait);
+ break;
+
+ case SNDRV_LSM_START:
+ dev_dbg(rtd->dev, "%s: Starting LSM client session\n",
+ __func__);
+ if (!prtd->lsm_client->started) {
+ ret = q6lsm_start(prtd->lsm_client, true);
+ if (!ret) {
+ prtd->lsm_client->started = true;
+ dev_dbg(rtd->dev, "%s: LSM client session started\n",
+ __func__);
+ }
+ }
+ break;
+
+ case SNDRV_LSM_STOP: {
+ dev_dbg(rtd->dev,
+ "%s: Stopping LSM client session\n",
+ __func__);
+ if (prtd->lsm_client->started) {
+ if (prtd->lsm_client->lab_enable) {
+ atomic_set(&prtd->read_abort, 1);
+ if (prtd->lsm_client->lab_started) {
+ ret = q6lsm_stop_lab(prtd->lsm_client);
+ if (ret)
+ dev_err(rtd->dev,
+ "%s: stop lab failed ret %d\n",
+ __func__, ret);
+ prtd->lsm_client->lab_started = false;
+ }
+ }
+ ret = q6lsm_stop(prtd->lsm_client, true);
+ if (!ret)
+ dev_dbg(rtd->dev,
+ "%s: LSM client session stopped %d\n",
+ __func__, ret);
+ prtd->lsm_client->started = false;
+ }
+ break;
+ }
+ case SNDRV_LSM_LAB_CONTROL: {
+ u32 *enable = NULL;
+
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: Invalid param arg for ioctl %s session %d\n",
+ __func__, "SNDRV_LSM_LAB_CONTROL",
+ prtd->lsm_client->session);
+ rc = -EINVAL;
+ break;
+ }
+ enable = (int *)arg;
+ dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n",
+ __func__, "SNDRV_LSM_LAB_CONTROL", *enable);
+ if (!prtd->lsm_client->started) {
+ if (prtd->lsm_client->lab_enable == *enable) {
+ dev_dbg(rtd->dev,
+ "%s: Lab for session %d already %s\n",
+ __func__, prtd->lsm_client->session,
+ ((*enable) ? "enabled" : "disabled"));
+ rc = 0;
+ break;
+ }
+ rc = q6lsm_lab_control(prtd->lsm_client, *enable);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: ioctl %s failed rc %d to %s lab for session %d\n",
+ __func__, "SNDRV_LAB_CONTROL", rc,
+ ((*enable) ? "enable" : "disable"),
+ prtd->lsm_client->session);
+ } else {
+ rc = msm_lsm_lab_buffer_alloc(prtd,
+ ((*enable) ? LAB_BUFFER_ALLOC
+ : LAB_BUFFER_DEALLOC));
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: msm_lsm_lab_buffer_alloc failed rc %d for %s",
+ __func__, rc,
+ ((*enable) ? "ALLOC" : "DEALLOC"));
+ if (!rc)
+ prtd->lsm_client->lab_enable = *enable;
+ }
+ } else {
+ dev_err(rtd->dev, "%s: ioctl %s issued after start",
+ __func__, "SNDRV_LSM_LAB_CONTROL");
+ rc = -EINVAL;
+ }
+ break;
+ }
+ case SNDRV_LSM_STOP_LAB:
+ dev_dbg(rtd->dev, "%s: stopping LAB\n", __func__);
+ if (prtd->lsm_client->lab_enable &&
+ prtd->lsm_client->lab_started) {
+ atomic_set(&prtd->read_abort, 1);
+ rc = q6lsm_stop_lab(prtd->lsm_client);
+ if (rc)
+ dev_err(rtd->dev,
+ "%s: Lab stop failed for session %d rc %d\n",
+ __func__,
+ prtd->lsm_client->session, rc);
+ prtd->lsm_client->lab_started = false;
+ }
+ break;
+ default:
+ dev_dbg(rtd->dev,
+ "%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
+ __func__, cmd);
+ rc = snd_pcm_lib_ioctl(substream, cmd, arg);
+ break;
+ }
+
+ if (!rc)
+ dev_dbg(rtd->dev, "%s: leave (%d)\n",
+ __func__, rc);
+ else
+ dev_err(rtd->dev, "%s: cmd 0x%x failed %d\n",
+ __func__, cmd, rc);
+
+ return rc;
+}
+#ifdef CONFIG_COMPAT
+struct snd_lsm_event_status32 {
+ u16 status;
+ u16 payload_size;
+ u8 payload[0];
+};
+
+struct snd_lsm_sound_model_v2_32 {
+ compat_uptr_t data;
+ compat_uptr_t confidence_level;
+ u32 data_size;
+ enum lsm_detection_mode detection_mode;
+ u8 num_confidence_levels;
+ bool detect_failure;
+};
+
+struct snd_lsm_detection_params_32 {
+ compat_uptr_t conf_level;
+ enum lsm_detection_mode detect_mode;
+ u8 num_confidence_levels;
+ bool detect_failure;
+};
+
+struct lsm_params_info_32 {
+ u32 module_id;
+ u32 param_id;
+ u32 param_size;
+ compat_uptr_t param_data;
+ enum LSM_PARAM_TYPE param_type;
+};
+
+struct snd_lsm_module_params_32 {
+ compat_uptr_t params;
+ u32 num_params;
+ u32 data_size;
+};
+
+enum {
+ SNDRV_LSM_EVENT_STATUS32 =
+ _IOW('U', 0x02, struct snd_lsm_event_status32),
+ SNDRV_LSM_REG_SND_MODEL_V2_32 =
+ _IOW('U', 0x07, struct snd_lsm_sound_model_v2_32),
+ SNDRV_LSM_SET_PARAMS_32 =
+ _IOW('U', 0x0A, struct snd_lsm_detection_params_32),
+ SNDRV_LSM_SET_MODULE_PARAMS_32 =
+ _IOW('U', 0x0B, struct snd_lsm_module_params_32),
+};
+
+static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
+ unsigned int cmd, void __user *arg)
+{
+ struct snd_pcm_runtime *runtime;
+ struct lsm_priv *prtd;
+ struct snd_soc_pcm_runtime *rtd;
+ int err = 0;
+ u32 size = 0;
+
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: Invalid %s\n", __func__,
+ (!substream) ? "substream" : "private_data");
+ return -EINVAL;
+ }
+ runtime = substream->runtime;
+ rtd = substream->private_data;
+ prtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_LSM_EVENT_STATUS32: {
+ struct snd_lsm_event_status32 userarg32, *user32 = NULL;
+ struct snd_lsm_event_status *user = NULL;
+
+ if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
+ dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
+ __func__, "SNDRV_LSM_EVENT_STATUS32");
+ return -EFAULT;
+ }
+
+ if (userarg32.payload_size >
+ LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
+ pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
+ __func__, userarg32.payload_size,
+ LISTEN_MAX_STATUS_PAYLOAD_SIZE);
+ return -EINVAL;
+ }
+
+ size = sizeof(*user) + userarg32.payload_size;
+ user = kmalloc(size, GFP_KERNEL);
+ if (!user) {
+ dev_err(rtd->dev,
+ "%s: Allocation failed event status size %d\n",
+ __func__, size);
+ return -EFAULT;
+ } else {
+ cmd = SNDRV_LSM_EVENT_STATUS;
+ user->payload_size = userarg32.payload_size;
+ err = msm_lsm_ioctl_shared(substream, cmd, user);
+ }
+
+ /* Update size with actual payload size */
+ size = sizeof(userarg32) + user->payload_size;
+ if (!err && !access_ok(VERIFY_WRITE, arg, size)) {
+ dev_err(rtd->dev,
+ "%s: write verify failed size %d\n",
+ __func__, size);
+ err = -EFAULT;
+ }
+ if (!err) {
+ user32 = kmalloc(size, GFP_KERNEL);
+ if (!user32) {
+ dev_err(rtd->dev,
+ "%s: Allocation event user status size %d\n",
+ __func__, size);
+ err = -EFAULT;
+ } else {
+ user32->status = user->status;
+ user32->payload_size = user->payload_size;
+ memcpy(user32->payload,
+ user->payload, user32->payload_size);
+ }
+ }
+ if (!err && (copy_to_user(arg, user32, size))) {
+ dev_err(rtd->dev, "%s: failed to copy payload %d",
+ __func__, size);
+ err = -EFAULT;
+ }
+ kfree(user);
+ kfree(user32);
+ if (err)
+ dev_err(rtd->dev, "%s: lsmevent failed %d",
+ __func__, err);
+ break;
+ }
+
+ case SNDRV_LSM_REG_SND_MODEL_V2_32: {
+ struct snd_lsm_sound_model_v2_32 snd_modelv232;
+ struct snd_lsm_sound_model_v2 snd_modelv2;
+
+ if (prtd->lsm_client->use_topology) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if using topology\n",
+ __func__, "REG_SND_MODEL_V2");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&snd_modelv232, arg,
+ sizeof(snd_modelv232))) {
+ err = -EFAULT;
+ dev_err(rtd->dev,
+ "%s: copy user failed, size %zd %s\n",
+ __func__,
+ sizeof(struct snd_lsm_sound_model_v2_32),
+ "SNDRV_LSM_REG_SND_MODEL_V2_32");
+ } else {
+ snd_modelv2.confidence_level =
+ compat_ptr(snd_modelv232.confidence_level);
+ snd_modelv2.data = compat_ptr(snd_modelv232.data);
+ snd_modelv2.data_size = snd_modelv232.data_size;
+ snd_modelv2.detect_failure =
+ snd_modelv232.detect_failure;
+ snd_modelv2.detection_mode =
+ snd_modelv232.detection_mode;
+ snd_modelv2.num_confidence_levels =
+ snd_modelv232.num_confidence_levels;
+ cmd = SNDRV_LSM_REG_SND_MODEL_V2;
+ err = msm_lsm_ioctl_shared(substream, cmd,
+ &snd_modelv2);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: ioctl %s failed\n", __func__,
+ "SNDDRV_LSM_REG_SND_MODEL_V2_32");
+ }
+ break;
+ }
+
+ case SNDRV_LSM_SET_PARAMS_32:{
+ struct snd_lsm_detection_params_32 det_params32;
+ struct snd_lsm_detection_params det_params;
+
+ if (prtd->lsm_client->use_topology) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if using topology\n",
+ __func__, "SET_PARAMS_32");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&det_params32, arg,
+ sizeof(det_params32))) {
+ err = -EFAULT;
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %zd\n",
+ __func__, "SNDRV_LSM_SET_PARAMS_32",
+ sizeof(det_params32));
+ } else {
+ det_params.conf_level =
+ compat_ptr(det_params32.conf_level);
+ det_params.detect_mode =
+ det_params32.detect_mode;
+ det_params.num_confidence_levels =
+ det_params32.num_confidence_levels;
+ det_params.detect_failure =
+ det_params32.detect_failure;
+ cmd = SNDRV_LSM_SET_PARAMS;
+ err = msm_lsm_ioctl_shared(substream, cmd,
+ &det_params);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: ioctl %s failed\n", __func__,
+ "SNDRV_LSM_SET_PARAMS");
+ }
+ break;
+ }
+
+ case SNDRV_LSM_SET_MODULE_PARAMS_32: {
+ struct snd_lsm_module_params_32 p_data_32;
+ struct snd_lsm_module_params p_data;
+ u8 *params, *params32;
+ size_t p_size;
+ struct lsm_params_info_32 *p_info_32;
+ struct lsm_params_info *p_info;
+ int i;
+
+ if (!prtd->lsm_client->use_topology) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if not using topology\n",
+ __func__, "SET_MODULE_PARAMS_32");
+ return -EINVAL;
+ }
+
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: %s: No Param data to set\n",
+ __func__, "SET_MODULE_PARAMS_32");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&p_data_32, arg,
+ sizeof(p_data_32))) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %zd\n",
+ __func__, "SET_MODULE_PARAMS_32",
+ sizeof(p_data_32));
+ return -EFAULT;
+ }
+
+ p_data.params = compat_ptr(p_data_32.params);
+ p_data.num_params = p_data_32.num_params;
+ p_data.data_size = p_data_32.data_size;
+
+ if (p_data.num_params > LSM_PARAMS_MAX) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid num_params %d\n",
+ __func__, "SET_MODULE_PARAMS_32",
+ p_data.num_params);
+ return -EINVAL;
+ }
+
+ if (p_data.data_size !=
+ (p_data.num_params * sizeof(struct lsm_params_info_32))) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid size %d\n",
+ __func__, "SET_MODULE_PARAMS_32",
+ p_data.data_size);
+ return -EINVAL;
+ }
+
+ p_size = sizeof(struct lsm_params_info_32) *
+ p_data.num_params;
+
+ params32 = kzalloc(p_size, GFP_KERNEL);
+ if (!params32)
+ return -ENOMEM;
+
+ p_size = sizeof(struct lsm_params_info) * p_data.num_params;
+ params = kzalloc(p_size, GFP_KERNEL);
+ if (!params) {
+ dev_err(rtd->dev,
+ "%s: no memory for params, size = %zd\n",
+ __func__, p_size);
+ kfree(params32);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(params32, p_data.params,
+ p_data.data_size)) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %d\n",
+ __func__, "params32", p_data.data_size);
+ kfree(params32);
+ kfree(params);
+ return -EFAULT;
+ }
+
+ p_info_32 = (struct lsm_params_info_32 *) params32;
+ p_info = (struct lsm_params_info *) params;
+ for (i = 0; i < p_data.num_params; i++) {
+ p_info->module_id = p_info_32->module_id;
+ p_info->param_id = p_info_32->param_id;
+ p_info->param_size = p_info_32->param_size;
+ p_info->param_data = compat_ptr(p_info_32->param_data);
+ p_info->param_type = p_info_32->param_type;
+
+ p_info_32++;
+ p_info++;
+ }
+
+ err = msm_lsm_process_params(substream,
+ &p_data, params);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: Failed to process params, err = %d\n",
+ __func__, err);
+ kfree(params);
+ kfree(params32);
+ break;
+ }
+ default:
+ err = msm_lsm_ioctl_shared(substream, cmd, arg);
+ break;
+ }
+ return err;
+}
+#else
+#define msm_lsm_ioctl_compat NULL
+#endif
+
+static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ int err = 0;
+ u32 size = 0;
+ struct snd_lsm_session_data session_data;
+ struct snd_pcm_runtime *runtime;
+ struct snd_soc_pcm_runtime *rtd;
+ struct lsm_priv *prtd;
+
+ if (!substream || !substream->private_data) {
+ pr_err("%s: Invalid %s\n", __func__,
+ (!substream) ? "substream" : "private_data");
+ return -EINVAL;
+ }
+ runtime = substream->runtime;
+ prtd = runtime->private_data;
+ rtd = substream->private_data;
+
+ switch (cmd) {
+ case SNDRV_LSM_SET_SESSION_DATA:
+ dev_dbg(rtd->dev,
+ "%s: SNDRV_LSM_SET_SESSION_DATA\n",
+ __func__);
+ if (copy_from_user(&session_data, (void *)arg,
+ sizeof(struct snd_lsm_session_data))) {
+ err = -EFAULT;
+ dev_err(rtd->dev,
+ "%s: copy from user failed, size %zd\n",
+ __func__, sizeof(struct snd_lsm_session_data));
+ break;
+ }
+ if (!err)
+ err = msm_lsm_ioctl_shared(substream,
+ cmd, &session_data);
+ if (err)
+ dev_err(rtd->dev,
+ "%s REG_SND_MODEL failed err %d\n",
+ __func__, err);
+ break;
+ case SNDRV_LSM_REG_SND_MODEL_V2: {
+ struct snd_lsm_sound_model_v2 snd_model_v2;
+
+ if (prtd->lsm_client->use_topology) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if using topology\n",
+ __func__, "REG_SND_MODEL_V2");
+ return -EINVAL;
+ }
+
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: Invalid params snd_model\n", __func__);
+ return -EINVAL;
+ }
+ if (copy_from_user(&snd_model_v2, arg, sizeof(snd_model_v2))) {
+ err = -EFAULT;
+ dev_err(rtd->dev,
+ "%s: copy from user failed, size %zd\n",
+ __func__,
+ sizeof(struct snd_lsm_sound_model_v2));
+ }
+ if (!err)
+ err = msm_lsm_ioctl_shared(substream, cmd,
+ &snd_model_v2);
+ if (err)
+ dev_err(rtd->dev,
+ "%s REG_SND_MODEL failed err %d\n",
+ __func__, err);
+ return err;
+ }
+ break;
+ case SNDRV_LSM_SET_PARAMS: {
+ struct snd_lsm_detection_params det_params;
+
+ if (prtd->lsm_client->use_topology) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if using topology\n",
+ __func__, "SET_PARAMS");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: SNDRV_LSM_SET_PARAMS\n", __func__);
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: %s, Invalid params\n",
+ __func__, "SNDRV_LSM_SET_PARAMS");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&det_params, arg,
+ sizeof(det_params))) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size %zd\n",
+ __func__, "SNDRV_LSM_SET_PARAMS",
+ sizeof(det_params));
+ err = -EFAULT;
+ }
+
+ if (!err)
+ err = msm_lsm_ioctl_shared(substream, cmd,
+ &det_params);
+ else
+ dev_err(rtd->dev,
+ "%s: LSM_SET_PARAMS failed, err %d\n",
+ __func__, err);
+ return err;
+ }
+
+ case SNDRV_LSM_SET_MODULE_PARAMS: {
+ struct snd_lsm_module_params p_data;
+ size_t p_size;
+ u8 *params;
+
+ if (!prtd->lsm_client->use_topology) {
+ dev_err(rtd->dev,
+ "%s: %s: not supported if not using topology\n",
+ __func__, "SET_MODULE_PARAMS");
+ return -EINVAL;
+ }
+
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: %s: No Param data to set\n",
+ __func__, "SET_MODULE_PARAMS");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&p_data, arg,
+ sizeof(p_data))) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %zd\n",
+ __func__, "p_data", sizeof(p_data));
+ return -EFAULT;
+ }
+
+ if (p_data.num_params > LSM_PARAMS_MAX) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid num_params %d\n",
+ __func__, "SET_MODULE_PARAMS",
+ p_data.num_params);
+ return -EINVAL;
+ }
+
+ p_size = p_data.num_params *
+ sizeof(struct lsm_params_info);
+
+ if (p_data.data_size != p_size) {
+ dev_err(rtd->dev,
+ "%s: %s: Invalid size %zd\n",
+ __func__, "SET_MODULE_PARAMS", p_size);
+
+ return -EFAULT;
+ }
+
+ params = kzalloc(p_size, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ if (copy_from_user(params, p_data.params,
+ p_data.data_size)) {
+ dev_err(rtd->dev,
+ "%s: %s: copy_from_user failed, size = %d\n",
+ __func__, "params", p_data.data_size);
+ kfree(params);
+ return -EFAULT;
+ }
+
+ err = msm_lsm_process_params(substream, &p_data, params);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: %s: Failed to set params, err = %d\n",
+ __func__, "SET_MODULE_PARAMS", err);
+ kfree(params);
+ break;
+ }
+
+ case SNDRV_LSM_EVENT_STATUS: {
+ struct snd_lsm_event_status *user = NULL, userarg;
+
+ dev_dbg(rtd->dev,
+ "%s: SNDRV_LSM_EVENT_STATUS\n", __func__);
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: Invalid params event status\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (copy_from_user(&userarg, arg, sizeof(userarg))) {
+ dev_err(rtd->dev,
+ "%s: err copyuser event_status\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (userarg.payload_size >
+ LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
+ pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
+ __func__, userarg.payload_size,
+ LISTEN_MAX_STATUS_PAYLOAD_SIZE);
+ return -EINVAL;
+ }
+
+ size = sizeof(struct snd_lsm_event_status) +
+ userarg.payload_size;
+ user = kmalloc(size, GFP_KERNEL);
+ if (!user) {
+ dev_err(rtd->dev,
+ "%s: Allocation failed event status size %d\n",
+ __func__, size);
+ return -EFAULT;
+ }
+ user->payload_size = userarg.payload_size;
+ err = msm_lsm_ioctl_shared(substream, cmd, user);
+
+ /* Update size with actual payload size */
+ size = sizeof(*user) + user->payload_size;
+ if (!err && !access_ok(VERIFY_WRITE, arg, size)) {
+ dev_err(rtd->dev,
+ "%s: write verify failed size %d\n",
+ __func__, size);
+ err = -EFAULT;
+ }
+ if (!err && (copy_to_user(arg, user, size))) {
+ dev_err(rtd->dev,
+ "%s: failed to copy payload %d",
+ __func__, size);
+ err = -EFAULT;
+ }
+ kfree(user);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: lsmevent failed %d", __func__, err);
+ return err;
+ }
+ default:
+ err = msm_lsm_ioctl_shared(substream, cmd, arg);
+ break;
+ }
+ return err;
+}
+
+static int msm_lsm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL);
+ if (!prtd) {
+ pr_err("%s: Failed to allocate memory for lsm_priv\n",
+ __func__);
+ return -ENOMEM;
+ }
+ spin_lock_init(&prtd->event_lock);
+ init_waitqueue_head(&prtd->event_wait);
+ init_waitqueue_head(&prtd->period_wait);
+ prtd->substream = substream;
+ runtime->private_data = prtd;
+ runtime->hw = msm_pcm_hardware_capture;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret < 0)
+ pr_info("%s: snd_pcm_hw_constraint_list failed ret %d\n",
+ __func__, ret);
+ /* Ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ pr_info("%s: snd_pcm_hw_constraint_integer failed ret %d\n",
+ __func__, ret);
+
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
+ CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
+ if (ret < 0)
+ pr_info("%s: constraint for buffer bytes min max ret = %d\n",
+ __func__, ret);
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+ if (ret < 0) {
+ pr_info("%s: constraint for period bytes step ret = %d\n",
+ __func__, ret);
+ }
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+ if (ret < 0)
+ pr_info("%s: constraint for buffer bytes step ret = %d\n",
+ __func__, ret);
+ prtd->lsm_client = q6lsm_client_alloc(
+ (lsm_app_cb)lsm_event_handler, prtd);
+ if (!prtd->lsm_client) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ runtime->private_data = NULL;
+ return -ENOMEM;
+ }
+ prtd->lsm_client->opened = false;
+ return 0;
+}
+
+static int msm_lsm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd;
+
+ if (!substream->private_data) {
+ pr_err("%s: Invalid private_data", __func__);
+ return -EINVAL;
+ }
+
+ rtd = prtd->substream->private_data;
+
+ if (!prtd->lsm_client) {
+ dev_err(rtd->dev,
+ "%s: LSM client data ptr is NULL\n", __func__);
+ return -EINVAL;
+ }
+ prtd->lsm_client->started = false;
+ runtime->private_data = prtd;
+ return 0;
+}
+
+static int msm_lsm_close(struct snd_pcm_substream *substream)
+{
+ unsigned long flags;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
+
+ if (!substream->private_data) {
+ pr_err("%s: Invalid private_data", __func__);
+ return -EINVAL;
+ }
+ if (!prtd || !prtd->lsm_client) {
+ pr_err("%s: No LSM session active\n", __func__);
+ return -EINVAL;
+ }
+ rtd = substream->private_data;
+
+ dev_dbg(rtd->dev, "%s\n", __func__);
+ if (prtd->lsm_client->started) {
+ ret = q6lsm_stop(prtd->lsm_client, true);
+ if (ret)
+ dev_err(rtd->dev,
+ "%s: session stop failed, err = %d\n",
+ __func__, ret);
+ else
+ dev_dbg(rtd->dev,
+ "%s: LSM client session stopped %d\n",
+ __func__, ret);
+
+ /*
+ * Go Ahead and try de-register sound model,
+ * even if stop failed
+ */
+ prtd->lsm_client->started = false;
+
+ ret = q6lsm_deregister_sound_model(prtd->lsm_client);
+ if (ret)
+ dev_err(rtd->dev,
+ "%s: dereg_snd_model failed, err = %d\n",
+ __func__, ret);
+ else
+ dev_dbg(rtd->dev, "%s: dereg_snd_model successful\n",
+ __func__);
+ }
+
+ if (prtd->lsm_client->opened) {
+ q6lsm_close(prtd->lsm_client);
+ prtd->lsm_client->opened = false;
+ }
+ q6lsm_client_free(prtd->lsm_client);
+
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ kfree(prtd->event_status);
+ prtd->event_status = NULL;
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ kfree(prtd);
+ runtime->private_data = NULL;
+
+ return 0;
+}
+
+static int msm_lsm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct lsm_lab_hw_params *hw_params = NULL;
+ struct snd_soc_pcm_runtime *rtd;
+
+ if (!substream->private_data) {
+ pr_err("%s: Invalid private_data", __func__);
+ return -EINVAL;
+ }
+ rtd = substream->private_data;
+
+ if (!prtd || !params) {
+ dev_err(rtd->dev,
+ "%s: invalid params prtd %pK params %pK",
+ __func__, prtd, params);
+ return -EINVAL;
+ }
+ hw_params = &prtd->lsm_client->hw_params;
+ hw_params->sample_rate = params_rate(params);
+ hw_params->sample_size =
+ (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 0;
+ hw_params->period_count = params_periods(params);
+ if (hw_params->sample_rate != 16000 || hw_params->sample_size != 16 ||
+ hw_params->period_count == 0) {
+ dev_err(rtd->dev,
+ "%s: Invalid params sample rate %d sample size %d period count %d",
+ __func__, hw_params->sample_rate,
+ hw_params->sample_size,
+ hw_params->period_count);
+ return -EINVAL;
+ }
+ hw_params->buf_sz = params_buffer_bytes(params) /
+ hw_params->period_count;
+ dev_dbg(rtd->dev,
+ "%s: sample rate %d sample size %d buffer size %d period count %d\n",
+ __func__, hw_params->sample_rate, hw_params->sample_size,
+ hw_params->buf_sz, hw_params->period_count);
+ return 0;
+}
+
+static snd_pcm_uframes_t msm_lsm_pcm_pointer(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd;
+
+ if (!substream->private_data) {
+ pr_err("%s: Invalid private_data", __func__);
+ return -EINVAL;
+ }
+ rtd = substream->private_data;
+
+ if (!prtd) {
+ dev_err(rtd->dev,
+ "%s: Invalid param %pK\n", __func__, prtd);
+ return 0;
+ }
+
+ if (prtd->dma_write >= snd_pcm_lib_buffer_bytes(substream))
+ prtd->dma_write = 0;
+ dev_dbg(rtd->dev,
+ "%s: dma post = %d\n", __func__, prtd->dma_write);
+ return bytes_to_frames(runtime, prtd->dma_write);
+}
+
+static int msm_lsm_pcm_copy(struct snd_pcm_substream *substream, int ch,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ char *pcm_buf = NULL;
+ int fbytes = 0, rc = 0;
+ struct snd_soc_pcm_runtime *rtd;
+
+ if (!substream->private_data) {
+ pr_err("%s: Invalid private_data", __func__);
+ return -EINVAL;
+ }
+ rtd = substream->private_data;
+
+ if (!prtd) {
+ dev_err(rtd->dev,
+ "%s: Invalid param %pK\n", __func__, prtd);
+ return -EINVAL;
+ }
+
+ fbytes = frames_to_bytes(runtime, frames);
+ if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
+ runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
+ dev_err(rtd->dev,
+ "%s: runtime state incorrect %d", __func__,
+ runtime->status->state);
+ return 0;
+ }
+ rc = wait_event_timeout(prtd->period_wait,
+ (atomic_read(&prtd->buf_count) |
+ atomic_read(&prtd->read_abort)), (2 * HZ));
+ if (!rc) {
+ dev_err(rtd->dev,
+ "%s: timeout for read retry\n", __func__);
+ return -EAGAIN;
+ }
+ if (atomic_read(&prtd->read_abort)) {
+ dev_err(rtd->dev,
+ "%s: Read abort received\n", __func__);
+ return -EIO;
+ }
+ prtd->appl_cnt = prtd->appl_cnt %
+ prtd->lsm_client->hw_params.period_count;
+ pcm_buf = prtd->lsm_client->lab_buffer[prtd->appl_cnt].data;
+ dev_dbg(rtd->dev,
+ "%s: copy the pcm data size %d\n",
+ __func__, fbytes);
+ if (pcm_buf) {
+ if (copy_to_user(buf, pcm_buf, fbytes)) {
+ dev_err(rtd->dev,
+ "%s: failed to copy bytes %d\n",
+ __func__, fbytes);
+ return -EINVAL;
+ }
+ } else {
+ dev_err(rtd->dev,
+ "%s: Invalid pcm buffer\n", __func__);
+ return -EINVAL;
+ }
+ prtd->appl_cnt = (prtd->appl_cnt + 1) %
+ prtd->lsm_client->hw_params.period_count;
+ atomic_dec(&prtd->buf_count);
+ return 0;
+}
+
+static struct snd_pcm_ops msm_lsm_ops = {
+ .open = msm_lsm_open,
+ .close = msm_lsm_close,
+ .ioctl = msm_lsm_ioctl,
+ .prepare = msm_lsm_prepare,
+ .compat_ioctl = msm_lsm_ioctl_compat,
+ .hw_params = msm_lsm_hw_params,
+ .copy = msm_lsm_pcm_copy,
+ .pointer = msm_lsm_pcm_pointer,
+};
+
+static int msm_asoc_lsm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ return 0;
+}
+
+static int msm_asoc_lsm_probe(struct snd_soc_platform *platform)
+{
+ pr_debug("enter %s\n", __func__);
+
+ return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_lsm_ops,
+ .pcm_new = msm_asoc_lsm_new,
+ .probe = msm_asoc_lsm_probe,
+};
+
+static int msm_lsm_probe(struct platform_device *pdev)
+{
+
+ return snd_soc_register_platform(&pdev->dev, &msm_soc_platform);
+}
+
+static int msm_lsm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id msm_lsm_client_dt_match[] = {
+ {.compatible = "qcom,msm-lsm-client" },
+ { }
+};
+
+static struct platform_driver msm_lsm_driver = {
+ .driver = {
+ .name = "msm-lsm-client",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(msm_lsm_client_dt_match),
+ },
+ .probe = msm_lsm_probe,
+ .remove = msm_lsm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_lsm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_lsm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("LSM client platform driver");
+MODULE_DEVICE_TABLE(of, msm_lsm_client_dt_match);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
new file mode 100644
index 0000000..4ea8abb
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -0,0 +1,921 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6adm-v2.h>
+#include <asm/dma.h>
+#include "msm-pcm-afe-v2.h"
+
+#define MIN_PLAYBACK_PERIOD_SIZE (128 * 2)
+#define MAX_PLAYBACK_PERIOD_SIZE (128 * 2 * 2 * 6)
+#define MIN_PLAYBACK_NUM_PERIODS (4)
+#define MAX_PLAYBACK_NUM_PERIODS (384)
+
+#define MIN_CAPTURE_PERIOD_SIZE (128 * 2)
+#define MAX_CAPTURE_PERIOD_SIZE (192 * 2 * 2 * 8 * 4)
+#define MIN_CAPTURE_NUM_PERIODS (4)
+#define MAX_CAPTURE_NUM_PERIODS (384)
+
+static struct snd_pcm_hardware msm_afe_hardware_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE|
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = (SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 6,
+ .buffer_bytes_max = MAX_PLAYBACK_PERIOD_SIZE *
+ MAX_PLAYBACK_NUM_PERIODS,
+ .period_bytes_min = MIN_PLAYBACK_PERIOD_SIZE,
+ .period_bytes_max = MAX_PLAYBACK_PERIOD_SIZE,
+ .periods_min = MIN_PLAYBACK_NUM_PERIODS,
+ .periods_max = MAX_PLAYBACK_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware msm_afe_hardware_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE|
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = (SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 6,
+ .buffer_bytes_max = MAX_CAPTURE_PERIOD_SIZE *
+ MAX_CAPTURE_NUM_PERIODS,
+ .period_bytes_min = MIN_CAPTURE_PERIOD_SIZE,
+ .period_bytes_max = MAX_CAPTURE_PERIOD_SIZE,
+ .periods_min = MIN_CAPTURE_NUM_PERIODS,
+ .periods_max = MAX_CAPTURE_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+
+static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt);
+static enum hrtimer_restart afe_hrtimer_rec_callback(struct hrtimer *hrt);
+
+static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt)
+{
+ struct pcm_afe_info *prtd =
+ container_of(hrt, struct pcm_afe_info, hrt);
+ struct snd_pcm_substream *substream = prtd->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u32 mem_map_handle = 0;
+
+ mem_map_handle = afe_req_mmap_handle(prtd->audio_client);
+ if (!mem_map_handle)
+ pr_err("%s: mem_map_handle is NULL\n", __func__);
+
+ if (prtd->start) {
+ pr_debug("sending frame to DSP: poll_time: %d\n",
+ prtd->poll_time);
+ if (prtd->dsp_cnt == runtime->periods)
+ prtd->dsp_cnt = 0;
+ pr_debug("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle);
+ afe_rt_proxy_port_write(
+ (prtd->dma_addr +
+ (prtd->dsp_cnt *
+ snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle,
+ snd_pcm_lib_period_bytes(prtd->substream));
+ prtd->dsp_cnt++;
+ hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time
+ * 1000));
+
+ return HRTIMER_RESTART;
+ } else
+ return HRTIMER_NORESTART;
+}
+static enum hrtimer_restart afe_hrtimer_rec_callback(struct hrtimer *hrt)
+{
+ struct pcm_afe_info *prtd =
+ container_of(hrt, struct pcm_afe_info, hrt);
+ struct snd_pcm_substream *substream = prtd->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u32 mem_map_handle = 0;
+ int ret;
+
+ mem_map_handle = afe_req_mmap_handle(prtd->audio_client);
+ if (!mem_map_handle)
+ pr_err("%s: mem_map_handle is NULL\n", __func__);
+
+ if (prtd->start) {
+ if (prtd->dsp_cnt == runtime->periods)
+ prtd->dsp_cnt = 0;
+ pr_debug("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle);
+ ret = afe_rt_proxy_port_read(
+ (prtd->dma_addr + (prtd->dsp_cnt
+ * snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle,
+ snd_pcm_lib_period_bytes(prtd->substream));
+ if (ret < 0) {
+ pr_err("%s: AFE port read fails: %d\n", __func__, ret);
+ prtd->start = 0;
+ return HRTIMER_NORESTART;
+ }
+ prtd->dsp_cnt++;
+ pr_debug("sending frame rec to DSP: poll_time: %d\n",
+ prtd->poll_time);
+ hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time
+ * 1000));
+
+ return HRTIMER_RESTART;
+ } else
+ return HRTIMER_NORESTART;
+}
+static void pcm_afe_process_tx_pkt(uint32_t opcode,
+ uint32_t token, uint32_t *payload,
+ void *priv)
+{
+ struct pcm_afe_info *prtd = priv;
+ unsigned long dsp_flags;
+ struct snd_pcm_substream *substream = NULL;
+ struct snd_pcm_runtime *runtime = NULL;
+ uint16_t event;
+ uint64_t period_bytes;
+ uint64_t bytes_one_sec;
+
+ if (prtd == NULL)
+ return;
+ substream = prtd->substream;
+ runtime = substream->runtime;
+ pr_debug("%s\n", __func__);
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ switch (opcode) {
+ case AFE_EVENT_RT_PROXY_PORT_STATUS: {
+ event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10);
+ switch (event) {
+ case AFE_EVENT_RTPORT_START: {
+ prtd->dsp_cnt = 0;
+ /* Calculate poll time.
+ * Split steps to avoid overflow.
+ * Poll time-time corresponding to one period
+ * in bytes.
+ * (Samplerate * channelcount * format) =
+ * bytes in 1 sec.
+ * Poll time =
+ * (period bytes / bytes in one sec) *
+ * 1000000 micro seconds.
+ * Multiplication by 1000000 is done in two
+ * steps to keep the accuracy of poll time.
+ */
+ if (prtd->mmap_flag) {
+ period_bytes = ((uint64_t)(
+ (snd_pcm_lib_period_bytes(
+ prtd->substream)) *
+ 1000));
+ bytes_one_sec = (runtime->rate
+ * runtime->channels * 2);
+ bytes_one_sec =
+ div_u64(bytes_one_sec, 1000);
+ prtd->poll_time =
+ div_u64(period_bytes,
+ bytes_one_sec);
+ pr_debug("prtd->poll_time: %d",
+ prtd->poll_time);
+ }
+ break;
+ }
+ case AFE_EVENT_RTPORT_STOP:
+ pr_debug("%s: event!=0\n", __func__);
+ prtd->start = 0;
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+ break;
+ case AFE_EVENT_RTPORT_LOW_WM:
+ pr_debug("%s: Underrun\n", __func__);
+ break;
+ case AFE_EVENT_RTPORT_HI_WM:
+ pr_debug("%s: Overrun\n", __func__);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2:
+ pr_debug("write done\n");
+ prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
+ (prtd->substream);
+ snd_pcm_period_elapsed(prtd->substream);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case RESET_EVENTS:
+ prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
+ (prtd->substream);
+ prtd->reset_event = true;
+ snd_pcm_period_elapsed(prtd->substream);
+ break;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+}
+
+static void pcm_afe_process_rx_pkt(uint32_t opcode,
+ uint32_t token, uint32_t *payload,
+ void *priv)
+{
+ struct pcm_afe_info *prtd = priv;
+ unsigned long dsp_flags;
+ struct snd_pcm_substream *substream = NULL;
+ struct snd_pcm_runtime *runtime = NULL;
+ uint16_t event;
+ uint64_t period_bytes;
+ uint64_t bytes_one_sec;
+ uint32_t mem_map_handle = 0;
+
+ if (prtd == NULL)
+ return;
+ substream = prtd->substream;
+ runtime = substream->runtime;
+ pr_debug("%s\n", __func__);
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ switch (opcode) {
+ case AFE_EVENT_RT_PROXY_PORT_STATUS: {
+ event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10);
+ switch (event) {
+ case AFE_EVENT_RTPORT_START: {
+ prtd->dsp_cnt = 0;
+ /* Calculate poll time. Split steps to avoid overflow.
+ * Poll time-time corresponding to one period in bytes.
+ * (Samplerate * channelcount * format)=bytes in 1 sec.
+ * Poll time = (period bytes / bytes in one sec) *
+ * 1000000 micro seconds.
+ * Multiplication by 1000000 is done in two steps to
+ * keep the accuracy of poll time.
+ */
+ if (prtd->mmap_flag) {
+ period_bytes = ((uint64_t)(
+ (snd_pcm_lib_period_bytes(
+ prtd->substream)) * 1000));
+ bytes_one_sec = (runtime->rate *
+ runtime->channels * 2);
+ bytes_one_sec = div_u64(bytes_one_sec, 1000);
+ prtd->poll_time =
+ div_u64(period_bytes, bytes_one_sec);
+ pr_debug("prtd->poll_time : %d\n",
+ prtd->poll_time);
+ } else {
+ mem_map_handle =
+ afe_req_mmap_handle(prtd->audio_client);
+ if (!mem_map_handle)
+ pr_err("%s:mem_map_handle is NULL\n",
+ __func__);
+ /* Do initial read to start transfer */
+ afe_rt_proxy_port_read((prtd->dma_addr +
+ (prtd->dsp_cnt *
+ snd_pcm_lib_period_bytes(
+ prtd->substream))),
+ mem_map_handle,
+ snd_pcm_lib_period_bytes(
+ prtd->substream));
+ prtd->dsp_cnt++;
+ }
+ break;
+ }
+ case AFE_EVENT_RTPORT_STOP:
+ pr_debug("%s: event!=0\n", __func__);
+ prtd->start = 0;
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+ break;
+ case AFE_EVENT_RTPORT_LOW_WM:
+ pr_debug("%s: Underrun\n", __func__);
+ break;
+ case AFE_EVENT_RTPORT_HI_WM:
+ pr_debug("%s: Overrun\n", __func__);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2:
+ pr_debug("%s :Read done\n", __func__);
+ prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
+ (prtd->substream);
+ if (!prtd->mmap_flag) {
+ atomic_set(&prtd->rec_bytes_avail, 1);
+ wake_up(&prtd->read_wait);
+ }
+ snd_pcm_period_elapsed(prtd->substream);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case RESET_EVENTS:
+ prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
+ (prtd->substream);
+ prtd->reset_event = true;
+ if (!prtd->mmap_flag) {
+ atomic_set(&prtd->rec_bytes_avail, 1);
+ wake_up(&prtd->read_wait);
+ }
+ snd_pcm_period_elapsed(prtd->substream);
+ break;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+}
+
+static int msm_afe_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s: sample_rate=%d\n", __func__, runtime->rate);
+
+ pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+ ret = afe_register_get_events(dai->id,
+ pcm_afe_process_tx_pkt, prtd);
+ if (ret < 0) {
+ pr_err("afe-pcm:register for events failed\n");
+ return ret;
+ }
+ pr_debug("%s:success\n", __func__);
+ prtd->prepared++;
+ return ret;
+}
+
+static int msm_afe_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+ ret = afe_register_get_events(dai->id,
+ pcm_afe_process_rx_pkt, prtd);
+ if (ret < 0) {
+ pr_err("afe-pcm:register for events failed\n");
+ return ret;
+ }
+ pr_debug("%s:success\n", __func__);
+ prtd->prepared++;
+ return 0;
+}
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 8000, 16000, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static int msm_afe_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = NULL;
+ int ret = 0;
+
+ prtd = kzalloc(sizeof(struct pcm_afe_info), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+ pr_debug("prtd %pK\n", prtd);
+
+ mutex_init(&prtd->lock);
+ spin_lock_init(&prtd->dsp_lock);
+ prtd->dsp_cnt = 0;
+
+ mutex_lock(&prtd->lock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = msm_afe_hardware_playback;
+ else
+ runtime->hw = msm_afe_hardware_capture;
+
+ prtd->substream = substream;
+ runtime->private_data = prtd;
+ prtd->audio_client = q6afe_audio_client_alloc(prtd);
+ if (!prtd->audio_client) {
+ pr_debug("%s: Could not allocate memory\n", __func__);
+ mutex_unlock(&prtd->lock);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+
+ atomic_set(&prtd->rec_bytes_avail, 0);
+ init_waitqueue_head(&prtd->read_wait);
+
+ hrtimer_init(&prtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd->hrt.function = afe_hrtimer_callback;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->hrt.function = afe_hrtimer_rec_callback;
+
+ mutex_unlock(&prtd->lock);
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret < 0)
+ pr_err("snd_pcm_hw_constraint_list failed\n");
+ /* Ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ pr_err("snd_pcm_hw_constraint_integer failed\n");
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ MIN_CAPTURE_NUM_PERIODS * MIN_CAPTURE_PERIOD_SIZE,
+ MAX_CAPTURE_NUM_PERIODS * MAX_CAPTURE_PERIOD_SIZE);
+
+ if (ret < 0) {
+ pr_err("constraint for buffer bytes min max ret = %d\n",
+ ret);
+ }
+ }
+
+ prtd->reset_event = false;
+ return 0;
+}
+
+static int msm_afe_playback_copy(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t hwoff,
+ void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+ char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
+ u32 mem_map_handle = 0;
+
+ pr_debug("%s : appl_ptr 0x%lx hw_ptr 0x%lx dest_to_copy 0x%pK\n",
+ __func__,
+ runtime->control->appl_ptr, runtime->status->hw_ptr, hwbuf);
+
+ if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) {
+ pr_err("%s :Failed to copy audio from user buffer\n",
+ __func__);
+
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ if (!prtd->mmap_flag) {
+ mem_map_handle = afe_req_mmap_handle(prtd->audio_client);
+ if (!mem_map_handle) {
+ pr_err("%s: mem_map_handle is NULL\n", __func__);
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ pr_debug("%s : prtd-> dma_addr 0x%lx dsp_cnt %d\n", __func__,
+ prtd->dma_addr, prtd->dsp_cnt);
+
+ if (prtd->dsp_cnt == runtime->periods)
+ prtd->dsp_cnt = 0;
+
+ ret = afe_rt_proxy_port_write(
+ (prtd->dma_addr + (prtd->dsp_cnt *
+ snd_pcm_lib_period_bytes(prtd->substream))),
+ mem_map_handle,
+ snd_pcm_lib_period_bytes(prtd->substream));
+
+ if (ret) {
+ pr_err("%s: AFE proxy port write failed %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ prtd->dsp_cnt++;
+ }
+fail:
+ return ret;
+}
+
+static int msm_afe_capture_copy(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t hwoff,
+ void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+ char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
+ u32 mem_map_handle = 0;
+
+ if (!prtd->mmap_flag) {
+ mem_map_handle = afe_req_mmap_handle(prtd->audio_client);
+
+ if (!mem_map_handle) {
+ pr_err("%s: mem_map_handle is NULL\n", __func__);
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ if (prtd->dsp_cnt == runtime->periods)
+ prtd->dsp_cnt = 0;
+
+ ret = afe_rt_proxy_port_read((prtd->dma_addr +
+ (prtd->dsp_cnt *
+ snd_pcm_lib_period_bytes(prtd->substream))),
+ mem_map_handle,
+ snd_pcm_lib_period_bytes(prtd->substream));
+
+ if (ret) {
+ pr_err("%s: AFE proxy port read failed %d\n",
+ __func__, ret);
+ goto fail;
+ }
+
+ prtd->dsp_cnt++;
+ ret = wait_event_timeout(prtd->read_wait,
+ atomic_read(&prtd->rec_bytes_avail), 5 * HZ);
+ if (ret < 0) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+
+ ret = -ETIMEDOUT;
+ goto fail;
+ }
+ atomic_set(&prtd->rec_bytes_avail, 0);
+ }
+ pr_debug("%s:appl_ptr 0x%lx hw_ptr 0x%lx src_to_copy 0x%pK\n",
+ __func__, runtime->control->appl_ptr,
+ runtime->status->hw_ptr, hwbuf);
+
+ if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) {
+ pr_err("%s: copy to user failed\n", __func__);
+
+ goto fail;
+ ret = -EFAULT;
+ }
+
+fail:
+ return ret;
+}
+
+static int msm_afe_copy(struct snd_pcm_substream *substream, int channel,
+ snd_pcm_uframes_t hwoff, void __user *buf,
+ snd_pcm_uframes_t frames)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+
+ int ret = 0;
+
+ if (prtd->reset_event) {
+ pr_debug("%s: reset events received from ADSP, return error\n",
+ __func__);
+ return -ENETRESET;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_afe_playback_copy(substream, channel, hwoff,
+ buf, frames);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_afe_capture_copy(substream, channel, hwoff,
+ buf, frames);
+ return ret;
+}
+
+static int msm_afe_close(struct snd_pcm_substream *substream)
+{
+ int rc = 0;
+ struct snd_dma_buffer *dma_buf;
+ struct snd_pcm_runtime *runtime;
+ struct pcm_afe_info *prtd;
+ struct snd_soc_pcm_runtime *rtd = NULL;
+ struct snd_soc_dai *dai = NULL;
+ int dir = IN;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ if (substream == NULL) {
+ pr_err("substream is NULL\n");
+ return -EINVAL;
+ }
+ rtd = substream->private_data;
+ dai = rtd->cpu_dai;
+ runtime = substream->runtime;
+ prtd = runtime->private_data;
+
+ mutex_lock(&prtd->lock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dir = IN;
+ ret = afe_unregister_get_events(dai->id);
+ if (ret < 0)
+ pr_err("AFE unregister for events failed\n");
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ dir = OUT;
+ ret = afe_unregister_get_events(dai->id);
+ if (ret < 0)
+ pr_err("AFE unregister for events failed\n");
+ }
+ if (prtd->mmap_flag)
+ hrtimer_cancel(&prtd->hrt);
+
+ rc = afe_cmd_memory_unmap(afe_req_mmap_handle(prtd->audio_client));
+ if (rc < 0)
+ pr_err("AFE memory unmap failed\n");
+
+ pr_debug("release all buffer\n");
+ dma_buf = &substream->dma_buffer;
+ if (dma_buf == NULL) {
+ pr_debug("dma_buf is NULL\n");
+ goto done;
+ }
+
+ if (dma_buf->area)
+ dma_buf->area = NULL;
+ q6afe_audio_client_buf_free_contiguous(dir, prtd->audio_client);
+done:
+ pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+ q6afe_audio_client_free(prtd->audio_client);
+ mutex_unlock(&prtd->lock);
+ prtd->prepared--;
+ kfree(prtd);
+ return 0;
+}
+static int msm_afe_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+
+ prtd->pcm_irq_pos = 0;
+ if (prtd->prepared)
+ return 0;
+ mutex_lock(&prtd->lock);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_afe_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_afe_capture_prepare(substream);
+ mutex_unlock(&prtd->lock);
+ return ret;
+}
+static int msm_afe_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+ struct afe_audio_client *ac = prtd->audio_client;
+ struct afe_audio_port_data *apd = ac->port;
+ struct afe_audio_buffer *ab;
+ int dir = -1;
+
+ pr_debug("%s\n", __func__);
+ prtd->mmap_flag = 1;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ab = &(apd[dir].buf[0]);
+
+ return msm_audio_ion_mmap((struct audio_buffer *)ab, vma);
+}
+static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
+ prtd->start = 1;
+ if (prtd->mmap_flag)
+ hrtimer_start(&prtd->hrt, ns_to_ktime(0),
+ HRTIMER_MODE_REL);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);
+ prtd->start = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+static int msm_afe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct pcm_afe_info *prtd = runtime->private_data;
+ struct afe_audio_buffer *buf;
+ int dir, rc;
+
+ pr_debug("%s:\n", __func__);
+
+ mutex_lock(&prtd->lock);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+
+ rc = q6afe_audio_client_buf_alloc_contiguous(dir,
+ prtd->audio_client,
+ (params_buffer_bytes(params) / params_periods(params)),
+ params_periods(params));
+ pr_debug("params_buffer_bytes(params) = %d\n",
+ (params_buffer_bytes(params)));
+ pr_debug("params_periods(params) = %d\n",
+ (params_periods(params)));
+ pr_debug("params_periodsize(params) = %d\n",
+ (params_buffer_bytes(params) / params_periods(params)));
+
+ if (rc < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n", rc);
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+ buf = prtd->audio_client->port[dir].buf;
+
+ if (buf == NULL || buf[0].data == NULL) {
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+
+ pr_debug("%s:buf = %pK\n", __func__, buf);
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = buf[0].data;
+ dma_buf->addr = buf[0].phys;
+
+ dma_buf->bytes = params_buffer_bytes(params);
+
+ if (!dma_buf->area) {
+ pr_err("%s:MSM AFE physical memory allocation failed\n",
+ __func__);
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+
+ memset(dma_buf->area, 0, params_buffer_bytes(params));
+
+ prtd->dma_addr = (phys_addr_t) dma_buf->addr;
+
+ mutex_unlock(&prtd->lock);
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ rc = afe_memory_map(dma_buf->addr, dma_buf->bytes, prtd->audio_client);
+ if (rc < 0)
+ pr_err("fail to map memory to DSP\n");
+
+ return rc;
+}
+static snd_pcm_uframes_t msm_afe_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_afe_info *prtd = runtime->private_data;
+
+ if (prtd->pcm_irq_pos >= snd_pcm_lib_buffer_bytes(substream))
+ prtd->pcm_irq_pos = 0;
+
+ if (prtd->reset_event) {
+ pr_debug("%s: reset events received from ADSP, return XRUN\n",
+ __func__);
+ return SNDRV_PCM_POS_XRUN;
+ }
+
+ pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+ return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static struct snd_pcm_ops msm_afe_ops = {
+ .open = msm_afe_open,
+ .copy = msm_afe_copy,
+ .hw_params = msm_afe_hw_params,
+ .trigger = msm_afe_trigger,
+ .close = msm_afe_close,
+ .prepare = msm_afe_prepare,
+ .mmap = msm_afe_mmap,
+ .pointer = msm_afe_pointer,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static int msm_afe_afe_probe(struct snd_soc_platform *platform)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_afe_ops,
+ .pcm_new = msm_asoc_pcm_new,
+ .probe = msm_afe_afe_probe,
+};
+
+static int msm_afe_probe(struct platform_device *pdev)
+{
+
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_afe_remove(struct platform_device *pdev)
+{
+ pr_debug("%s\n", __func__);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+static const struct of_device_id msm_pcm_afe_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-afe"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_pcm_afe_dt_match);
+
+static struct platform_driver msm_afe_driver = {
+ .driver = {
+ .name = "msm-pcm-afe",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_afe_dt_match,
+ },
+ .probe = msm_afe_probe,
+ .remove = msm_afe_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ pr_debug("%s\n", __func__);
+ return platform_driver_register(&msm_afe_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ pr_debug("%s\n", __func__);
+ platform_driver_unregister(&msm_afe_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("AFE PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
new file mode 100644
index 0000000..84a4c3c
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2012,2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_PCM_AFE_H
+#define _MSM_PCM_AFE_H
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+
+
+struct pcm_afe_info {
+ unsigned long dma_addr;
+ struct snd_pcm_substream *substream;
+ unsigned int pcm_irq_pos; /* IRQ position */
+ struct mutex lock;
+ spinlock_t dsp_lock;
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+ uint8_t start;
+ uint32_t dsp_cnt;
+ uint32_t buf_phys;
+ int32_t mmap_flag;
+ int prepared;
+ struct hrtimer hrt;
+ int poll_time;
+ struct afe_audio_client *audio_client;
+ wait_queue_head_t read_wait;
+ atomic_t rec_bytes_avail;
+ bool reset_event;
+};
+
+
+#define MSM_EXT(xname, fp_info, fp_get, fp_put, addr) \
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .name = xname, \
+ .info = fp_info,\
+ .get = fp_get, .put = fp_put, \
+ .private_value = addr, \
+ }
+
+#endif /*_MSM_PCM_AFE_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-dtmf-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-dtmf-v2.c
new file mode 100644
index 0000000..000ad0e
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-dtmf-v2.c
@@ -0,0 +1,596 @@
+/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/q6afe-v2.h>
+
+#include "msm-pcm-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+#include "q6voice.h"
+
+enum {
+ DTMF_IN_RX,
+ DTMF_IN_TX,
+};
+
+enum format {
+ FORMAT_S16_LE = 2
+};
+
+struct dtmf_det_info {
+ char session[MAX_SESSION_NAME_LEN];
+ uint8_t dir;
+ uint16_t high_freq;
+ uint16_t low_freq;
+};
+
+struct dtmf_buf_node {
+ struct list_head list;
+ struct dtmf_det_info dtmf_det_pkt;
+};
+
+enum dtmf_state {
+ DTMF_GEN_RX_STOPPED,
+ DTMF_GEN_RX_STARTED,
+};
+
+#define DTMF_MAX_Q_LEN 10
+#define DTMF_PKT_SIZE sizeof(struct dtmf_det_info)
+
+struct dtmf_drv_info {
+ enum dtmf_state state;
+ struct snd_pcm_substream *capture_substream;
+
+ struct list_head out_queue;
+ struct list_head free_out_queue;
+
+ wait_queue_head_t out_wait;
+
+ struct mutex lock;
+ spinlock_t dsp_lock;
+
+ uint8_t capture_start;
+ uint8_t capture_instance;
+
+ unsigned int pcm_capture_size;
+ unsigned int pcm_capture_count;
+ unsigned int pcm_capture_irq_pos;
+ unsigned int pcm_capture_buf_pos;
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = (sizeof(struct dtmf_buf_node) * DTMF_MAX_Q_LEN),
+ .period_bytes_min = DTMF_PKT_SIZE,
+ .period_bytes_max = DTMF_PKT_SIZE,
+ .periods_min = DTMF_MAX_Q_LEN,
+ .periods_max = DTMF_MAX_Q_LEN,
+ .fifo_size = 0,
+};
+
+static int msm_dtmf_rx_generate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint16_t low_freq = ucontrol->value.integer.value[0];
+ uint16_t high_freq = ucontrol->value.integer.value[1];
+ int64_t duration = ucontrol->value.integer.value[2];
+ uint16_t gain = ucontrol->value.integer.value[3];
+
+ pr_debug("%s: low_freq=%d high_freq=%d duration=%d gain=%d\n",
+ __func__, low_freq, high_freq, (int)duration, gain);
+ afe_dtmf_generate_rx(duration, high_freq, low_freq, gain);
+ return 0;
+}
+
+static int msm_dtmf_rx_generate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s:\n", __func__);
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_dtmf_detect_voice_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int enable = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: enable=%d\n", __func__, enable);
+ voc_enable_dtmf_rx_detection(voc_get_session_id(VOICE_SESSION_NAME),
+ enable);
+
+ return 0;
+}
+
+static int msm_dtmf_detect_voice_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_dtmf_detect_volte_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int enable = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: enable=%d\n", __func__, enable);
+ voc_enable_dtmf_rx_detection(voc_get_session_id(VOLTE_SESSION_NAME),
+ enable);
+
+ return 0;
+}
+
+static int msm_dtmf_detect_volte_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static struct snd_kcontrol_new msm_dtmf_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DTMF_Generate Rx Low High Duration Gain",
+ SND_SOC_NOPM, 0, 5000, 0, 4,
+ msm_dtmf_rx_generate_get,
+ msm_dtmf_rx_generate_put),
+ SOC_SINGLE_EXT("DTMF_Detect Rx Voice enable", SND_SOC_NOPM, 0, 1, 0,
+ msm_dtmf_detect_voice_rx_get,
+ msm_dtmf_detect_voice_rx_put),
+ SOC_SINGLE_EXT("DTMF_Detect Rx VoLTE enable", SND_SOC_NOPM, 0, 1, 0,
+ msm_dtmf_detect_volte_rx_get,
+ msm_dtmf_detect_volte_rx_put),
+};
+
+static int msm_pcm_dtmf_probe(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, msm_dtmf_controls,
+ ARRAY_SIZE(msm_dtmf_controls));
+ return 0;
+}
+
+static void dtmf_rx_detected_cb(uint8_t *pkt,
+ char *session,
+ void *private_data)
+{
+ struct dtmf_buf_node *buf_node = NULL;
+ struct vss_istream_evt_rx_dtmf_detected *dtmf_det_pkt =
+ (struct vss_istream_evt_rx_dtmf_detected *)pkt;
+ struct dtmf_drv_info *prtd = private_data;
+ unsigned long dsp_flags;
+
+ pr_debug("%s\n", __func__);
+ if (prtd->capture_substream == NULL)
+ return;
+
+ /* Copy dtmf detected info into out_queue. */
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ /* discarding dtmf detection info till start is received */
+ if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
+ buf_node = list_first_entry(&prtd->free_out_queue,
+ struct dtmf_buf_node, list);
+ list_del(&buf_node->list);
+ buf_node->dtmf_det_pkt.high_freq = dtmf_det_pkt->high_freq;
+ buf_node->dtmf_det_pkt.low_freq = dtmf_det_pkt->low_freq;
+ if (session != NULL)
+ strlcpy(buf_node->dtmf_det_pkt.session,
+ session, MAX_SESSION_NAME_LEN);
+
+ buf_node->dtmf_det_pkt.dir = DTMF_IN_RX;
+ pr_debug("high =%d, low=%d session=%s\n",
+ buf_node->dtmf_det_pkt.high_freq,
+ buf_node->dtmf_det_pkt.low_freq,
+ buf_node->dtmf_det_pkt.session);
+ list_add_tail(&buf_node->list, &prtd->out_queue);
+ prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ snd_pcm_period_elapsed(prtd->capture_substream);
+ } else {
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ pr_err("DTMF detection pkt in Rx dropped, no free node available\n");
+ }
+
+ wake_up(&prtd->out_wait);
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t hwoff,
+ void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ int count = 0;
+ struct dtmf_buf_node *buf_node = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+ unsigned long dsp_flags;
+
+ count = frames_to_bytes(runtime, frames);
+
+ ret = wait_event_interruptible_timeout(prtd->out_wait,
+ (!list_empty(&prtd->out_queue)),
+ 1 * HZ);
+
+ if (ret > 0) {
+ if (count <= DTMF_PKT_SIZE) {
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ buf_node = list_first_entry(&prtd->out_queue,
+ struct dtmf_buf_node, list);
+ list_del(&buf_node->list);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ ret = copy_to_user(buf,
+ &buf_node->dtmf_det_pkt,
+ count);
+ if (ret) {
+ pr_err("%s: Copy to user returned %d\n",
+ __func__, ret);
+ ret = -EFAULT;
+ }
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ list_add_tail(&buf_node->list,
+ &prtd->free_out_queue);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+
+ } else {
+ pr_err("%s: Read count %d > DTMF_PKT_SIZE\n",
+ __func__, count);
+ ret = -ENOMEM;
+ }
+ } else if (ret == 0) {
+ pr_err("%s: No UL data available\n", __func__);
+ ret = -ETIMEDOUT;
+ } else {
+ pr_err("%s: Read was interrupted\n", __func__);
+ ret = -ERESTARTSYS;
+ }
+ return ret;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+
+ pr_debug("%s() DTMF\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+
+ return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = NULL;
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ prtd = kzalloc(sizeof(struct dtmf_drv_info), GFP_KERNEL);
+
+ if (prtd == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ mutex_init(&prtd->lock);
+ spin_lock_init(&prtd->dsp_lock);
+ init_waitqueue_head(&prtd->out_wait);
+ INIT_LIST_HEAD(&prtd->out_queue);
+ INIT_LIST_HEAD(&prtd->free_out_queue);
+
+ runtime->hw = msm_pcm_hardware;
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+ prtd->capture_substream = substream;
+ prtd->capture_instance++;
+ runtime->private_data = prtd;
+ }
+
+done:
+ return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct list_head *ptr = NULL;
+ struct list_head *next = NULL;
+ struct dtmf_buf_node *buf_node = NULL;
+ struct snd_dma_buffer *c_dma_buf;
+ struct snd_pcm_substream *c_substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+ unsigned long dsp_flags;
+
+ pr_debug("%s() DTMF\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mutex_lock(&prtd->lock);
+ wake_up(&prtd->out_wait);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->capture_instance--;
+
+ if (!prtd->capture_instance) {
+ if (prtd->state == DTMF_GEN_RX_STARTED) {
+ prtd->state = DTMF_GEN_RX_STOPPED;
+ voc_disable_dtmf_det_on_active_sessions();
+ voc_register_dtmf_rx_detection_cb(NULL, NULL);
+ }
+ /* release all buffer */
+ /* release out_queue and free_out_queue */
+ pr_debug("release all buffer\n");
+ c_substream = prtd->capture_substream;
+ if (c_substream == NULL) {
+ pr_debug("c_substream is NULL\n");
+ mutex_unlock(&prtd->lock);
+ return -EINVAL;
+ }
+
+ c_dma_buf = &c_substream->dma_buffer;
+ if (c_dma_buf == NULL) {
+ pr_debug("c_dma_buf is NULL.\n");
+ mutex_unlock(&prtd->lock);
+ return -EINVAL;
+ }
+
+ if (c_dma_buf->area != NULL) {
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ list_for_each_safe(ptr, next,
+ &prtd->out_queue) {
+ buf_node = list_entry(ptr,
+ struct dtmf_buf_node, list);
+ list_del(&buf_node->list);
+ }
+
+ list_for_each_safe(ptr, next,
+ &prtd->free_out_queue) {
+ buf_node = list_entry(ptr,
+ struct dtmf_buf_node, list);
+ list_del(&buf_node->list);
+ }
+
+ spin_unlock_irqrestore(&prtd->dsp_lock,
+ dsp_flags);
+ dma_free_coherent(c_substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max,
+ c_dma_buf->area,
+ c_dma_buf->addr);
+ c_dma_buf->area = NULL;
+ }
+ }
+ prtd->capture_substream = NULL;
+ mutex_unlock(&prtd->lock);
+ }
+
+ return ret;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct dtmf_buf_node *buf_node = NULL;
+ int i = 0, offset = 0;
+ int ret = 0;
+
+ pr_debug("%s: DTMF\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mutex_lock(&prtd->lock);
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+
+ dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max,
+ &dma_buf->addr, GFP_KERNEL);
+ if (!dma_buf->area) {
+ pr_err("%s:MSM DTMF dma_alloc failed\n", __func__);
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+
+ dma_buf->bytes = runtime->hw.buffer_bytes_max;
+ memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+
+ for (i = 0; i < DTMF_MAX_Q_LEN; i++) {
+ pr_debug("node =%d\n", i);
+ buf_node = (void *) dma_buf->area + offset;
+ list_add_tail(&buf_node->list,
+ &prtd->free_out_queue);
+ offset = offset + sizeof(struct dtmf_buf_node);
+ }
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ mutex_unlock(&prtd->lock);
+ }
+
+ return ret;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+
+ pr_debug("%s: DTMF\n", __func__);
+ prtd->pcm_capture_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_capture_irq_pos = 0;
+ prtd->pcm_capture_buf_pos = 0;
+ return 0;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+
+ pr_debug("%s: DTMF\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mutex_lock(&prtd->lock);
+
+ msm_pcm_capture_prepare(substream);
+
+ if (runtime->format != FORMAT_S16_LE) {
+ pr_err("format:%u doesn't match %d\n",
+ (uint32_t)runtime->format, FORMAT_S16_LE);
+ mutex_unlock(&prtd->lock);
+ return -EINVAL;
+ }
+
+ if (prtd->capture_instance &&
+ (prtd->state != DTMF_GEN_RX_STARTED)) {
+ voc_register_dtmf_rx_detection_cb(dtmf_rx_detected_cb,
+ prtd);
+ prtd->state = DTMF_GEN_RX_STARTED;
+ }
+ mutex_unlock(&prtd->lock);
+ }
+
+ return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ pr_debug("%s: Trigger start\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->capture_start = 1;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->capture_start = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ snd_pcm_uframes_t ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
+ prtd->pcm_capture_irq_pos = 0;
+ ret = bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
+ }
+
+ return ret;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .copy = msm_pcm_copy,
+ .hw_params = msm_pcm_hw_params,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+ .pointer = msm_pcm_pointer,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+ .probe = msm_pcm_dtmf_probe,
+};
+
+static int msm_pcm_probe(struct platform_device *pdev)
+{
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_pcm_dtmf_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-dtmf"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_pcm_dtmf_dt_match);
+
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-dtmf",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_dtmf_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = msm_pcm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("DTMF platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-host-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-host-voice-v2.c
new file mode 100644
index 0000000..720c46a
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-host-voice-v2.c
@@ -0,0 +1,1553 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/msm_audio_ion.h>
+#include "q6voice.h"
+
+#define HPCM_MAX_Q_LEN 2
+#define HPCM_MIN_VOC_PKT_SIZE 320
+#define HPCM_MAX_VOC_PKT_SIZE 640
+#define VHPCM_BLOCK_SIZE 4096
+#define CACHE_ALIGNMENT_SIZE 128
+#define CACHE_ALIGNMENT_MASK 0xFFFFFF80
+
+#define VOICE_TX_CAPTURE_DAI_ID "CS-VOICE HOST TX CAPTURE"
+#define VOICE_TX_PLAYBACK_DAI_ID "CS-VOICE HOST TX PLAYBACK"
+#define VOICE_RX_CAPTURE_DAI_ID "CS-VOICE HOST RX CAPTURE"
+#define VOICE_RX_PLAYBACK_DAI_ID "CS-VOICE HOST RX PLAYBACK"
+
+#define VOLTE_TX_CAPTURE_DAI_ID "VOLTE HOST TX CAPTURE"
+#define VOLTE_TX_PLAYBACK_DAI_ID "VOLTE HOST TX PLAYBACK"
+#define VOLTE_RX_CAPTURE_DAI_ID "VOLTE HOST RX CAPTURE"
+#define VOLTE_RX_PLAYBACK_DAI_ID "VOLTE HOST RX PLAYBACK"
+
+
+#define VoMMode1_TX_CAPTURE_DAI_ID "VoiceMMode1 HOST TX CAPTURE"
+#define VoMMode1_TX_PLAYBACK_DAI_ID "VoiceMMode1 HOST TX PLAYBACK"
+#define VoMMode1_RX_CAPTURE_DAI_ID "VoiceMMode1 HOST RX CAPTURE"
+#define VoMMode1_RX_PLAYBACK_DAI_ID "VoiceMMode1 HOST RX PLAYBACK"
+
+#define VoMMode2_TX_CAPTURE_DAI_ID "VoiceMMode2 HOST TX CAPTURE"
+#define VoMMode2_TX_PLAYBACK_DAI_ID "VoiceMMode2 HOST TX PLAYBACK"
+#define VoMMode2_RX_CAPTURE_DAI_ID "VoiceMMode2 HOST RX CAPTURE"
+#define VoMMode2_RX_PLAYBACK_DAI_ID "VoiceMMode2 HOST RX PLAYBACK"
+
+enum {
+ RX = 1,
+ TX,
+};
+
+enum {
+ VOICE_INDEX = 0,
+ VOLTE_INDEX,
+ VOMMODE1_INDEX,
+ VOMMODE2_INDEX,
+ MAX_SESSION
+};
+
+enum hpcm_state {
+ HPCM_STOPPED = 1,
+ HPCM_CLOSED,
+ HPCM_PREPARED,
+ HPCM_STARTED,
+};
+
+struct hpcm_frame {
+ uint32_t len;
+ uint8_t voc_pkt[HPCM_MAX_VOC_PKT_SIZE];
+};
+
+struct hpcm_buf_node {
+ struct list_head list;
+ struct hpcm_frame frame;
+};
+
+struct vocpcm_ion_buffer {
+ /* Physical address */
+ phys_addr_t paddr;
+ /* Kernel virtual address */
+ void *kvaddr;
+};
+
+struct dai_data {
+ enum hpcm_state state;
+ struct snd_pcm_substream *substream;
+ struct list_head filled_queue;
+ struct list_head free_queue;
+ wait_queue_head_t queue_wait;
+ spinlock_t dsp_lock;
+ uint32_t pcm_size;
+ uint32_t pcm_count;
+ /* IRQ position */
+ uint32_t pcm_irq_pos;
+ /* Position in buffer */
+ uint32_t pcm_buf_pos;
+ struct vocpcm_ion_buffer vocpcm_ion_buffer;
+};
+
+struct tap_point {
+ struct dai_data playback_dai_data;
+ struct dai_data capture_dai_data;
+};
+
+struct session {
+ struct tap_point tx_tap_point;
+ struct tap_point rx_tap_point;
+ phys_addr_t sess_paddr;
+ void *sess_kvaddr;
+ struct ion_handle *ion_handle;
+ struct mem_map_table tp_mem_table;
+};
+
+struct tappnt_mxr_data {
+ bool enable;
+ uint16_t direction;
+ uint16_t sample_rate;
+};
+
+/* Values from mixer ctl are cached in this structure */
+struct mixer_conf {
+ int8_t sess_indx;
+ struct tappnt_mxr_data rx;
+ struct tappnt_mxr_data tx;
+};
+
+struct start_cmd {
+ struct vss_ivpcm_tap_point tap_pnt[2];
+ uint32_t no_of_tapoints;
+};
+
+struct hpcm_drv {
+ struct mutex lock;
+ struct session session[MAX_SESSION];
+ struct mixer_conf mixer_conf;
+ struct ion_client *ion_client;
+ struct start_cmd start_cmd;
+};
+
+static struct hpcm_drv hpcm_drv;
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_SPECIAL,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = sizeof(struct hpcm_buf_node) * HPCM_MAX_Q_LEN,
+ .period_bytes_min = HPCM_MIN_VOC_PKT_SIZE,
+ .period_bytes_max = HPCM_MAX_VOC_PKT_SIZE,
+ .periods_min = HPCM_MAX_Q_LEN,
+ .periods_max = HPCM_MAX_Q_LEN,
+ .fifo_size = 0,
+};
+
+static char *hpcm_get_sess_name(int sess_indx)
+{
+ char *sess_name = NULL;
+
+ if (sess_indx == VOICE_INDEX)
+ sess_name = VOICE_SESSION_NAME;
+ else if (sess_indx == VOLTE_INDEX)
+ sess_name = VOLTE_SESSION_NAME;
+ else if (sess_indx == VOMMODE1_INDEX)
+ sess_name = VOICEMMODE1_NAME;
+ else if (sess_indx == VOMMODE2_INDEX)
+ sess_name = VOICEMMODE2_NAME;
+ else
+ pr_err("%s:, Invalid sess_index\n", __func__);
+
+ return sess_name;
+}
+
+static void hpcm_reset_mixer_config(struct hpcm_drv *prtd)
+{
+ prtd->mixer_conf.sess_indx = -1;
+ prtd->mixer_conf.rx.enable = false;
+ prtd->mixer_conf.rx.direction = -1;
+ prtd->mixer_conf.rx.sample_rate = 0;
+
+ prtd->mixer_conf.tx.enable = false;
+ prtd->mixer_conf.tx.direction = -1;
+ prtd->mixer_conf.tx.sample_rate = 0;
+}
+
+/* Check for valid mixer control values */
+static bool hpcm_is_valid_config(int sess_indx, int tap_point,
+ uint16_t direction, uint16_t samplerate)
+{
+ if (sess_indx < VOICE_INDEX || sess_indx > VOMMODE2_INDEX) {
+ pr_err("%s: invalid sess_indx :%d\n", __func__, sess_indx);
+ goto error;
+ }
+
+ if (samplerate != VSS_IVPCM_SAMPLING_RATE_8K &&
+ samplerate != VSS_IVPCM_SAMPLING_RATE_16K) {
+ pr_err("%s: invalid sample rate :%d\n", __func__, samplerate);
+ goto error;
+ }
+
+ if ((tap_point != RX) && (tap_point != TX)) {
+ pr_err("%s: invalid tappoint :%d\n", __func__, tap_point);
+ goto error;
+ }
+
+ if ((direction != VSS_IVPCM_TAP_POINT_DIR_IN) &&
+ (direction != VSS_IVPCM_TAP_POINT_DIR_OUT) &&
+ (direction != VSS_IVPCM_TAP_POINT_DIR_OUT_IN)) {
+ pr_err("%s: invalid direction :%d\n", __func__, direction);
+ goto error;
+ }
+
+ return true;
+
+error:
+ return false;
+}
+
+
+static struct dai_data *hpcm_get_dai_data(char *pcm_id, struct hpcm_drv *prtd)
+{
+ struct dai_data *dai_data = NULL;
+ size_t size = 0;
+
+ if (pcm_id) {
+ size = strlen(pcm_id);
+ /* Check for Voice DAI */
+ if (strnstr(pcm_id, VOICE_TX_CAPTURE_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOICE_INDEX].tx_tap_point.capture_dai_data;
+ } else if (strnstr(pcm_id, VOICE_TX_PLAYBACK_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOICE_INDEX].tx_tap_point.playback_dai_data;
+ } else if (strnstr(pcm_id, VOICE_RX_CAPTURE_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOICE_INDEX].rx_tap_point.capture_dai_data;
+ } else if (strnstr(pcm_id, VOICE_RX_PLAYBACK_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOICE_INDEX].rx_tap_point.playback_dai_data;
+ /* Check for VoLTE DAI */
+ } else if (strnstr(pcm_id, VOLTE_TX_CAPTURE_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOLTE_INDEX].tx_tap_point.capture_dai_data;
+ } else if (strnstr(pcm_id, VOLTE_TX_PLAYBACK_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOLTE_INDEX].tx_tap_point.playback_dai_data;
+ } else if (strnstr(pcm_id, VOLTE_RX_CAPTURE_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOLTE_INDEX].rx_tap_point.capture_dai_data;
+ } else if (strnstr(pcm_id, VOLTE_RX_PLAYBACK_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOLTE_INDEX].rx_tap_point.playback_dai_data;
+ /* check for VoiceMMode1 DAI */
+ } else if (strnstr(pcm_id, VoMMode1_TX_CAPTURE_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOMMODE1_INDEX].tx_tap_point.capture_dai_data;
+ } else if (strnstr(pcm_id, VoMMode1_TX_PLAYBACK_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOMMODE1_INDEX].tx_tap_point.playback_dai_data;
+ } else if (strnstr(pcm_id, VoMMode1_RX_CAPTURE_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOMMODE1_INDEX].rx_tap_point.capture_dai_data;
+ } else if (strnstr(pcm_id, VoMMode1_RX_PLAYBACK_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOMMODE1_INDEX].rx_tap_point.playback_dai_data;
+ /* check for VOiceMMode2 DAI */
+ } else if (strnstr(pcm_id, VoMMode2_TX_CAPTURE_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOMMODE2_INDEX].tx_tap_point.capture_dai_data;
+ } else if (strnstr(pcm_id, VoMMode2_TX_PLAYBACK_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOMMODE2_INDEX].tx_tap_point.playback_dai_data;
+ } else if (strnstr(pcm_id, VoMMode2_RX_CAPTURE_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOMMODE2_INDEX].rx_tap_point.capture_dai_data;
+ } else if (strnstr(pcm_id, VoMMode2_RX_PLAYBACK_DAI_ID, size)) {
+ dai_data =
+ &prtd->session[VOMMODE2_INDEX].rx_tap_point.playback_dai_data;
+
+ } else {
+ pr_err("%s: Wrong dai id\n", __func__);
+ }
+ }
+
+ return dai_data;
+}
+
+static struct tap_point *hpcm_get_tappoint_data(char *pcm_id,
+ struct hpcm_drv *prtd)
+{
+ struct tap_point *tp = NULL;
+ size_t size = 0;
+
+ if (pcm_id) {
+ size = strlen(pcm_id);
+ /* Check for Voice DAI */
+ if (strnstr(pcm_id, VOICE_TX_CAPTURE_DAI_ID, size)) {
+ tp = &prtd->session[VOICE_INDEX].tx_tap_point;
+ } else if (strnstr(pcm_id, VOICE_TX_PLAYBACK_DAI_ID, size)) {
+ tp = &prtd->session[VOICE_INDEX].tx_tap_point;
+ } else if (strnstr(pcm_id, VOICE_RX_CAPTURE_DAI_ID, size)) {
+ tp = &prtd->session[VOICE_INDEX].rx_tap_point;
+ } else if (strnstr(pcm_id, VOICE_RX_PLAYBACK_DAI_ID, size)) {
+ tp = &prtd->session[VOICE_INDEX].rx_tap_point;
+ /* Check for VoLTE DAI */
+ } else if (strnstr(pcm_id, VOLTE_TX_CAPTURE_DAI_ID, size)) {
+ tp = &prtd->session[VOLTE_INDEX].tx_tap_point;
+ } else if (strnstr(pcm_id, VOLTE_TX_PLAYBACK_DAI_ID, size)) {
+ tp = &prtd->session[VOLTE_INDEX].tx_tap_point;
+ } else if (strnstr(pcm_id, VOLTE_RX_CAPTURE_DAI_ID, size)) {
+ tp = &prtd->session[VOLTE_INDEX].rx_tap_point;
+ } else if (strnstr(pcm_id, VOLTE_RX_PLAYBACK_DAI_ID, size)) {
+ tp = &prtd->session[VOLTE_INDEX].rx_tap_point;
+ /* check for VoiceMMode1 */
+ } else if (strnstr(pcm_id, VoMMode1_TX_CAPTURE_DAI_ID, size)) {
+ tp = &prtd->session[VOMMODE1_INDEX].tx_tap_point;
+ } else if (strnstr(pcm_id, VoMMode1_TX_PLAYBACK_DAI_ID, size)) {
+ tp = &prtd->session[VOMMODE1_INDEX].tx_tap_point;
+ } else if (strnstr(pcm_id, VoMMode1_RX_CAPTURE_DAI_ID, size)) {
+ tp = &prtd->session[VOMMODE1_INDEX].rx_tap_point;
+ } else if (strnstr(pcm_id, VoMMode1_RX_PLAYBACK_DAI_ID, size)) {
+ tp = &prtd->session[VOMMODE1_INDEX].rx_tap_point;
+ /* check for VoiceMMode2 */
+ } else if (strnstr(pcm_id, VoMMode2_TX_CAPTURE_DAI_ID, size)) {
+ tp = &prtd->session[VOMMODE2_INDEX].tx_tap_point;
+ } else if (strnstr(pcm_id, VoMMode2_TX_PLAYBACK_DAI_ID, size)) {
+ tp = &prtd->session[VOMMODE2_INDEX].tx_tap_point;
+ } else if (strnstr(pcm_id, VoMMode2_RX_CAPTURE_DAI_ID, size)) {
+ tp = &prtd->session[VOMMODE2_INDEX].rx_tap_point;
+ } else if (strnstr(pcm_id, VoMMode2_RX_PLAYBACK_DAI_ID, size)) {
+ tp = &prtd->session[VOMMODE2_INDEX].rx_tap_point;
+ } else {
+ pr_err("%s: wrong dai id\n", __func__);
+ }
+ }
+
+ return tp;
+}
+
+static struct tappnt_mxr_data *hpcm_get_tappnt_mixer_data(char *pcm_id,
+ struct hpcm_drv *prtd)
+{
+
+ if (strnstr(pcm_id, VOICE_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VOICE_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VOLTE_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VOLTE_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VoMMode1_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VoMMode1_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VoMMode2_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VoMMode2_TX_PLAYBACK_DAI_ID, strlen(pcm_id))) {
+ return &prtd->mixer_conf.tx;
+ } else {
+ return &prtd->mixer_conf.rx;
+ }
+}
+
+static int get_tappnt_value(char *pcm_id)
+{
+
+ if (strnstr(pcm_id, VOICE_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VOICE_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VOLTE_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VOLTE_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VoMMode1_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VoMMode1_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VoMMode2_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
+ strnstr(pcm_id, VoMMode2_TX_PLAYBACK_DAI_ID, strlen(pcm_id))) {
+ return TX;
+ } else {
+ return RX;
+ }
+}
+
+static bool hpcm_all_dais_are_ready(uint16_t direction, struct tap_point *tp,
+ enum hpcm_state state)
+{
+ bool dais_started = false;
+
+ /*
+ * Based on the direction set per tap point in the mixer control,
+ * all the dais per tap point should meet the required state for the
+ * commands such as vpcm_map_memory/vpcm_start to be executed.
+ */
+ switch (direction) {
+ case VSS_IVPCM_TAP_POINT_DIR_OUT_IN:
+ if ((tp->playback_dai_data.state >= state) &&
+ (tp->capture_dai_data.state >= state)) {
+ dais_started = true;
+ }
+ break;
+
+ case VSS_IVPCM_TAP_POINT_DIR_IN:
+ if (tp->playback_dai_data.state >= state)
+ dais_started = true;
+ break;
+
+ case VSS_IVPCM_TAP_POINT_DIR_OUT:
+ if (tp->capture_dai_data.state >= state)
+ dais_started = true;
+ break;
+
+ default:
+ pr_err("invalid direction\n");
+ }
+
+ return dais_started;
+}
+
+static void hpcm_create_free_queue(struct snd_dma_buffer *dma_buf,
+ struct dai_data *dai_data)
+{
+ struct hpcm_buf_node *buf_node = NULL;
+ int i = 0, offset = 0;
+
+ for (i = 0; i < HPCM_MAX_Q_LEN; i++) {
+ buf_node = (void *)dma_buf->area + offset;
+ list_add_tail(&buf_node->list,
+ &dai_data->free_queue);
+ offset = offset + sizeof(struct hpcm_buf_node);
+ }
+}
+
+static void hpcm_free_allocated_mem(struct hpcm_drv *prtd)
+{
+ phys_addr_t paddr = 0;
+ struct tap_point *txtp = NULL;
+ struct tap_point *rxtp = NULL;
+ struct session *sess = NULL;
+
+ sess = &prtd->session[prtd->mixer_conf.sess_indx];
+ txtp = &sess->tx_tap_point;
+ rxtp = &sess->rx_tap_point;
+ paddr = sess->sess_paddr;
+
+ if (paddr) {
+ msm_audio_ion_free(prtd->ion_client, sess->ion_handle);
+ prtd->ion_client = NULL;
+ sess->ion_handle = NULL;
+ msm_audio_ion_free(sess->tp_mem_table.client,
+ sess->tp_mem_table.handle);
+ sess->tp_mem_table.client = NULL;
+ sess->tp_mem_table.handle = NULL;
+ sess->sess_paddr = 0;
+ sess->sess_kvaddr = 0;
+ sess->ion_handle = 0;
+ prtd->ion_client = 0;
+ sess->tp_mem_table.client = 0;
+ sess->tp_mem_table.handle = 0;
+
+ txtp->capture_dai_data.vocpcm_ion_buffer.paddr = 0;
+ txtp->capture_dai_data.vocpcm_ion_buffer.kvaddr = 0;
+
+ txtp->playback_dai_data.vocpcm_ion_buffer.paddr = 0;
+ txtp->playback_dai_data.vocpcm_ion_buffer.kvaddr = 0;
+
+ rxtp->capture_dai_data.vocpcm_ion_buffer.paddr = 0;
+ rxtp->capture_dai_data.vocpcm_ion_buffer.kvaddr = 0;
+
+ rxtp->playback_dai_data.vocpcm_ion_buffer.paddr = 0;
+ rxtp->playback_dai_data.vocpcm_ion_buffer.kvaddr = 0;
+ } else {
+ pr_debug("%s, paddr = 0, nothing to free\n", __func__);
+ }
+}
+
+static void hpcm_unmap_and_free_shared_memory(struct hpcm_drv *prtd)
+
+{
+ phys_addr_t paddr = 0;
+ char *sess_name = hpcm_get_sess_name(prtd->mixer_conf.sess_indx);
+
+ if (prtd->mixer_conf.sess_indx >= 0)
+ paddr = prtd->session[prtd->mixer_conf.sess_indx].sess_paddr;
+ else
+ paddr = 0;
+
+ if (paddr) {
+ voc_send_cvp_unmap_vocpcm_memory(voc_get_session_id(sess_name));
+ hpcm_free_allocated_mem(prtd);
+ } else {
+ pr_debug("%s, paddr = 0, nothing to unmap/free\n", __func__);
+ }
+}
+
+static int hpcm_map_vocpcm_memory(struct hpcm_drv *prtd)
+{
+ int ret = 0;
+ char *sess_name = hpcm_get_sess_name(prtd->mixer_conf.sess_indx);
+ struct session *sess = NULL;
+
+ sess = &prtd->session[prtd->mixer_conf.sess_indx];
+
+ ret = voc_send_cvp_map_vocpcm_memory(voc_get_session_id(sess_name),
+ &sess->tp_mem_table,
+ sess->sess_paddr,
+ VHPCM_BLOCK_SIZE);
+
+ return ret;
+}
+
+static int hpcm_allocate_shared_memory(struct hpcm_drv *prtd)
+{
+ int result;
+ int ret = 0;
+ size_t mem_len;
+ size_t len;
+ struct tap_point *txtp = NULL;
+ struct tap_point *rxtp = NULL;
+ struct session *sess = NULL;
+
+ sess = &prtd->session[prtd->mixer_conf.sess_indx];
+ txtp = &sess->tx_tap_point;
+ rxtp = &sess->rx_tap_point;
+
+ result = msm_audio_ion_alloc("host_pcm_buffer",
+ &prtd->ion_client,
+ &sess->ion_handle,
+ VHPCM_BLOCK_SIZE,
+ &sess->sess_paddr,
+ &mem_len,
+ &sess->sess_kvaddr);
+ if (result) {
+ pr_err("%s: msm_audio_ion_alloc error, rc = %d\n",
+ __func__, result);
+ sess->sess_paddr = 0;
+ sess->sess_kvaddr = 0;
+ ret = -ENOMEM;
+ goto done;
+ }
+ pr_debug("%s: Host PCM memory block allocated\n", __func__);
+
+ /* Allocate mem_map_table for tap point */
+ result = msm_audio_ion_alloc("host_pcm_table",
+ &sess->tp_mem_table.client,
+ &sess->tp_mem_table.handle,
+ sizeof(struct vss_imemory_table_t),
+ &sess->tp_mem_table.phys,
+ &len,
+ &sess->tp_mem_table.data);
+
+ if (result) {
+ pr_err("%s: msm_audio_ion_alloc error, rc = %d\n",
+ __func__, result);
+ msm_audio_ion_free(prtd->ion_client, sess->ion_handle);
+ prtd->ion_client = NULL;
+ sess->ion_handle = NULL;
+ sess->sess_paddr = 0;
+ sess->sess_kvaddr = 0;
+ ret = -ENOMEM;
+ goto done;
+ }
+ pr_debug("%s: Host PCM memory table allocated\n", __func__);
+
+ memset(sess->tp_mem_table.data, 0,
+ sizeof(struct vss_imemory_table_t));
+
+ sess->tp_mem_table.size = sizeof(struct vss_imemory_table_t);
+
+ pr_debug("%s: data %pK phys %pK\n", __func__,
+ sess->tp_mem_table.data, &sess->tp_mem_table.phys);
+
+ /* Split 4096 block into four 1024 byte blocks for each dai */
+ txtp->capture_dai_data.vocpcm_ion_buffer.paddr =
+ sess->sess_paddr;
+ txtp->capture_dai_data.vocpcm_ion_buffer.kvaddr =
+ sess->sess_kvaddr;
+
+ txtp->playback_dai_data.vocpcm_ion_buffer.paddr =
+ sess->sess_paddr + VHPCM_BLOCK_SIZE/4;
+ txtp->playback_dai_data.vocpcm_ion_buffer.kvaddr =
+ sess->sess_kvaddr + VHPCM_BLOCK_SIZE/4;
+
+ rxtp->capture_dai_data.vocpcm_ion_buffer.paddr =
+ sess->sess_paddr + (VHPCM_BLOCK_SIZE/4) * 2;
+ rxtp->capture_dai_data.vocpcm_ion_buffer.kvaddr =
+ sess->sess_kvaddr + (VHPCM_BLOCK_SIZE/4) * 2;
+
+ rxtp->playback_dai_data.vocpcm_ion_buffer.paddr =
+ sess->sess_paddr + (VHPCM_BLOCK_SIZE/4) * 3;
+ rxtp->playback_dai_data.vocpcm_ion_buffer.kvaddr =
+ sess->sess_kvaddr + (VHPCM_BLOCK_SIZE/4) * 3;
+
+done:
+ return ret;
+}
+
+static int hpcm_start_vocpcm(char *pcm_id, struct hpcm_drv *prtd,
+ struct tap_point *tp)
+{
+ int indx = prtd->mixer_conf.sess_indx;
+ uint32_t *no_of_tp = &prtd->start_cmd.no_of_tapoints;
+ struct vss_ivpcm_tap_point *tap_pnt = &prtd->start_cmd.tap_pnt[0];
+ uint32_t no_of_tp_req = 0;
+ char *sess_name = hpcm_get_sess_name(indx);
+
+ if (prtd->mixer_conf.rx.enable)
+ no_of_tp_req++;
+ if (prtd->mixer_conf.tx.enable)
+ no_of_tp_req++;
+
+ if (prtd->mixer_conf.rx.enable && (get_tappnt_value(pcm_id) == RX)) {
+ if (hpcm_all_dais_are_ready(prtd->mixer_conf.rx.direction,
+ tp, HPCM_PREPARED)) {
+ pr_debug("%s: RX conditions met\n", __func__);
+ tap_pnt[*no_of_tp].tap_point =
+ VSS_IVPCM_TAP_POINT_RX_DEFAULT;
+ tap_pnt[*no_of_tp].direction =
+ prtd->mixer_conf.rx.direction;
+ tap_pnt[*no_of_tp].sampling_rate =
+ prtd->mixer_conf.rx.sample_rate;
+ (*no_of_tp)++;
+ }
+ }
+
+ if (prtd->mixer_conf.tx.enable && (get_tappnt_value(pcm_id) == TX)) {
+ if (hpcm_all_dais_are_ready(prtd->mixer_conf.tx.direction,
+ tp, HPCM_PREPARED)) {
+ pr_debug("%s: TX conditions met\n", __func__);
+ tap_pnt[*no_of_tp].tap_point =
+ VSS_IVPCM_TAP_POINT_TX_DEFAULT;
+ tap_pnt[*no_of_tp].direction =
+ prtd->mixer_conf.tx.direction;
+ tap_pnt[*no_of_tp].sampling_rate =
+ prtd->mixer_conf.tx.sample_rate;
+ (*no_of_tp)++;
+ }
+ }
+
+ if ((prtd->mixer_conf.tx.enable || prtd->mixer_conf.rx.enable) &&
+ *no_of_tp == no_of_tp_req) {
+ voc_send_cvp_start_vocpcm(voc_get_session_id(sess_name),
+ tap_pnt, *no_of_tp);
+ /* Reset the start command so that it is not called twice */
+ memset(&prtd->start_cmd, 0, sizeof(struct start_cmd));
+ } else {
+ pr_debug("%s: required pcm handles not opened yet\n", __func__);
+ }
+
+ return 0;
+}
+
+/* Playback path*/
+static void hpcm_copy_playback_data_from_queue(struct dai_data *dai_data,
+ uint32_t *len)
+{
+ struct hpcm_buf_node *buf_node = NULL;
+ unsigned long dsp_flags;
+
+ if (dai_data->substream == NULL)
+ return;
+
+ spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
+
+ if (!list_empty(&dai_data->filled_queue)) {
+ buf_node = list_first_entry(&dai_data->filled_queue,
+ struct hpcm_buf_node, list);
+ list_del(&buf_node->list);
+ *len = buf_node->frame.len;
+ memcpy((u8 *)dai_data->vocpcm_ion_buffer.kvaddr,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &dai_data->free_queue);
+ dai_data->pcm_irq_pos += dai_data->pcm_count;
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+ snd_pcm_period_elapsed(dai_data->substream);
+ } else {
+ *len = 0;
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+ pr_err("IN data not available\n");
+ }
+
+ wake_up(&dai_data->queue_wait);
+}
+
+/* Capture path*/
+static void hpcm_copy_capture_data_to_queue(struct dai_data *dai_data,
+ uint32_t len)
+{
+ struct hpcm_buf_node *buf_node = NULL;
+ unsigned long dsp_flags;
+
+ if (dai_data->substream == NULL)
+ return;
+
+ /* Copy out buffer packet into free_queue */
+ spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
+
+ if (!list_empty(&dai_data->free_queue)) {
+ buf_node = list_first_entry(&dai_data->free_queue,
+ struct hpcm_buf_node, list);
+ list_del(&buf_node->list);
+ buf_node->frame.len = len;
+ memcpy(&buf_node->frame.voc_pkt[0],
+ (uint8_t *)dai_data->vocpcm_ion_buffer.kvaddr,
+ buf_node->frame.len);
+ list_add_tail(&buf_node->list, &dai_data->filled_queue);
+ dai_data->pcm_irq_pos += dai_data->pcm_count;
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+ snd_pcm_period_elapsed(dai_data->substream);
+ } else {
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+ pr_err("OUTPUT data dropped\n");
+ }
+
+ wake_up(&dai_data->queue_wait);
+}
+
+void hpcm_notify_evt_processing(uint8_t *data, char *session,
+ void *private_data)
+{
+ struct hpcm_drv *prtd = (struct hpcm_drv *)private_data;
+ struct vss_ivpcm_evt_notify_v2_t *notify_evt =
+ (struct vss_ivpcm_evt_notify_v2_t *)data;
+ struct vss_ivpcm_evt_push_buffer_v2_t push_buff_event;
+ struct tap_point *tp = NULL;
+ int in_buf_len = 0;
+ struct tappnt_mxr_data *tmd = NULL;
+ char *sess_name = hpcm_get_sess_name(prtd->mixer_conf.sess_indx);
+
+ /* If it's not a timetick, it's a error notification, drop the event */
+ if ((notify_evt->notify_mask & VSS_IVPCM_NOTIFY_MASK_TIMETICK) == 0) {
+ pr_err("%s: Error notification. mask=%d\n", __func__,
+ notify_evt->notify_mask);
+ return;
+ }
+
+ if (notify_evt->tap_point == VSS_IVPCM_TAP_POINT_TX_DEFAULT) {
+ tp = &prtd->session[prtd->mixer_conf.sess_indx].tx_tap_point;
+ tmd = &prtd->mixer_conf.tx;
+ } else if (notify_evt->tap_point == VSS_IVPCM_TAP_POINT_RX_DEFAULT) {
+ tp = &prtd->session[prtd->mixer_conf.sess_indx].rx_tap_point;
+ tmd = &prtd->mixer_conf.rx;
+ }
+
+ if (tp == NULL || tmd == NULL) {
+ pr_err("%s: tp = %pK or tmd = %pK is null\n", __func__,
+ tp, tmd);
+
+ return;
+ }
+
+ if (notify_evt->notify_mask & VSS_IVPCM_NOTIFY_MASK_OUTPUT_BUFFER) {
+ hpcm_copy_capture_data_to_queue(&tp->capture_dai_data,
+ notify_evt->filled_out_size);
+ }
+
+ if (notify_evt->notify_mask & VSS_IVPCM_NOTIFY_MASK_INPUT_BUFFER) {
+ hpcm_copy_playback_data_from_queue(&tp->playback_dai_data,
+ &in_buf_len);
+ }
+
+ switch (tmd->direction) {
+ /*
+ * When the dir is OUT_IN, for the first notify mask, pushbuf mask
+ * should be set to VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER since we
+ * atleast need one buffer's worth data before we can send IN buffer.
+ * For the consecutive notify evts, the push buf mask will set for both
+ * VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER and
+ * VSS_IVPCM_PUSH_BUFFER_MASK_IN_BUFFER.
+ */
+ case VSS_IVPCM_TAP_POINT_DIR_OUT_IN:
+ if (notify_evt->notify_mask ==
+ VSS_IVPCM_NOTIFY_MASK_TIMETICK) {
+ push_buff_event.push_buf_mask =
+ VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER;
+ } else {
+ push_buff_event.push_buf_mask =
+ VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER |
+ VSS_IVPCM_PUSH_BUFFER_MASK_INPUT_BUFFER;
+ }
+ break;
+
+ case VSS_IVPCM_TAP_POINT_DIR_IN:
+ push_buff_event.push_buf_mask =
+ VSS_IVPCM_PUSH_BUFFER_MASK_INPUT_BUFFER;
+ break;
+
+ case VSS_IVPCM_TAP_POINT_DIR_OUT:
+ push_buff_event.push_buf_mask =
+ VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER;
+ break;
+ }
+
+ push_buff_event.tap_point = notify_evt->tap_point;
+ push_buff_event.out_buf_mem_address =
+ tp->capture_dai_data.vocpcm_ion_buffer.paddr;
+ push_buff_event.in_buf_mem_address =
+ tp->playback_dai_data.vocpcm_ion_buffer.paddr;
+ push_buff_event.sampling_rate = notify_evt->sampling_rate;
+ push_buff_event.num_in_channels = 1;
+
+ /*
+ * ADSP must read and write from a cache aligned (128 byte) location,
+ * and in blocks of the cache alignment size. The 128 byte cache
+ * alignment requirement is guaranteed due to 4096 byte memory
+ * alignment requirement during memory allocation/mapping. The output
+ * buffer (ADSP write) size mask ensures that a 128 byte multiple
+ * worth of will be written. Internally, the input buffer (ADSP read)
+ * size will also be a multiple of 128 bytes. However it is the
+ * application's responsibility to ensure no other data is written in
+ * the specified length of memory.
+ */
+ push_buff_event.out_buf_mem_size = ((notify_evt->request_buf_size) +
+ CACHE_ALIGNMENT_SIZE) & CACHE_ALIGNMENT_MASK;
+ push_buff_event.in_buf_mem_size = in_buf_len;
+
+ voc_send_cvp_vocpcm_push_buf_evt(voc_get_session_id(sess_name),
+ &push_buff_event);
+}
+
+static int msm_hpcm_configure_voice_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ int tap_point = ucontrol->value.integer.value[0];
+ uint16_t direction = ucontrol->value.integer.value[1];
+ uint16_t sample_rate = ucontrol->value.integer.value[2];
+ struct tappnt_mxr_data *tmd = NULL;
+ int ret = 0;
+
+ mutex_lock(&hpcm_drv.lock);
+ pr_debug("%s: tap_point = %d direction = %d sample_rate = %d\n",
+ __func__, tap_point, direction, sample_rate);
+
+ if (!hpcm_is_valid_config(VOICE_INDEX, tap_point, direction,
+ sample_rate)) {
+ pr_err("Invalid vpcm mixer control voice values\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (tap_point == RX)
+ tmd = &hpcm_drv.mixer_conf.rx;
+ else
+ tmd = &hpcm_drv.mixer_conf.tx;
+
+ tmd->enable = true;
+ tmd->direction = direction;
+ tmd->sample_rate = sample_rate;
+ hpcm_drv.mixer_conf.sess_indx = VOICE_INDEX;
+
+done:
+ mutex_unlock(&hpcm_drv.lock);
+ return ret;
+}
+
+static int msm_hpcm_configure_vmmode1_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ int tap_point = ucontrol->value.integer.value[0];
+ uint16_t direction = ucontrol->value.integer.value[1];
+ uint16_t sample_rate = ucontrol->value.integer.value[2];
+ struct tappnt_mxr_data *tmd = NULL;
+ int ret = 0;
+
+ mutex_lock(&hpcm_drv.lock);
+ pr_debug("%s: tap_point = %d direction = %d sample_rate = %d\n",
+ __func__, tap_point, direction, sample_rate);
+
+ if (!hpcm_is_valid_config(VOMMODE1_INDEX, tap_point, direction,
+ sample_rate)) {
+ pr_err("Invalid vpcm mixer control voice values\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (tap_point == RX)
+ tmd = &hpcm_drv.mixer_conf.rx;
+ else
+ tmd = &hpcm_drv.mixer_conf.tx;
+
+ tmd->enable = true;
+ tmd->direction = direction;
+ tmd->sample_rate = sample_rate;
+ hpcm_drv.mixer_conf.sess_indx = VOMMODE1_INDEX;
+
+done:
+ mutex_unlock(&hpcm_drv.lock);
+ return ret;
+}
+
+static int msm_hpcm_configure_vmmode2_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ int tap_point = ucontrol->value.integer.value[0];
+ uint16_t direction = ucontrol->value.integer.value[1];
+ uint16_t sample_rate = ucontrol->value.integer.value[2];
+ struct tappnt_mxr_data *tmd = NULL;
+ int ret = 0;
+
+ mutex_lock(&hpcm_drv.lock);
+ pr_debug("%s: tap_point = %d direction = %d sample_rate = %d\n",
+ __func__, tap_point, direction, sample_rate);
+
+ if (!hpcm_is_valid_config(VOMMODE2_INDEX, tap_point, direction,
+ sample_rate)) {
+ pr_err("Invalid vpcm mixer control voice values\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (tap_point == RX)
+ tmd = &hpcm_drv.mixer_conf.rx;
+ else
+ tmd = &hpcm_drv.mixer_conf.tx;
+
+ tmd->enable = true;
+ tmd->direction = direction;
+ tmd->sample_rate = sample_rate;
+ hpcm_drv.mixer_conf.sess_indx = VOMMODE2_INDEX;
+
+done:
+ mutex_unlock(&hpcm_drv.lock);
+ return ret;
+}
+
+static int msm_hpcm_configure_volte_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ int tap_point = ucontrol->value.integer.value[0];
+ uint16_t direction = ucontrol->value.integer.value[1];
+ uint16_t sample_rate = ucontrol->value.integer.value[2];
+ struct tappnt_mxr_data *tmd = NULL;
+ int ret = 0;
+
+ mutex_lock(&hpcm_drv.lock);
+ pr_debug("%s: tap_point=%d direction=%d sample_rate=%d\n",
+ __func__, tap_point, direction, sample_rate);
+
+ if (!hpcm_is_valid_config(VOLTE_INDEX, tap_point, direction,
+ sample_rate)) {
+ pr_err("Invalid vpcm mixer control volte values\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (tap_point == RX)
+ tmd = &hpcm_drv.mixer_conf.rx;
+ else
+ tmd = &hpcm_drv.mixer_conf.tx;
+
+ tmd->enable = true;
+ tmd->direction = direction;
+ tmd->sample_rate = sample_rate;
+ hpcm_drv.mixer_conf.sess_indx = VOLTE_INDEX;
+
+done:
+ mutex_unlock(&hpcm_drv.lock);
+ return ret;
+
+}
+
+static struct snd_kcontrol_new msm_hpcm_controls[] = {
+ SOC_SINGLE_MULTI_EXT("HPCM_Voice tappoint direction samplerate",
+ SND_SOC_NOPM, 0, 16000, 0, 3,
+ NULL, msm_hpcm_configure_voice_put),
+ SOC_SINGLE_MULTI_EXT("HPCM_VoLTE tappoint direction samplerate",
+ SND_SOC_NOPM, 0, 16000, 0, 3,
+ NULL, msm_hpcm_configure_volte_put),
+ SOC_SINGLE_MULTI_EXT("HPCM_VMMode1 tappoint direction samplerate",
+ SND_SOC_NOPM, 0, 16000, 0, 3,
+ NULL, msm_hpcm_configure_vmmode1_put),
+ SOC_SINGLE_MULTI_EXT("HPCM_VMMode2 tappoint direction samplerate",
+ SND_SOC_NOPM, 0, 16000, 0, 3,
+ NULL, msm_hpcm_configure_vmmode2_put),
+};
+
+/* Sample rates supported */
+static unsigned int supported_sample_rates[] = {8000, 16000};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct list_head *ptr = NULL;
+ struct list_head *next = NULL;
+ struct hpcm_buf_node *buf_node = NULL;
+ struct snd_dma_buffer *dma_buf;
+ struct snd_pcm_runtime *runtime;
+ struct hpcm_drv *prtd;
+ unsigned long dsp_flags;
+ struct dai_data *dai_data = NULL;
+ struct tap_point *tp = NULL;
+ struct tappnt_mxr_data *tmd = NULL;
+ char *sess_name = NULL;
+
+ if (substream == NULL) {
+ pr_err("substream is NULL\n");
+ return -EINVAL;
+ }
+
+ pr_debug("%s, %s\n", __func__, substream->pcm->id);
+ runtime = substream->runtime;
+ prtd = runtime->private_data;
+ sess_name = hpcm_get_sess_name(prtd->mixer_conf.sess_indx);
+ dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
+
+ if (dai_data == NULL) {
+ pr_err("%s, dai_data is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ wake_up(&dai_data->queue_wait);
+ mutex_lock(&prtd->lock);
+
+ tmd = hpcm_get_tappnt_mixer_data(substream->pcm->id, prtd);
+
+ tp = hpcm_get_tappoint_data(substream->pcm->id, prtd);
+ /* Send stop command */
+ voc_send_cvp_stop_vocpcm(voc_get_session_id(sess_name));
+ /* Memory unmap/free takes place only when called the first time */
+ hpcm_unmap_and_free_shared_memory(prtd);
+ /* Unregister host PCM event callback function */
+ voc_deregister_hpcm_evt_cb();
+ /* Reset the cached start cmd */
+ memset(&prtd->start_cmd, 0, sizeof(struct start_cmd));
+ /* Release all buffer */
+ pr_debug("%s: Release all buffer\n", __func__);
+ substream = dai_data->substream;
+ if (substream == NULL) {
+ pr_debug("%s: substream is NULL\n", __func__);
+ goto done;
+ }
+ dma_buf = &substream->dma_buffer;
+ if (dma_buf == NULL) {
+ pr_debug("%s: dma_buf is NULL\n", __func__);
+ goto done;
+ }
+ if (dma_buf->area != NULL) {
+ spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
+ list_for_each_safe(ptr, next, &dai_data->filled_queue) {
+ buf_node = list_entry(ptr,
+ struct hpcm_buf_node, list);
+ list_del(&buf_node->list);
+ }
+ list_for_each_safe(ptr, next, &dai_data->free_queue) {
+ buf_node = list_entry(ptr,
+ struct hpcm_buf_node, list);
+ list_del(&buf_node->list);
+ }
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+ dma_free_coherent(substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max, dma_buf->area,
+ dma_buf->addr);
+ dma_buf->area = NULL;
+ }
+ dai_data->substream = NULL;
+ dai_data->pcm_buf_pos = 0;
+ dai_data->pcm_count = 0;
+ dai_data->pcm_irq_pos = 0;
+ dai_data->pcm_size = 0;
+ dai_data->state = HPCM_CLOSED;
+ hpcm_reset_mixer_config(prtd);
+
+done:
+ mutex_unlock(&prtd->lock);
+ return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf,
+ snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ struct hpcm_buf_node *buf_node = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hpcm_drv *prtd = runtime->private_data;
+ struct dai_data *dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
+ unsigned long dsp_flags;
+
+ int count = frames_to_bytes(runtime, frames);
+
+ if (dai_data == NULL) {
+ pr_err("%s, dai_data is null\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_interruptible_timeout(dai_data->queue_wait,
+ (!list_empty(&dai_data->free_queue) ||
+ dai_data->state == HPCM_STOPPED),
+ 1 * HZ);
+ if (ret > 0) {
+ if (count <= HPCM_MAX_VOC_PKT_SIZE) {
+ spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
+ buf_node =
+ list_first_entry(&dai_data->free_queue,
+ struct hpcm_buf_node, list);
+ list_del(&buf_node->list);
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+ ret = copy_from_user(&buf_node->frame.voc_pkt, buf,
+ count);
+ buf_node->frame.len = count;
+ spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
+ list_add_tail(&buf_node->list, &dai_data->filled_queue);
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+ } else {
+ pr_err("%s: Write cnt %d is > HPCM_MAX_VOC_PKT_SIZE\n",
+ __func__, count);
+ ret = -ENOMEM;
+ }
+ } else if (ret == 0) {
+ pr_err("%s: No free Playback buffer\n", __func__);
+ ret = -ETIMEDOUT;
+ } else {
+ pr_err("%s: playback copy was interrupted\n", __func__);
+ }
+
+done:
+ return ret;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t hwoff,
+ void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ int count = 0;
+ struct hpcm_buf_node *buf_node = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hpcm_drv *prtd = runtime->private_data;
+ struct dai_data *dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
+ unsigned long dsp_flags;
+
+ if (dai_data == NULL) {
+ pr_err("%s, dai_data is null\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ count = frames_to_bytes(runtime, frames);
+
+ ret = wait_event_interruptible_timeout(dai_data->queue_wait,
+ (!list_empty(&dai_data->filled_queue) ||
+ dai_data->state == HPCM_STOPPED),
+ 1 * HZ);
+
+ if (ret > 0) {
+ if (count <= HPCM_MAX_VOC_PKT_SIZE) {
+ spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
+ buf_node = list_first_entry(&dai_data->filled_queue,
+ struct hpcm_buf_node, list);
+ list_del(&buf_node->list);
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+ ret = copy_to_user(buf, &buf_node->frame.voc_pkt,
+ buf_node->frame.len);
+ if (ret) {
+ pr_err("%s: Copy to user returned %d\n",
+ __func__, ret);
+ ret = -EFAULT;
+ }
+ spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
+ list_add_tail(&buf_node->list, &dai_data->free_queue);
+ spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
+
+ } else {
+ pr_err("%s: Read count %d > HPCM_MAX_VOC_PKT_SIZE\n",
+ __func__, count);
+ ret = -ENOMEM;
+ }
+
+ } else if (ret == 0) {
+ pr_err("%s: No Caputre data available\n", __func__);
+ ret = -ETIMEDOUT;
+ } else {
+ pr_err("%s: Read was interrupted\n", __func__);
+ ret = -ERESTARTSYS;
+ }
+
+done:
+ return ret;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int channel,
+ snd_pcm_uframes_t hwoff, void __user *buf,
+ snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_copy(substream, channel,
+ hwoff, buf, frames);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_copy(substream, channel,
+ hwoff, buf, frames);
+
+ return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct dai_data *dai_data = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hpcm_drv *prtd = runtime->private_data;
+ snd_pcm_uframes_t ret;
+
+ dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
+
+ if (dai_data == NULL) {
+ pr_err("%s, dai_data is null\n", __func__);
+
+ ret = 0;
+ goto done;
+ }
+
+ if (dai_data->pcm_irq_pos >= dai_data->pcm_size)
+ dai_data->pcm_irq_pos = 0;
+
+ ret = bytes_to_frames(runtime, (dai_data->pcm_irq_pos));
+
+done:
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hpcm_drv *prtd = runtime->private_data;
+ struct dai_data *dai_data =
+ hpcm_get_dai_data(substream->pcm->id, prtd);
+
+ if (dai_data == NULL) {
+ pr_err("%s, dai_data is null\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s, %s\n", __func__, substream->pcm->id);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pr_debug("SNDRV_PCM_TRIGGER_START\n");
+ dai_data->state = HPCM_STARTED;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ dai_data->state = HPCM_STOPPED;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+done:
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hpcm_drv *prtd = runtime->private_data;
+ struct dai_data *dai_data = NULL;
+ struct tap_point *tp = NULL;
+
+ pr_debug("%s, %s\n", __func__, substream->pcm->id);
+ mutex_lock(&prtd->lock);
+
+ dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
+
+ if (dai_data == NULL) {
+ pr_err("%s, dai_data is null\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ dai_data->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ dai_data->pcm_count = snd_pcm_lib_period_bytes(substream);
+ dai_data->pcm_irq_pos = 0;
+ dai_data->pcm_buf_pos = 0;
+ dai_data->state = HPCM_PREPARED;
+
+ /* Register event notify processing callback in prepare instead of
+ * init() as q6voice module's init() can be called at a later point
+ */
+ voc_register_hpcm_evt_cb(hpcm_notify_evt_processing, &hpcm_drv);
+
+ tp = hpcm_get_tappoint_data(substream->pcm->id, prtd);
+ if (tp != NULL) {
+ ret = hpcm_start_vocpcm(substream->pcm->id, prtd, tp);
+ if (ret) {
+ pr_err("error sending start cmd err=%d\n", ret);
+ goto done;
+ }
+ } else {
+ pr_err("%s tp is NULL\n", __func__);
+ }
+done:
+ mutex_unlock(&prtd->lock);
+ return ret;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct hpcm_drv *prtd = (struct hpcm_drv *)runtime->private_data;
+ int ret = 0;
+
+ pr_debug("%s: %s\n", __func__, substream->pcm->id);
+ mutex_lock(&prtd->lock);
+
+ /* Allocate and map voice host PCM ion buffer */
+ if (prtd->session[prtd->mixer_conf.sess_indx].sess_paddr == 0) {
+ ret = hpcm_allocate_shared_memory(prtd);
+ if (ret) {
+ pr_err("error creating shared memory err=%d\n", ret);
+ goto done;
+ }
+
+ ret = hpcm_map_vocpcm_memory(prtd);
+ if (ret) {
+ pr_err("error mapping shared memory err=%d\n", ret);
+ hpcm_free_allocated_mem(prtd);
+ goto done;
+ }
+ } else {
+ pr_debug("%s, VHPCM memory allocation/mapping not performed\n"
+ , __func__);
+ }
+
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+
+ dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max,
+ &dma_buf->addr, GFP_KERNEL);
+
+ if (!dma_buf->area) {
+ pr_err("%s:MSM dma_alloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ dma_buf->bytes = runtime->hw.buffer_bytes_max;
+ memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+
+ hpcm_create_free_queue(dma_buf,
+ hpcm_get_dai_data(substream->pcm->id, prtd));
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+done:
+ mutex_unlock(&prtd->lock);
+ return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hpcm_drv *prtd = &hpcm_drv;
+ struct tappnt_mxr_data *tmd = NULL;
+ struct dai_data *dai_data = NULL;
+ int ret = 0;
+ int tp_val = 0;
+
+ pr_debug("%s, %s\n", __func__, substream->pcm->id);
+ mutex_lock(&prtd->lock);
+
+ dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
+
+ if (dai_data == NULL) {
+ pr_err("%s, dai_data is null\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ runtime->hw = msm_pcm_hardware;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret < 0)
+ pr_debug("snd_pcm_hw_constraint_list failed\n");
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ pr_debug("snd_pcm_hw_constraint_integer failed\n");
+ goto done;
+ }
+
+ tp_val = get_tappnt_value(substream->pcm->id);
+ tmd = hpcm_get_tappnt_mixer_data(substream->pcm->id, prtd);
+
+ /* Check wheather the kcontrol values set are valid */
+ if (!tmd ||
+ !(tmd->enable) ||
+ !hpcm_is_valid_config(prtd->mixer_conf.sess_indx,
+ tp_val, tmd->direction,
+ tmd->sample_rate)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ dai_data->substream = substream;
+ runtime->private_data = prtd;
+
+done:
+ mutex_unlock(&prtd->lock);
+ return ret;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+ .pointer = msm_pcm_pointer,
+ .copy = msm_pcm_copy,
+ .close = msm_pcm_close,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+
+ pr_debug("%s:\n", __func__);
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ return 0;
+}
+
+static int msm_pcm_hpcm_probe(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, msm_hpcm_controls,
+ ARRAY_SIZE(msm_hpcm_controls));
+
+ return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+ .probe = msm_pcm_hpcm_probe,
+};
+
+static int msm_pcm_probe(struct platform_device *pdev)
+{
+
+ pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ return snd_soc_register_platform(&pdev->dev, &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_voice_host_pcm_dt_match[] = {
+ {.compatible = "qcom,msm-voice-host-pcm"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_voice_host_pcm_dt_match);
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-voice-host-pcm",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_voice_host_pcm_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = msm_pcm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ int i = 0;
+ struct session *s = NULL;
+
+ memset(&hpcm_drv, 0, sizeof(hpcm_drv));
+ mutex_init(&hpcm_drv.lock);
+
+ for (i = 0; i < MAX_SESSION; i++) {
+ s = &hpcm_drv.session[i];
+ spin_lock_init(&s->rx_tap_point.capture_dai_data.dsp_lock);
+ spin_lock_init(&s->rx_tap_point.playback_dai_data.dsp_lock);
+ spin_lock_init(&s->tx_tap_point.capture_dai_data.dsp_lock);
+ spin_lock_init(&s->tx_tap_point.playback_dai_data.dsp_lock);
+
+ init_waitqueue_head(
+ &s->rx_tap_point.capture_dai_data.queue_wait);
+ init_waitqueue_head(
+ &s->rx_tap_point.playback_dai_data.queue_wait);
+ init_waitqueue_head(
+ &s->tx_tap_point.capture_dai_data.queue_wait);
+ init_waitqueue_head(
+ &s->tx_tap_point.playback_dai_data.queue_wait);
+
+ INIT_LIST_HEAD(&s->rx_tap_point.capture_dai_data.filled_queue);
+ INIT_LIST_HEAD(&s->rx_tap_point.capture_dai_data.free_queue);
+ INIT_LIST_HEAD(&s->rx_tap_point.playback_dai_data.filled_queue);
+ INIT_LIST_HEAD(&s->rx_tap_point.playback_dai_data.free_queue);
+
+ INIT_LIST_HEAD(&s->tx_tap_point.capture_dai_data.filled_queue);
+ INIT_LIST_HEAD(&s->tx_tap_point.capture_dai_data.free_queue);
+ INIT_LIST_HEAD(&s->tx_tap_point.playback_dai_data.filled_queue);
+ INIT_LIST_HEAD(&s->tx_tap_point.playback_dai_data.free_queue);
+ }
+
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
new file mode 100644
index 0000000..5072ecd
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -0,0 +1,790 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <asm/dma.h>
+
+#include "msm-pcm-routing-v2.h"
+
+#define LOOPBACK_VOL_MAX_STEPS 0x2000
+#define LOOPBACK_SESSION_MAX 4
+
+static DEFINE_MUTEX(loopback_session_lock);
+static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
+ LOOPBACK_VOL_MAX_STEPS);
+
+struct msm_pcm_loopback {
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ int instance;
+
+ struct mutex lock;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+
+ int playback_start;
+ int capture_start;
+ int session_id;
+ struct audio_client *audio_client;
+ uint32_t volume;
+};
+
+struct fe_dai_session_map {
+ char stream_name[32];
+ struct msm_pcm_loopback *loopback_priv;
+};
+
+static struct fe_dai_session_map session_map[LOOPBACK_SESSION_MAX] = {
+ { {}, NULL},
+ { {}, NULL},
+ { {}, NULL},
+ { {}, NULL},
+};
+
+static u32 hfp_tx_mute;
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd,
+ struct msm_pcm_loopback **pcm);
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_pcm_loopback *pcm = priv_data;
+
+ WARN_ON(!pcm);
+
+ pr_debug("%s: event 0x%x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_DEVSWITCH:
+ q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+ q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+ q6asm_run(pcm->audio_client, 0, 0, 0);
+ /* fallthrough */
+ default:
+ pr_err("%s: default event 0x%x\n", __func__, event);
+ break;
+ }
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ pr_debug("%s:\n", __func__);
+ switch (opcode) {
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ pr_err("%s: Not Supported Event opcode[0x%x]\n",
+ __func__, opcode);
+ break;
+ }
+}
+
+static int msm_loopback_session_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = hfp_tx_mute;
+ return 0;
+}
+
+static int msm_loopback_session_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0, n = 0;
+ int mute = ucontrol->value.integer.value[0];
+ struct msm_pcm_loopback *pcm = NULL;
+
+ if ((mute < 0) || (mute > 1)) {
+ pr_err(" %s Invalid arguments", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: mute=%d\n", __func__, mute);
+ hfp_tx_mute = mute;
+ for (n = 0; n < LOOPBACK_SESSION_MAX; n++) {
+ if (!strcmp(session_map[n].stream_name, "MultiMedia6"))
+ pcm = session_map[n].loopback_priv;
+ }
+ if (pcm && pcm->audio_client) {
+ ret = q6asm_set_mute(pcm->audio_client, mute);
+ if (ret < 0)
+ pr_err("%s: Send mute command failed rc=%d\n",
+ __func__, ret);
+ }
+done:
+ return ret;
+}
+
+static struct snd_kcontrol_new msm_loopback_controls[] = {
+ SOC_SINGLE_EXT("HFP TX Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_loopback_session_mute_get,
+ msm_loopback_session_mute_put),
+};
+
+static int msm_pcm_loopback_probe(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, msm_loopback_controls,
+ ARRAY_SIZE(msm_loopback_controls));
+
+ return 0;
+}
+static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd,
+ uint32_t volume)
+{
+ int rc = -EINVAL;
+
+ pr_debug("%s: Setting volume 0x%x\n", __func__, volume);
+
+ if (prtd && prtd->audio_client) {
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
+static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd,
+ struct msm_pcm_loopback **pcm)
+{
+ int ret = 0;
+ int n, index = -1;
+
+ dev_dbg(rtd->platform->dev, "%s: stream %s\n", __func__,
+ rtd->dai_link->stream_name);
+
+ mutex_lock(&loopback_session_lock);
+ for (n = 0; n < LOOPBACK_SESSION_MAX; n++) {
+ if (!strcmp(rtd->dai_link->stream_name,
+ session_map[n].stream_name)) {
+ *pcm = session_map[n].loopback_priv;
+ goto exit;
+ }
+ /*
+ * Store the min index value for allocating a new session.
+ * Here, if session stream name is not found in the
+ * existing entries after the loop iteration, then this
+ * index will be used to allocate the new session.
+ * This index variable is expected to point to the topmost
+ * available free session.
+ */
+ if (!(session_map[n].stream_name[0]) && (index < 0))
+ index = n;
+ }
+
+ if (index < 0) {
+ dev_err(rtd->platform->dev, "%s: Max Sessions allocated\n",
+ __func__);
+ ret = -EAGAIN;
+ goto exit;
+ }
+
+ session_map[index].loopback_priv = kzalloc(
+ sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+ if (!session_map[index].loopback_priv) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ strlcpy(session_map[index].stream_name,
+ rtd->dai_link->stream_name,
+ sizeof(session_map[index].stream_name));
+ dev_dbg(rtd->platform->dev, "%s: stream %s index %d\n",
+ __func__, session_map[index].stream_name, index);
+
+ mutex_init(&session_map[index].loopback_priv->lock);
+ *pcm = session_map[index].loopback_priv;
+exit:
+ mutex_unlock(&loopback_session_lock);
+ return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct msm_pcm_loopback *pcm = NULL;
+ int ret = 0;
+ uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_evt event;
+ struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
+ uint32_t param_id;
+
+ ret = msm_pcm_loopback_get_session(rtd, &pcm);
+ if (ret)
+ return ret;
+
+ mutex_lock(&pcm->lock);
+
+ pcm->volume = 0x2000;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_substream = substream;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_substream = substream;
+
+ pcm->instance++;
+ dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+ pcm->instance, substream->stream);
+ if (pcm->instance == 2) {
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+ if (pcm->audio_client != NULL)
+ stop_pcm(pcm);
+
+ pcm->audio_client = q6asm_audio_client_alloc(
+ (app_cb)msm_pcm_loopback_event_handler, pcm);
+ if (!pcm->audio_client) {
+ dev_err(rtd->platform->dev,
+ "%s: Could not allocate memory\n", __func__);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ pcm->session_id = pcm->audio_client->session;
+ pcm->audio_client->perf_mode = false;
+ ret = q6asm_open_loopback_v2(pcm->audio_client,
+ bits_per_sample);
+ if (ret < 0) {
+ dev_err(rtd->platform->dev,
+ "%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(pcm->audio_client);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) pcm;
+ msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->capture_substream->stream);
+ msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->playback_substream->stream,
+ event);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pcm->playback_substream = substream;
+ ret = pcm_loopback_set_volume(pcm, pcm->volume);
+ if (ret < 0)
+ dev_err(rtd->platform->dev,
+ "Error %d setting volume", ret);
+ }
+ /* Set to largest negative value */
+ asm_mtmx_strtr_window.window_lsw = 0x00000000;
+ asm_mtmx_strtr_window.window_msw = 0x80000000;
+ param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2;
+ q6asm_send_mtmx_strtr_window(pcm->audio_client,
+ &asm_mtmx_strtr_window,
+ param_id);
+ /* Set to largest positive value */
+ asm_mtmx_strtr_window.window_lsw = 0xffffffff;
+ asm_mtmx_strtr_window.window_msw = 0x7fffffff;
+ param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2;
+ q6asm_send_mtmx_strtr_window(pcm->audio_client,
+ &asm_mtmx_strtr_window,
+ param_id);
+ }
+ dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+ __func__, pcm->instance, substream->pcm->id);
+ runtime->private_data = pcm;
+
+ mutex_unlock(&pcm->lock);
+
+ return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+ struct snd_soc_pcm_runtime *soc_pcm_rx;
+ struct snd_soc_pcm_runtime *soc_pcm_tx;
+
+ if (pcm->audio_client == NULL)
+ return;
+ q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+ if (pcm->playback_substream != NULL) {
+ soc_pcm_rx = pcm->playback_substream->private_data;
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ if (pcm->capture_substream != NULL) {
+ soc_pcm_tx = pcm->capture_substream->private_data;
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ }
+ q6asm_audio_client_free(pcm->audio_client);
+ pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ int ret = 0, n;
+ bool found = false;
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_start = 0;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_start = 0;
+
+ pcm->instance--;
+ if (!pcm->playback_start || !pcm->capture_start) {
+ dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+ stop_pcm(pcm);
+ }
+
+ if (!pcm->instance) {
+ mutex_lock(&loopback_session_lock);
+ for (n = 0; n < LOOPBACK_SESSION_MAX; n++) {
+ if (!strcmp(rtd->dai_link->stream_name,
+ session_map[n].stream_name)) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ memset(session_map[n].stream_name, 0,
+ sizeof(session_map[n].stream_name));
+ mutex_unlock(&pcm->lock);
+ mutex_destroy(&session_map[n].loopback_priv->lock);
+ session_map[n].loopback_priv = NULL;
+ kfree(pcm);
+ dev_dbg(rtd->platform->dev, "%s: stream freed %s\n",
+ __func__, rtd->dai_link->stream_name);
+ mutex_unlock(&loopback_session_lock);
+ return 0;
+ }
+ mutex_unlock(&loopback_session_lock);
+ }
+ mutex_unlock(&pcm->lock);
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!pcm->playback_start)
+ pcm->playback_start = 1;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!pcm->capture_start)
+ pcm->capture_start = 1;
+ }
+ mutex_unlock(&pcm->lock);
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(rtd->platform->dev,
+ "%s: playback_start:%d,capture_start:%d\n", __func__,
+ pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(rtd->platform->dev,
+ "%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+ __func__, pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+ break;
+ default:
+ pr_err("%s: default cmd %d\n", __func__, cmd);
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+};
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = kcontrol->private_data;
+ struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
+ struct msm_pcm_loopback *prtd;
+ int volume = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: volume : 0x%x\n", __func__, volume);
+ if ((!substream) || (!substream->runtime)) {
+ pr_err("%s substream or runtime not found\n", __func__);
+ rc = -ENODEV;
+ goto exit;
+ }
+ prtd = substream->runtime->private_data;
+ if (!prtd) {
+ rc = -ENODEV;
+ goto exit;
+ }
+ rc = pcm_loopback_set_volume(prtd, volume);
+
+exit:
+ return rc;
+}
+
+static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_pcm_loopback *prtd;
+
+ pr_debug("%s\n", __func__);
+ if ((!substream) || (!substream->runtime)) {
+ pr_err("%s substream or runtime not found\n", __func__);
+ rc = -ENODEV;
+ goto exit;
+ }
+ prtd = substream->runtime->private_data;
+ if (!prtd) {
+ rc = -ENODEV;
+ goto exit;
+ }
+ ucontrol->value.integer.value[0] = prtd->volume;
+
+exit:
+ return rc;
+}
+
+static int msm_pcm_add_volume_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+ int ret = 0;
+
+ dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1,
+ rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0)
+ return ret;
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->get = msm_pcm_volume_ctl_get;
+ kctl->tlv.p = loopback_rx_vol_gain;
+ return 0;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+
+ return 0;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_RX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+
+ return 0;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_TX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_usr *app_type_info;
+ struct snd_kcontrol *kctl;
+ const char *playback_mixer_ctl_name = "Audio Stream";
+ const char *capture_mixer_ctl_name = "Audio Stream Capture";
+ const char *deviceNo = "NN";
+ const char *suffix = "App Type Cfg";
+ int ctl_len, ret = 0;
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Playback app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, ctl_len, rtd->dai_link->be_id,
+ &app_type_info);
+ if (ret < 0)
+ return ret;
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ playback_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
+ }
+
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Capture app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ NULL, 1, ctl_len, rtd->dai_link->be_id,
+ &app_type_info);
+ if (ret < 0)
+ return ret;
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ capture_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ ret = msm_pcm_add_volume_controls(rtd);
+ if (ret)
+ pr_err("%s: pcm add volume controls failed:%d\n",
+ __func__, ret);
+ ret = msm_pcm_add_app_type_controls(rtd);
+ if (ret)
+ pr_err("%s: pcm add app type controls failed:%d\n",
+ __func__, ret);
+ return ret;
+}
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_pcm_add_controls(rtd);
+ if (ret)
+ dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+ .probe = msm_pcm_loopback_probe,
+};
+
+static int msm_pcm_probe(struct platform_device *pdev)
+{
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_pcm_loopback_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-loopback"},
+ {}
+};
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-loopback",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_loopback_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = msm_pcm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
new file mode 100644
index 0000000..1fdb878
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
@@ -0,0 +1,845 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6audio-v2.h>
+#include <sound/timer.h>
+#include <asm/dma.h>
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+
+#include "msm-pcm-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+
+#define PCM_MASTER_VOL_MAX_STEPS 0x2000
+static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
+ PCM_MASTER_VOL_MAX_STEPS);
+
+struct snd_msm {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+};
+
+#define CMD_EOS_MIN_TIMEOUT_LENGTH 50
+#define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50)
+
+#define ATRACE_END() \
+ trace_printk("tracing_mark_write: E\n")
+#define ATRACE_BEGIN(name) \
+ trace_printk("tracing_mark_write: B|%d|%s\n", current->tgid, name)
+#define ATRACE_FUNC() ATRACE_BEGIN(__func__)
+#define ATRACE_INT(name, value) \
+ trace_printk("tracing_mark_write: C|%d|%s|%d\n", \
+ current->tgid, name, (int)(value))
+
+#define SIO_PLAYBACK_MAX_PERIOD_SIZE PLAYBACK_MAX_PERIOD_SIZE
+#define SIO_PLAYBACK_MIN_PERIOD_SIZE 48
+#define SIO_PLAYBACK_MAX_NUM_PERIODS 512
+#define SIO_PLAYBACK_MIN_NUM_PERIODS PLAYBACK_MIN_NUM_PERIODS
+#define SIO_PLAYBACK_MIN_BYTES (SIO_PLAYBACK_MIN_NUM_PERIODS * \
+ SIO_PLAYBACK_MIN_PERIOD_SIZE)
+
+#define SIO_PLAYBACK_MAX_BYTES ((SIO_PLAYBACK_MAX_NUM_PERIODS) * \
+ (SIO_PLAYBACK_MAX_PERIOD_SIZE))
+
+#define SIO_CAPTURE_MAX_PERIOD_SIZE CAPTURE_MAX_PERIOD_SIZE
+#define SIO_CAPTURE_MIN_PERIOD_SIZE 48
+#define SIO_CAPTURE_MAX_NUM_PERIODS 512
+#define SIO_CAPTURE_MIN_NUM_PERIODS CAPTURE_MIN_NUM_PERIODS
+
+#define SIO_CAPTURE_MIN_BYTES (SIO_CAPTURE_MIN_NUM_PERIODS * \
+ SIO_CAPTURE_MIN_PERIOD_SIZE)
+
+#define SIO_CAPTURE_MAX_BYTES (SIO_CAPTURE_MAX_NUM_PERIODS * \
+ SIO_CAPTURE_MAX_PERIOD_SIZE)
+
+static struct snd_pcm_hardware msm_pcm_hardware_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = SIO_PLAYBACK_MAX_NUM_PERIODS *
+ SIO_PLAYBACK_MAX_PERIOD_SIZE,
+ .period_bytes_min = SIO_PLAYBACK_MIN_PERIOD_SIZE,
+ .period_bytes_max = SIO_PLAYBACK_MAX_PERIOD_SIZE,
+ .periods_min = SIO_PLAYBACK_MIN_NUM_PERIODS,
+ .periods_max = SIO_PLAYBACK_MAX_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 4,
+ .buffer_bytes_max = SIO_CAPTURE_MAX_NUM_PERIODS *
+ SIO_CAPTURE_MAX_PERIOD_SIZE,
+ .period_bytes_min = SIO_CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = SIO_CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = SIO_CAPTURE_MIN_NUM_PERIODS,
+ .periods_max = SIO_CAPTURE_MAX_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+ 88200, 96000, 176400, 192000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ uint32_t *ptrmem = (uint32_t *)payload;
+
+ switch (opcode) {
+ case ASM_DATA_EVENT_WATERMARK:
+ pr_debug("%s: Watermark level = 0x%08x\n", __func__, *ptrmem);
+ break;
+ case APR_BASIC_RSP_RESULT:
+ pr_debug("%s: Payload = [0x%x]stat[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ switch (payload[0]) {
+ case ASM_SESSION_CMD_RUN_V2:
+ case ASM_SESSION_CMD_PAUSE:
+ case ASM_STREAM_CMD_FLUSH:
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd;
+ int ret = 0;
+
+ prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ prtd->substream = substream;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = msm_pcm_hardware_playback;
+ else
+ runtime->hw = msm_pcm_hardware_capture;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret)
+ pr_info("snd_pcm_hw_constraint_list failed\n");
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret)
+ pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ SIO_PLAYBACK_MIN_BYTES,
+ SIO_PLAYBACK_MAX_BYTES);
+ if (ret) {
+ pr_info("%s: P buffer bytes minmax constraint ret %d\n",
+ __func__, ret);
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ SIO_CAPTURE_MIN_BYTES,
+ SIO_CAPTURE_MAX_BYTES);
+ if (ret) {
+ pr_info("%s: C buffer bytes minmax constraint ret %d\n",
+ __func__, ret);
+ }
+ }
+
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+ if (ret) {
+ pr_err("%s: Constraint for period bytes step ret = %d\n",
+ __func__, ret);
+ }
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+ if (ret) {
+ pr_err("%s: Constraint for buffer bytes step ret = %d\n",
+ __func__, ret);
+ }
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)event_handler, prtd);
+ if (!prtd->audio_client) {
+ pr_err("%s: client alloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto fail_cmd;
+ }
+ prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
+ runtime->private_data = prtd;
+ return 0;
+
+fail_cmd:
+ kfree(prtd);
+ return ret;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd = runtime->private_data;
+ struct msm_plat_data *pdata;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct audio_buffer *buf;
+ struct shared_io_config config;
+ uint16_t sample_word_size;
+ uint16_t bits_per_sample;
+ int ret;
+ int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT;
+
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->dev);
+ if (!pdata) {
+ ret = -EINVAL;
+ pr_err("%s: platform data not populated ret: %d\n", __func__,
+ ret);
+ return ret;
+ }
+
+ /* need to set LOW_LATENCY_PCM_MODE for capture since
+ * push mode does not support ULL
+ */
+ prtd->audio_client->perf_mode = (dir == IN) ?
+ pdata->perf_mode :
+ LOW_LATENCY_PCM_MODE;
+
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = params_rate(params);
+ prtd->channel_mode = params_channels(params);
+ if (prtd->enabled)
+ return 0;
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bits_per_sample = 24;
+ sample_word_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bits_per_sample = 16;
+ sample_word_size = 16;
+ break;
+ }
+
+ config.format = FORMAT_LINEAR_PCM;
+ config.bits_per_sample = bits_per_sample;
+ config.rate = params_rate(params);
+ config.channels = params_channels(params);
+ config.sample_word_size = sample_word_size;
+ config.bufsz = params_buffer_bytes(params) / params_periods(params);
+ config.bufcnt = params_periods(params);
+
+ ret = q6asm_open_shared_io(prtd->audio_client, &config, dir);
+ if (ret) {
+ pr_err("%s: q6asm_open_write_shared_io failed ret: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ prtd->pcm_size = params_buffer_bytes(params);
+ prtd->pcm_count = params_buffer_bytes(params);
+ prtd->pcm_irq_pos = 0;
+
+ buf = prtd->audio_client->port[dir].buf;
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = buf->data;
+ dma_buf->addr = buf->phys;
+ dma_buf->bytes = prtd->pcm_size;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ pr_debug("%s: session ID %d, perf %d\n", __func__,
+ prtd->audio_client->session,
+ prtd->audio_client->perf_mode);
+ prtd->session_id = prtd->audio_client->session;
+
+ pr_debug("msm_pcm_routing_reg_phy_stream w/ id %d\n",
+ soc_prtd->dai_link->be_id);
+ ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id, substream->stream);
+
+ if (ret) {
+ pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
+ return ret;
+ }
+
+ atomic_set(&prtd->out_count, runtime->periods);
+ prtd->enabled = 1;
+ prtd->cmd_pending = 0;
+ prtd->cmd_interrupt = 0;
+
+ return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+ struct audio_buffer *buf;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: %s Trigger start\n", __func__,
+ dir == 0 ? "P" : "C");
+ ret = q6asm_run(prtd->audio_client, 0, 0, 0);
+ if (ret)
+ break;
+ atomic_set(&prtd->start, 1);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);
+ atomic_set(&prtd->start, 0);
+ q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+ q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ buf = q6asm_shared_io_buf(prtd->audio_client, dir);
+ if (buf == NULL) {
+ pr_err("%s: shared IO buffer is null\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+ memset(buf->data, 0, buf->actual_size);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("%s: SNDRV_PCM_TRIGGER_PAUSE\n", __func__);
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->start, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+ struct audio_buffer *buf;
+
+ switch (cmd) {
+ case SNDRV_PCM_IOCTL1_RESET:
+ pr_debug("%s: %s SNDRV_PCM_IOCTL1_RESET\n", __func__,
+ dir == 0 ? "P" : "C");
+ buf = q6asm_shared_io_buf(prtd->audio_client, dir);
+
+ if (buf && buf->data)
+ memset(buf->data, 0, buf->actual_size);
+ break;
+ default:
+ break;
+ }
+
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ uint32_t read_index, wall_clk_msw, wall_clk_lsw;
+ /*these are offsets, unlike ASoC's full values*/
+ snd_pcm_sframes_t hw_ptr;
+ snd_pcm_sframes_t period_size;
+ int ret;
+ int retries = 10;
+ struct msm_audio *prtd = runtime->private_data;
+
+ period_size = runtime->period_size;
+
+ do {
+ ret = q6asm_get_shared_pos(prtd->audio_client,
+ &read_index, &wall_clk_msw,
+ &wall_clk_lsw);
+ } while (ret == -EAGAIN && --retries);
+
+ if (ret || !period_size) {
+ pr_err("get_shared_pos error or zero period size\n");
+ return 0;
+ }
+
+ hw_ptr = bytes_to_frames(substream->runtime,
+ read_index);
+
+ if (runtime->control->appl_ptr == 0) {
+ pr_debug("ptr(%s): appl(0), hw = %lu read_index = %u\n",
+ prtd->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "P" : "C",
+ hw_ptr, read_index);
+ }
+ return (hw_ptr/period_size) * period_size;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ return -EINVAL;
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ struct audio_client *ac = prtd->audio_client;
+ struct audio_port_data *apd = ac->port;
+ struct audio_buffer *ab;
+ int dir = -1;
+ int ret;
+
+ pr_debug("%s: mmap begin\n", __func__);
+ prtd->mmap_flag = 1;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+
+ ab = &(apd[dir].buf[0]);
+
+ ret = msm_audio_ion_mmap(ab, vma);
+
+ if (ret)
+ prtd->mmap_flag = 0;
+
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ if (!prtd || !prtd->mmap_flag)
+ return -EIO;
+
+ return 0;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd = runtime->private_data;
+ struct audio_client *ac = prtd->audio_client;
+ uint32_t timeout;
+ int dir = 0;
+ int ret = 0;
+
+ if (ac) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ dir = OUT;
+
+ /* determine timeout length */
+ if (runtime->frame_bits == 0 || runtime->rate == 0) {
+ timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
+ } else {
+ timeout = (runtime->period_size *
+ CMD_EOS_TIMEOUT_MULTIPLIER) /
+ ((runtime->frame_bits / 8) *
+ runtime->rate);
+ if (timeout < CMD_EOS_MIN_TIMEOUT_LENGTH)
+ timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
+ }
+
+ q6asm_cmd(ac, CMD_CLOSE);
+
+ ret = q6asm_shared_io_free(ac, dir);
+
+ if (ret) {
+ pr_err("%s: Failed to close pull mode, ret %d\n",
+ __func__, ret);
+ }
+ q6asm_audio_client_free(ac);
+ }
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ dir == IN ?
+ SNDRV_PCM_STREAM_PLAYBACK :
+ SNDRV_PCM_STREAM_CAPTURE);
+ kfree(prtd);
+ return 0;
+}
+
+static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
+{
+ int rc = 0;
+
+ if (prtd && prtd->audio_client) {
+ pr_debug("%s: channels %d volume 0x%x\n", __func__,
+ prtd->channel_mode, volume);
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
+ }
+ }
+ return rc;
+}
+
+static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s\n", __func__);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->volume;
+ return 0;
+}
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+ int volume = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: volume : 0x%x\n", __func__, volume);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ rc = msm_pcm_set_volume(prtd, volume);
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
+static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+
+ dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0) {
+ pr_err("%s volume control failed ret %d\n", __func__, ret);
+ return ret;
+ }
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->get = msm_pcm_volume_ctl_get;
+ kctl->tlv.p = msm_pcm_vol_gain;
+ return 0;
+}
+
+static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s", __func__);
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ prtd->set_channel_map = true;
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ prtd->channel_map[i] =
+ (char)(ucontrol->value.integer.value[i]);
+ }
+ return 0;
+}
+
+static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s", __func__);
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(ucontrol->value.integer.value));
+ if (!substream->runtime)
+ return 0; /* no channels set */
+
+ prtd = substream->runtime->private_data;
+
+ if (prtd && prtd->set_channel_map == true) {
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] =
+ (int)prtd->channel_map[i];
+ } else {
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] = 0;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_add_chmap_control(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_chmap *chmap_info;
+ struct snd_kcontrol *kctl;
+ char device_num[12];
+ int i, ret;
+
+ pr_debug("%s, Channel map cntrl add\n", __func__);
+ ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_std_chmaps,
+ PCM_FORMAT_MAX_NUM_CHANNEL, 0,
+ &chmap_info);
+ if (ret)
+ return ret;
+
+ kctl = chmap_info->kctl;
+ for (i = 0; i < kctl->count; i++)
+ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ snprintf(device_num, sizeof(device_num), "%d", pcm->device);
+ strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
+ pr_debug("%s, Overwriting channel map control name to: %s",
+ __func__, kctl->id.name);
+ kctl->put = msm_pcm_chmap_ctl_put;
+ kctl->get = msm_pcm_chmap_ctl_get;
+ return 0;
+}
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
+ int ret;
+
+ pr_debug("%s , register new control\n", __func__);
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_pcm_add_chmap_control(rtd);
+ if (ret) {
+ pr_err("%s failed to add chmap cntls\n", __func__);
+ goto exit;
+ }
+ ret = msm_pcm_add_volume_control(rtd);
+ if (ret) {
+ pr_err("%s: Could not add pcm Volume Control %d\n",
+ __func__, ret);
+ }
+ pcm->nonatomic = true;
+exit:
+ return ret;
+}
+
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .prepare = msm_pcm_prepare,
+ .copy = msm_pcm_copy,
+ .hw_params = msm_pcm_hw_params,
+ .ioctl = msm_pcm_ioctl,
+ .trigger = msm_pcm_trigger,
+ .pointer = msm_pcm_pointer,
+ .mmap = msm_pcm_mmap,
+ .close = msm_pcm_close,
+};
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static int msm_pcm_probe(struct platform_device *pdev)
+{
+ int rc;
+ struct msm_plat_data *pdata;
+ const char *latency_level;
+ int perf_mode = LOW_LATENCY_PCM_MODE;
+
+ dev_dbg(&pdev->dev, "Pull mode driver probe\n");
+
+ if (of_property_read_bool(pdev->dev.of_node,
+ "qcom,msm-pcm-low-latency")) {
+
+ rc = of_property_read_string(pdev->dev.of_node,
+ "qcom,latency-level", &latency_level);
+ if (!rc && !strcmp(latency_level, "ultra"))
+ perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_plat_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->perf_mode = perf_mode;
+
+ dev_set_drvdata(&pdev->dev, pdata);
+
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+ dev_dbg(&pdev->dev, "Pull mode driver register\n");
+ rc = snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+
+ if (rc)
+ dev_err(&pdev->dev, "Failed to register pull mode driver\n");
+
+ return rc;
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ struct msm_plat_data *pdata;
+
+ dev_dbg(&pdev->dev, "Pull mode remove\n");
+ pdata = dev_get_drvdata(&pdev->dev);
+ devm_kfree(&pdev->dev, pdata);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+static const struct of_device_id msm_pcm_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-dsp-noirq"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
+
+static struct platform_driver msm_pcm_driver_noirq = {
+ .driver = {
+ .name = "msm-pcm-dsp-noirq",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = msm_pcm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver_noirq);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver_noirq);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM NOIRQ module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
new file mode 100644
index 0000000..8ec4652
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -0,0 +1,1515 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6audio-v2.h>
+#include <sound/timer.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
+
+#include <linux/of_device.h>
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+
+#include "msm-pcm-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+
+enum stream_state {
+ IDLE = 0,
+ STOPPED,
+ RUNNING,
+};
+
+static struct audio_locks the_locks;
+
+#define PCM_MASTER_VOL_MAX_STEPS 0x2000
+static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
+ PCM_MASTER_VOL_MAX_STEPS);
+
+struct snd_msm {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+};
+
+#define CMD_EOS_MIN_TIMEOUT_LENGTH 50
+#define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50)
+#define MAX_PB_COPY_RETRIES 3
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 4,
+ .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
+ CAPTURE_MAX_PERIOD_SIZE,
+ .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = CAPTURE_MIN_NUM_PERIODS,
+ .periods_max = CAPTURE_MAX_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .rates = SNDRV_PCM_RATE_8000_384000,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS *
+ PLAYBACK_MAX_PERIOD_SIZE,
+ .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+ .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
+ .periods_min = PLAYBACK_MIN_NUM_PERIODS,
+ .periods_max = PLAYBACK_MAX_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+ 88200, 96000, 176400, 192000, 384000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_audio *prtd = priv_data;
+
+ WARN_ON(!prtd);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_BUF_RECFG:
+ q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+ q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ q6asm_run(prtd->audio_client, 0, 0, 0);
+ /* fallthrough */
+ default:
+ break;
+ }
+}
+
+static void event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ struct msm_audio *prtd = priv;
+ struct snd_pcm_substream *substream = prtd->substream;
+ uint32_t *ptrmem = (uint32_t *)payload;
+ uint32_t idx = 0;
+ uint32_t size = 0;
+ uint8_t buf_index;
+
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE_V2: {
+ pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
+ pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+ prtd->pcm_irq_pos += prtd->pcm_count;
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ atomic_inc(&prtd->out_count);
+ wake_up(&the_locks.write_wait);
+ if (!atomic_read(&prtd->start))
+ break;
+ if (!prtd->mmap_flag || prtd->reset_event)
+ break;
+ if (q6asm_is_cpu_buf_avail_nolock(IN,
+ prtd->audio_client,
+ &size, &idx)) {
+ pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+ __func__, prtd->pcm_count);
+ q6asm_write_nolock(prtd->audio_client,
+ prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ }
+ break;
+ }
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ pr_debug("ASM_DATA_EVENT_RENDERED_EOS\n");
+ clear_bit(CMD_EOS, &prtd->cmd_pending);
+ wake_up(&the_locks.eos_wait);
+ break;
+ case ASM_DATA_EVENT_READ_DONE_V2: {
+ pr_debug("ASM_DATA_EVENT_READ_DONE_V2\n");
+ buf_index = q6asm_get_buf_index_from_token(token);
+ pr_debug("%s: token=0x%08x buf_index=0x%08x\n",
+ __func__, token, buf_index);
+ prtd->in_frame_info[buf_index].size = payload[4];
+ prtd->in_frame_info[buf_index].offset = payload[5];
+ /* assume data size = 0 during flushing */
+ if (prtd->in_frame_info[buf_index].size) {
+ prtd->pcm_irq_pos +=
+ prtd->in_frame_info[buf_index].size;
+ pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ if (atomic_read(&prtd->in_count) <= prtd->periods)
+ atomic_inc(&prtd->in_count);
+ wake_up(&the_locks.read_wait);
+ if (prtd->mmap_flag &&
+ q6asm_is_cpu_buf_avail_nolock(OUT,
+ prtd->audio_client,
+ &size, &idx) &&
+ (substream->runtime->status->state ==
+ SNDRV_PCM_STATE_RUNNING))
+ q6asm_read_nolock(prtd->audio_client);
+ } else {
+ pr_debug("%s: reclaim flushed buf in_count %x\n",
+ __func__, atomic_read(&prtd->in_count));
+ prtd->pcm_irq_pos += prtd->pcm_count;
+ if (prtd->mmap_flag) {
+ if (q6asm_is_cpu_buf_avail_nolock(OUT,
+ prtd->audio_client,
+ &size, &idx) &&
+ (substream->runtime->status->state ==
+ SNDRV_PCM_STATE_RUNNING))
+ q6asm_read_nolock(prtd->audio_client);
+ } else {
+ atomic_inc(&prtd->in_count);
+ }
+ if (atomic_read(&prtd->in_count) == prtd->periods) {
+ pr_info("%s: reclaimed all bufs\n", __func__);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ wake_up(&the_locks.read_wait);
+ }
+ }
+ break;
+ }
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case ASM_SESSION_CMD_RUN_V2:
+ if (substream->stream
+ != SNDRV_PCM_STREAM_PLAYBACK) {
+ atomic_set(&prtd->start, 1);
+ break;
+ }
+ if (prtd->mmap_flag) {
+ pr_debug("%s:writing %d bytes of buffer to dsp\n",
+ __func__,
+ prtd->pcm_count);
+ q6asm_write_nolock(prtd->audio_client,
+ prtd->pcm_count,
+ 0, 0, NO_TIMESTAMP);
+ } else {
+ while (atomic_read(&prtd->out_needed)) {
+ pr_debug("%s:writing %d bytes of buffer to dsp\n",
+ __func__,
+ prtd->pcm_count);
+ q6asm_write_nolock(prtd->audio_client,
+ prtd->pcm_count,
+ 0, 0, NO_TIMESTAMP);
+ atomic_dec(&prtd->out_needed);
+ wake_up(&the_locks.write_wait);
+ };
+ }
+ atomic_set(&prtd->start, 1);
+ break;
+ default:
+ pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ break;
+ }
+ }
+ break;
+ case RESET_EVENTS:
+ pr_debug("%s RESET_EVENTS\n", __func__);
+ prtd->pcm_irq_pos += prtd->pcm_count;
+ atomic_inc(&prtd->out_count);
+ atomic_inc(&prtd->in_count);
+ prtd->reset_event = true;
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ wake_up(&the_locks.eos_wait);
+ wake_up(&the_locks.write_wait);
+ wake_up(&the_locks.read_wait);
+ break;
+ default:
+ pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd = runtime->private_data;
+ struct msm_plat_data *pdata;
+ struct snd_pcm_hw_params *params;
+ int ret;
+ uint16_t bits_per_sample;
+ uint16_t sample_word_size;
+
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->dev);
+ if (!pdata) {
+ pr_err("%s: platform data not populated\n", __func__);
+ return -EINVAL;
+ }
+ if (!prtd || !prtd->audio_client) {
+ pr_err("%s: private data null or audio client freed\n",
+ __func__);
+ return -EINVAL;
+ }
+ params = &soc_prtd->dpcm[substream->stream].hw_params;
+
+ pr_debug("%s\n", __func__);
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+ if (prtd->enabled)
+ return 0;
+
+ prtd->audio_client->perf_mode = pdata->perf_mode;
+ pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bits_per_sample = 32;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bits_per_sample = 24;
+ sample_word_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bits_per_sample = 16;
+ sample_word_size = 16;
+ break;
+ }
+
+ ret = q6asm_open_write_v4(prtd->audio_client,
+ FORMAT_LINEAR_PCM, bits_per_sample);
+
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_write_v2 failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return -ENOMEM;
+ }
+
+ ret = q6asm_send_cal(prtd->audio_client);
+ if (ret < 0)
+ pr_debug("%s : Send cal failed : %d", __func__, ret);
+
+ pr_debug("%s: session ID %d\n", __func__,
+ prtd->audio_client->session);
+ prtd->session_id = prtd->audio_client->session;
+ ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id, substream->stream);
+ if (ret) {
+ pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = q6asm_media_format_block_multi_ch_pcm_v4(
+ prtd->audio_client, runtime->rate,
+ runtime->channels, !prtd->set_channel_map,
+ prtd->channel_map, bits_per_sample,
+ sample_word_size, ASM_LITTLE_ENDIAN,
+ DEFAULT_QF);
+ if (ret < 0)
+ pr_info("%s: CMD Format block failed\n", __func__);
+
+ atomic_set(&prtd->out_count, runtime->periods);
+
+ prtd->enabled = 1;
+ prtd->cmd_pending = 0;
+ prtd->cmd_interrupt = 0;
+
+ return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_plat_data *pdata;
+ struct snd_pcm_hw_params *params;
+ struct msm_pcm_routing_evt event;
+ int ret = 0;
+ int i = 0;
+ uint16_t bits_per_sample = 16;
+ uint16_t sample_word_size;
+
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->dev);
+ if (!pdata) {
+ pr_err("%s: platform data not populated\n", __func__);
+ return -EINVAL;
+ }
+ if (!prtd || !prtd->audio_client) {
+ pr_err("%s: private data null or audio client freed\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (prtd->enabled == IDLE) {
+ pr_debug("%s:perf_mode=%d periods=%d\n", __func__,
+ pdata->perf_mode, runtime->periods);
+ params = &soc_prtd->dpcm[substream->stream].hw_params;
+ if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) ||
+ (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE))
+ bits_per_sample = 24;
+ else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
+ bits_per_sample = 32;
+
+ /* ULL mode is not supported in capture path */
+ if (pdata->perf_mode == LEGACY_PCM_MODE)
+ prtd->audio_client->perf_mode = LEGACY_PCM_MODE;
+ else
+ prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE;
+
+ pr_debug("%s Opening %d-ch PCM read stream, perf_mode %d\n",
+ __func__, params_channels(params),
+ prtd->audio_client->perf_mode);
+
+ ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
+ bits_per_sample);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_read failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return -ENOMEM;
+ }
+
+ ret = q6asm_send_cal(prtd->audio_client);
+ if (ret < 0)
+ pr_debug("%s : Send cal failed : %d", __func__, ret);
+
+ pr_debug("%s: session ID %d\n",
+ __func__, prtd->audio_client->session);
+ prtd->session_id = prtd->audio_client->session;
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) prtd;
+ ret = msm_pcm_routing_reg_phy_stream_v2(
+ soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id, substream->stream,
+ event);
+ if (ret) {
+ pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
+ return ret;
+ }
+ }
+
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+
+ if (prtd->enabled == IDLE || prtd->enabled == STOPPED) {
+ for (i = 0; i < runtime->periods; i++)
+ q6asm_read(prtd->audio_client);
+ prtd->periods = runtime->periods;
+ }
+
+ if (prtd->enabled != IDLE)
+ return 0;
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bits_per_sample = 32;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bits_per_sample = 24;
+ sample_word_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bits_per_sample = 16;
+ sample_word_size = 16;
+ break;
+ }
+
+ pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
+ __func__, prtd->samp_rate, prtd->channel_mode,
+ bits_per_sample, sample_word_size);
+ ret = q6asm_enc_cfg_blk_pcm_format_support_v4(prtd->audio_client,
+ prtd->samp_rate,
+ prtd->channel_mode,
+ bits_per_sample,
+ sample_word_size,
+ ASM_LITTLE_ENDIAN,
+ DEFAULT_QF);
+ if (ret < 0)
+ pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+ prtd->enabled = RUNNING;
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: Trigger start\n", __func__);
+ ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ atomic_set(&prtd->start, 0);
+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
+ prtd->enabled = STOPPED;
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ break;
+ }
+ /* pending CMD_EOS isn't expected */
+ WARN_ON_ONCE(test_bit(CMD_EOS, &prtd->cmd_pending));
+ set_bit(CMD_EOS, &prtd->cmd_pending);
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ if (ret)
+ clear_bit(CMD_EOS, &prtd->cmd_pending);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->start, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd;
+ int ret = 0;
+
+ prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ prtd->substream = substream;
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)event_handler, prtd);
+ if (!prtd->audio_client) {
+ pr_info("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+
+ prtd->audio_client->dev = soc_prtd->platform->dev;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = msm_pcm_hardware_playback;
+
+ /* Capture path */
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ runtime->hw = msm_pcm_hardware_capture;
+ else {
+ pr_err("Invalid Stream type %d\n", substream->stream);
+ return -EINVAL;
+ }
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret < 0)
+ pr_info("snd_pcm_hw_constraint_list failed\n");
+ /* Ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
+ PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
+ if (ret < 0) {
+ pr_err("constraint for buffer bytes min max ret = %d\n",
+ ret);
+ }
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
+ CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
+ if (ret < 0) {
+ pr_err("constraint for buffer bytes min max ret = %d\n",
+ ret);
+ }
+ }
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+ if (ret < 0) {
+ pr_err("constraint for period bytes step ret = %d\n",
+ ret);
+ }
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+ if (ret < 0) {
+ pr_err("constraint for buffer bytes step ret = %d\n",
+ ret);
+ }
+
+ prtd->enabled = IDLE;
+ prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
+ prtd->reset_event = false;
+ runtime->private_data = prtd;
+
+ return 0;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ int fbytes = 0;
+ int xfer = 0;
+ char *bufptr = NULL;
+ void *data = NULL;
+ uint32_t idx = 0;
+ uint32_t size = 0;
+ uint32_t retries = 0;
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ fbytes = frames_to_bytes(runtime, frames);
+ pr_debug("%s: prtd->out_count = %d\n",
+ __func__, atomic_read(&prtd->out_count));
+
+ while ((fbytes > 0) && (retries < MAX_PB_COPY_RETRIES)) {
+ if (prtd->reset_event) {
+ pr_err("%s: In SSR return ENETRESET before wait\n",
+ __func__);
+ return -ENETRESET;
+ }
+
+ ret = wait_event_timeout(the_locks.write_wait,
+ (atomic_read(&prtd->out_count)), 5 * HZ);
+ if (!ret) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+ ret = -ETIMEDOUT;
+ goto fail;
+ }
+ ret = 0;
+
+ if (prtd->reset_event) {
+ pr_err("%s: In SSR return ENETRESET after wait\n",
+ __func__);
+ return -ENETRESET;
+ }
+
+ if (!atomic_read(&prtd->out_count)) {
+ pr_err("%s: pcm stopped out_count 0\n", __func__);
+ return 0;
+ }
+
+ data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size,
+ &idx);
+ if (data == NULL) {
+ retries++;
+ continue;
+ } else {
+ retries = 0;
+ }
+
+ if (fbytes > size)
+ xfer = size;
+ else
+ xfer = fbytes;
+
+ bufptr = data;
+ if (bufptr) {
+ pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
+ __func__, fbytes, xfer, size);
+ if (copy_from_user(bufptr, buf, xfer)) {
+ ret = -EFAULT;
+ pr_err("%s: copy_from_user failed\n",
+ __func__);
+ q6asm_cpu_buf_release(IN, prtd->audio_client);
+ goto fail;
+ }
+ buf += xfer;
+ fbytes -= xfer;
+ pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes,
+ xfer);
+ if (atomic_read(&prtd->start)) {
+ pr_debug("%s:writing %d bytes of buffer to dsp\n",
+ __func__, xfer);
+ ret = q6asm_write(prtd->audio_client, xfer,
+ 0, 0, NO_TIMESTAMP);
+ if (ret < 0) {
+ ret = -EFAULT;
+ q6asm_cpu_buf_release(IN,
+ prtd->audio_client);
+ goto fail;
+ }
+ } else
+ atomic_inc(&prtd->out_needed);
+ atomic_dec(&prtd->out_count);
+ }
+ }
+fail:
+ if (retries >= MAX_PB_COPY_RETRIES)
+ ret = -ENOMEM;
+
+ return ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd = runtime->private_data;
+ uint32_t timeout;
+ int dir = 0;
+ int ret = 0;
+
+ pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
+
+ if (prtd->audio_client) {
+ dir = IN;
+
+ /* determine timeout length */
+ if (runtime->frame_bits == 0 || runtime->rate == 0) {
+ timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
+ } else {
+ timeout = (runtime->period_size *
+ CMD_EOS_TIMEOUT_MULTIPLIER) /
+ ((runtime->frame_bits / 8) *
+ runtime->rate);
+ if (timeout < CMD_EOS_MIN_TIMEOUT_LENGTH)
+ timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
+ }
+ pr_debug("%s: CMD_EOS timeout is %d\n", __func__, timeout);
+
+ ret = wait_event_timeout(the_locks.eos_wait,
+ !test_bit(CMD_EOS, &prtd->cmd_pending),
+ timeout);
+ if (!ret)
+ pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
+ __func__, prtd->cmd_pending);
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+ q6asm_audio_client_free(prtd->audio_client);
+ }
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ kfree(prtd);
+ return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+ snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ int fbytes = 0;
+ int xfer;
+ char *bufptr;
+ void *data = NULL;
+ static uint32_t idx;
+ static uint32_t size;
+ uint32_t offset = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = substream->runtime->private_data;
+
+
+ pr_debug("%s\n", __func__);
+ fbytes = frames_to_bytes(runtime, frames);
+
+ pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+ pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+ pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+ if (prtd->reset_event) {
+ pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
+ return -ENETRESET;
+ }
+ ret = wait_event_timeout(the_locks.read_wait,
+ (atomic_read(&prtd->in_count)), 5 * HZ);
+ if (!ret) {
+ pr_debug("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+ if (prtd->reset_event) {
+ pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
+ return -ENETRESET;
+ }
+ if (!atomic_read(&prtd->in_count)) {
+ pr_debug("%s: pcm stopped in_count 0\n", __func__);
+ return 0;
+ }
+ pr_debug("Checking if valid buffer is available...%pK\n",
+ data);
+ data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+ bufptr = data;
+ pr_debug("Size = %d\n", size);
+ pr_debug("fbytes = %d\n", fbytes);
+ pr_debug("idx = %d\n", idx);
+ if (bufptr) {
+ xfer = fbytes;
+ if (xfer > size)
+ xfer = size;
+ offset = prtd->in_frame_info[idx].offset;
+ pr_debug("Offset value = %d\n", offset);
+ if (copy_to_user(buf, bufptr+offset, xfer)) {
+ pr_err("Failed to copy buf to user\n");
+ ret = -EFAULT;
+ q6asm_cpu_buf_release(OUT, prtd->audio_client);
+ goto fail;
+ }
+ fbytes -= xfer;
+ size -= xfer;
+ prtd->in_frame_info[idx].offset += xfer;
+ pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+ __func__, fbytes, size, xfer);
+ pr_debug(" Sending next buffer to dsp\n");
+ memset(&prtd->in_frame_info[idx], 0,
+ sizeof(struct msm_audio_in_frame_info));
+ atomic_dec(&prtd->in_count);
+ ret = q6asm_read(prtd->audio_client);
+ if (ret < 0) {
+ pr_err("q6asm read failed\n");
+ ret = -EFAULT;
+ q6asm_cpu_buf_release(OUT, prtd->audio_client);
+ goto fail;
+ }
+ } else
+ pr_err("No valid buffer\n");
+
+ pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+ return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd = runtime->private_data;
+ int dir = OUT;
+
+ pr_debug("%s\n", __func__);
+ if (prtd->audio_client) {
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+ q6asm_audio_client_free(prtd->audio_client);
+ }
+
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ kfree(prtd);
+
+ return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+ return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_close(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_close(substream);
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_prepare(substream);
+ return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ if (prtd->pcm_irq_pos >= prtd->pcm_size)
+ prtd->pcm_irq_pos = 0;
+
+ pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+ return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ struct audio_client *ac = prtd->audio_client;
+ struct audio_port_data *apd = ac->port;
+ struct audio_buffer *ab;
+ int dir = -1;
+
+ prtd->mmap_flag = 1;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ab = &(apd[dir].buf[0]);
+
+ return msm_audio_ion_mmap(ab, vma);
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct audio_buffer *buf;
+ int dir, ret;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+ prtd->audio_client,
+ (params_buffer_bytes(params) / params_periods(params)),
+ params_periods(params));
+ if (ret < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
+ ret);
+ return -ENOMEM;
+ }
+ buf = prtd->audio_client->port[dir].buf;
+ if (buf == NULL || buf[0].data == NULL)
+ return -ENOMEM;
+
+ pr_debug("%s:buf = %pK\n", __func__, buf);
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = buf[0].data;
+ dma_buf->addr = buf[0].phys;
+ dma_buf->bytes = params_buffer_bytes(params);
+ if (!dma_buf->area)
+ return -ENOMEM;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .copy = msm_pcm_copy,
+ .hw_params = msm_pcm_hw_params,
+ .close = msm_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+ .pointer = msm_pcm_pointer,
+ .mmap = msm_pcm_mmap,
+};
+
+static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
+{
+ int rc = 0;
+
+ if (prtd && prtd->audio_client) {
+ pr_debug("%s: channels %d volume 0x%x\n", __func__,
+ prtd->channel_mode, volume);
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
+ }
+ }
+ return rc;
+}
+
+static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s\n", __func__);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->volume;
+ return 0;
+}
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+ int volume = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: volume : 0x%x\n", __func__, volume);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ rc = msm_pcm_set_volume(prtd, volume);
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
+static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+
+ dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0) {
+ pr_err("%s volume control failed ret %d\n", __func__, ret);
+ return ret;
+ }
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->get = msm_pcm_volume_ctl_get;
+ kctl->tlv.p = msm_pcm_vol_gain;
+ return 0;
+}
+
+static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s", __func__);
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ prtd->set_channel_map = true;
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ prtd->channel_map[i] =
+ (char)(ucontrol->value.integer.value[i]);
+ }
+ return 0;
+}
+
+static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s", __func__);
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(ucontrol->value.integer.value));
+ if (!substream->runtime)
+ return 0; /* no channels set */
+
+ prtd = substream->runtime->private_data;
+
+ if (prtd && prtd->set_channel_map == true) {
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] =
+ (int)prtd->channel_map[i];
+ } else {
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] = 0;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_chmap *chmap_info;
+ struct snd_kcontrol *kctl;
+ char device_num[12];
+ int i, ret = 0;
+
+ pr_debug("%s, Channel map cntrl add\n", __func__);
+ ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_std_chmaps,
+ PCM_FORMAT_MAX_NUM_CHANNEL, 0,
+ &chmap_info);
+ if (ret < 0) {
+ pr_err("%s, channel map cntrl add failed\n", __func__);
+ return ret;
+ }
+ kctl = chmap_info->kctl;
+ for (i = 0; i < kctl->count; i++)
+ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ snprintf(device_num, sizeof(device_num), "%d", pcm->device);
+ strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
+ pr_debug("%s, Overwriting channel map control name to: %s\n",
+ __func__, kctl->id.name);
+ kctl->put = msm_pcm_chmap_ctl_put;
+ kctl->get = msm_pcm_chmap_ctl_get;
+ return 0;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+
+ return 0;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_RX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+
+ return 0;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_TX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_usr *app_type_info;
+ struct snd_kcontrol *kctl;
+ const char *playback_mixer_ctl_name = "Audio Stream";
+ const char *capture_mixer_ctl_name = "Audio Stream Capture";
+ const char *deviceNo = "NN";
+ const char *suffix = "App Type Cfg";
+ int ctl_len, ret = 0;
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Playback app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, ctl_len, rtd->dai_link->be_id,
+ &app_type_info);
+ if (ret < 0) {
+ pr_err("%s: playback app type cntrl add failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ playback_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
+ }
+
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Capture app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ NULL, 1, ctl_len, rtd->dai_link->be_id,
+ &app_type_info);
+ if (ret < 0) {
+ pr_err("%s: capture app type cntrl add failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ capture_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ ret = msm_pcm_add_chmap_controls(rtd);
+ if (ret)
+ pr_err("%s: pcm add controls failed:%d\n", __func__, ret);
+ ret = msm_pcm_add_app_type_controls(rtd);
+ if (ret)
+ pr_err("%s: pcm add app type controls failed:%d\n",
+ __func__, ret);
+ return ret;
+}
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_pcm_add_controls(rtd);
+ if (ret) {
+ pr_err("%s, kctl add failed:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = msm_pcm_add_volume_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm Volume Control %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static snd_pcm_sframes_t msm_pcm_delay_blk(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ struct audio_client *ac = prtd->audio_client;
+ snd_pcm_sframes_t frames;
+ int ret;
+
+ ret = q6asm_get_path_delay(prtd->audio_client);
+ if (ret) {
+ pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
+ return 0;
+ }
+
+ /* convert microseconds to frames */
+ frames = ac->path_delay / 1000 * runtime->rate / 1000;
+
+ /* also convert the remainder from the initial division */
+ frames += ac->path_delay % 1000 * runtime->rate / 1000000;
+
+ /* overcompensate for the loss of precision (empirical) */
+ frames += 2;
+
+ return frames;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+ .delay_blk = msm_pcm_delay_blk,
+};
+
+static int msm_pcm_probe(struct platform_device *pdev)
+{
+ int rc;
+ int id;
+ struct msm_plat_data *pdata;
+ const char *latency_level;
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-pcm-dsp-id", &id);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
+ __func__);
+ return rc;
+ }
+
+ pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (of_property_read_bool(pdev->dev.of_node,
+ "qcom,msm-pcm-low-latency")) {
+
+ pdata->perf_mode = LOW_LATENCY_PCM_MODE;
+ rc = of_property_read_string(pdev->dev.of_node,
+ "qcom,latency-level", &latency_level);
+ if (!rc) {
+ if (!strcmp(latency_level, "ultra"))
+ pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ else if (!strcmp(latency_level, "ull-pp"))
+ pdata->perf_mode =
+ ULL_POST_PROCESSING_PCM_MODE;
+ }
+ } else {
+ pdata->perf_mode = LEGACY_PCM_MODE;
+ }
+
+ dev_set_drvdata(&pdev->dev, pdata);
+
+
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ struct msm_plat_data *pdata;
+
+ pdata = dev_get_drvdata(&pdev->dev);
+ kfree(pdata);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+static const struct of_device_id msm_pcm_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-dsp"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-dsp",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = msm_pcm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ init_waitqueue_head(&the_locks.enable_wait);
+ init_waitqueue_head(&the_locks.eos_wait);
+ init_waitqueue_head(&the_locks.write_wait);
+ init_waitqueue_head(&the_locks.read_wait);
+
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
new file mode 100644
index 0000000..5290d34
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+
+
+
+/* Support unconventional sample rates 12000, 24000 as well */
+#define USE_RATE \
+ (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+
+extern int copy_count;
+
+struct buffer {
+ void *data;
+ unsigned int size;
+ unsigned int used;
+ unsigned int addr;
+};
+
+struct buffer_rec {
+ void *data;
+ unsigned int size;
+ unsigned int read;
+ unsigned int addr;
+};
+
+struct audio_locks {
+ spinlock_t event_lock;
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+ wait_queue_head_t eos_wait;
+ wait_queue_head_t enable_wait;
+ wait_queue_head_t flush_wait;
+};
+
+struct msm_audio_in_frame_info {
+ uint32_t size;
+ uint32_t offset;
+};
+
+#define PLAYBACK_MIN_NUM_PERIODS 2
+#define PLAYBACK_MAX_NUM_PERIODS 8
+#define PLAYBACK_MAX_PERIOD_SIZE 122880
+#define PLAYBACK_MIN_PERIOD_SIZE 128
+#define CAPTURE_MIN_NUM_PERIODS 2
+#define CAPTURE_MAX_NUM_PERIODS 8
+#define CAPTURE_MAX_PERIOD_SIZE 122880
+#define CAPTURE_MIN_PERIOD_SIZE 320
+
+struct msm_audio {
+ struct snd_pcm_substream *substream;
+ unsigned int pcm_size;
+ unsigned int pcm_count;
+ unsigned int pcm_irq_pos; /* IRQ position */
+ uint16_t source; /* Encoding source bit mask */
+
+ struct audio_client *audio_client;
+
+ uint16_t session_id;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+ uint32_t dsp_cnt;
+
+ int abort; /* set when error, like sample rate mismatch */
+
+ bool reset_event;
+ int enabled;
+ int close_ack;
+ int cmd_ack;
+ /*
+ * cmd_ack doesn't tell if paticular command has been sent so can't
+ * determine if it needs to wait for completion.
+ * Use cmd_pending instead when checking whether a command is been
+ * sent or not.
+ */
+ unsigned long cmd_pending;
+ atomic_t start;
+ atomic_t stop;
+ atomic_t out_count;
+ atomic_t in_count;
+ atomic_t out_needed;
+ atomic_t eos;
+ int out_head;
+ int periods;
+ int mmap_flag;
+ atomic_t pending_buffer;
+ bool set_channel_map;
+ char channel_map[8];
+ int cmd_interrupt;
+ bool meta_data_mode;
+ uint32_t volume;
+ /* array of frame info */
+ struct msm_audio_in_frame_info in_frame_info[CAPTURE_MAX_NUM_PERIODS];
+};
+
+struct output_meta_data_st {
+ uint32_t meta_data_length;
+ uint32_t frame_size;
+ uint32_t timestamp_lsw;
+ uint32_t timestamp_msw;
+ uint32_t reserved[12];
+};
+
+struct msm_plat_data {
+ int perf_mode;
+};
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.c
new file mode 100644
index 0000000..dd3d73d
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.c
@@ -0,0 +1,176 @@
+/* Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <sound/hwdep.h>
+#include <sound/devdep_params.h>
+#include <sound/msm-dts-eagle.h>
+
+#include "msm-pcm-routing-devdep.h"
+#include "msm-ds2-dap-config.h"
+
+#ifdef CONFIG_SND_HWDEP
+static int msm_pcm_routing_hwdep_open(struct snd_hwdep *hw, struct file *file)
+{
+ pr_debug("%s\n", __func__);
+ msm_ds2_dap_update_port_parameters(hw, file, true);
+ return 0;
+}
+
+static int msm_pcm_routing_hwdep_release(struct snd_hwdep *hw,
+ struct file *file)
+{
+ pr_debug("%s\n", __func__);
+ msm_ds2_dap_update_port_parameters(hw, file, false);
+ return 0;
+}
+
+static int msm_pcm_routing_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ void __user *argp = (void __user *)arg;
+
+ pr_debug("%s:cmd %x\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_DEVDEP_DAP_IOCTL_SET_PARAM:
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_PARAM:
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_COMMAND:
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_LICENSE:
+ msm_pcm_routing_acquire_lock();
+ ret = msm_ds2_dap_ioctl(hw, file, cmd, argp);
+ msm_pcm_routing_release_lock();
+ break;
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER:
+ ret = msm_ds2_dap_ioctl(hw, file, cmd, argp);
+ break;
+ case DTS_EAGLE_IOCTL_GET_CACHE_SIZE:
+ case DTS_EAGLE_IOCTL_SET_CACHE_SIZE:
+ case DTS_EAGLE_IOCTL_GET_PARAM:
+ case DTS_EAGLE_IOCTL_SET_PARAM:
+ case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK:
+ case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE:
+ case DTS_EAGLE_IOCTL_GET_LICENSE:
+ case DTS_EAGLE_IOCTL_SET_LICENSE:
+ case DTS_EAGLE_IOCTL_SEND_LICENSE:
+ case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS:
+ ret = msm_dts_eagle_ioctl(cmd, arg);
+ if (ret == -EPERM) {
+ pr_err("%s called with invalid control 0x%X\n",
+ __func__, cmd);
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ pr_err("%s called with invalid control 0x%X\n", __func__, cmd);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+void msm_pcm_routing_hwdep_free(struct snd_pcm *pcm)
+{
+ pr_debug("%s\n", __func__);
+ msm_dts_eagle_pcm_free(pcm);
+}
+
+#ifdef CONFIG_COMPAT
+static int msm_pcm_routing_hwdep_compat_ioctl(struct snd_hwdep *hw,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+ void __user *argp = (void __user *)arg;
+
+ pr_debug("%s:cmd %x\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_DEVDEP_DAP_IOCTL_SET_PARAM32:
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_PARAM32:
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_COMMAND32:
+ case SNDRV_DEVDEP_DAP_IOCTL_DAP_LICENSE32:
+ msm_pcm_routing_acquire_lock();
+ ret = msm_ds2_dap_compat_ioctl(hw, file, cmd, argp);
+ msm_pcm_routing_release_lock();
+ break;
+ case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER32:
+ ret = msm_ds2_dap_compat_ioctl(hw, file, cmd, argp);
+ break;
+ case DTS_EAGLE_IOCTL_GET_CACHE_SIZE32:
+ case DTS_EAGLE_IOCTL_SET_CACHE_SIZE32:
+ case DTS_EAGLE_IOCTL_GET_PARAM32:
+ case DTS_EAGLE_IOCTL_SET_PARAM32:
+ case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32:
+ case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32:
+ case DTS_EAGLE_IOCTL_GET_LICENSE32:
+ case DTS_EAGLE_IOCTL_SET_LICENSE32:
+ case DTS_EAGLE_IOCTL_SEND_LICENSE32:
+ case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32:
+ ret = msm_dts_eagle_compat_ioctl(cmd, arg);
+ if (ret == -EPERM) {
+ pr_err("%s called with invalid control 0x%X\n",
+ __func__, cmd);
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ pr_err("%s called with invalid control 0x%X\n", __func__, cmd);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#endif
+
+int msm_pcm_routing_hwdep_new(struct snd_soc_pcm_runtime *runtime,
+ struct msm_pcm_routing_bdai_data *msm_bedais)
+{
+ struct snd_hwdep *hwdep;
+ struct snd_soc_dai_link *dai_link = runtime->dai_link;
+ int rc;
+
+ if (dai_link->be_id < 0 ||
+ dai_link->be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s:be_id %d invalid index\n",
+ __func__, dai_link->be_id);
+ return -EINVAL;
+ }
+ pr_debug("%s be_id %d\n", __func__, dai_link->be_id);
+ rc = snd_hwdep_new(runtime->card->snd_card,
+ msm_bedais[dai_link->be_id].name,
+ dai_link->be_id, &hwdep);
+ if (hwdep == NULL) {
+ pr_err("%s: hwdep intf failed to create %s- hwdep NULL\n",
+ __func__, msm_bedais[dai_link->be_id].name);
+ return rc;
+ }
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("%s: hwdep intf failed to create %s rc %d\n", __func__,
+ msm_bedais[dai_link->be_id].name, rc);
+ return rc;
+ }
+
+ hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_BE;
+ hwdep->private_data = &msm_bedais[dai_link->be_id];
+ hwdep->ops.open = msm_pcm_routing_hwdep_open;
+ hwdep->ops.ioctl = msm_pcm_routing_hwdep_ioctl;
+ hwdep->ops.release = msm_pcm_routing_hwdep_release;
+#ifdef CONFIG_COMPAT
+ hwdep->ops.ioctl_compat = msm_pcm_routing_hwdep_compat_ioctl;
+#endif
+ return msm_dts_eagle_pcm_new(runtime);
+}
+#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.h
new file mode 100644
index 0000000..d93d048
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2014-2015, 2017 The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_PCM_ROUTING_DEVDEP_H_
+#define _MSM_PCM_ROUTING_DEVDEP_H_
+
+#include <sound/soc.h>
+#include "msm-pcm-routing-v2.h"
+
+#ifdef CONFIG_SND_HWDEP
+int msm_pcm_routing_hwdep_new(struct snd_soc_pcm_runtime *runtime,
+ struct msm_pcm_routing_bdai_data *msm_bedais);
+void msm_pcm_routing_hwdep_free(struct snd_pcm *pcm);
+#else
+static inline int msm_pcm_routing_hwdep_new(struct snd_soc_pcm_runtime *runtime,
+ struct msm_pcm_routing_bdai_data *msm_bedais)
+{
+ return 0;
+}
+
+static inline void msm_pcm_routing_hwdep_free(struct snd_pcm *pcm)
+{
+}
+#endif
+#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
new file mode 100644
index 0000000..a8cbdbe
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -0,0 +1,11931 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6adm-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/tlv.h>
+#include <sound/asound.h>
+#include <sound/pcm_params.h>
+#include <sound/q6core.h>
+#include <sound/audio_cal_utils.h>
+#include <sound/msm-dts-eagle.h>
+#include <sound/audio_effects.h>
+#include <sound/hwdep.h>
+
+#include "msm-pcm-routing-v2.h"
+#include "msm-pcm-routing-devdep.h"
+#include "msm-qti-pp-config.h"
+#include "msm-dts-srs-tm-config.h"
+#include "msm-dolby-dap-config.h"
+#include "msm-ds2-dap-config.h"
+#include "q6voice.h"
+#include "sound/q6lsm.h"
+
+static int get_cal_path(int path_type);
+
+static struct mutex routing_lock;
+
+static struct cal_type_data *cal_data;
+
+static int fm_switch_enable;
+static int hfp_switch_enable;
+static int pri_mi2s_switch_enable;
+static int sec_mi2s_switch_enable;
+static int tert_mi2s_switch_enable;
+static int quat_mi2s_switch_enable;
+static int fm_pcmrx_switch_enable;
+static int lsm_mux_slim_port;
+static int slim0_rx_aanc_fb_port;
+static int msm_route_ec_ref_rx;
+static uint32_t voc_session_id = ALL_SESSION_VSID;
+static int msm_route_ext_ec_ref;
+static bool is_custom_stereo_on;
+static bool is_ds2_on;
+
+enum {
+ MADNONE,
+ MADAUDIO,
+ MADBEACON,
+ MADULTRASOUND,
+ MADSWAUDIO,
+};
+
+#define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
+#define SLIMBUS_1_TX_TEXT "SLIMBUS_1_TX"
+#define SLIMBUS_2_TX_TEXT "SLIMBUS_2_TX"
+#define SLIMBUS_3_TX_TEXT "SLIMBUS_3_TX"
+#define SLIMBUS_4_TX_TEXT "SLIMBUS_4_TX"
+#define SLIMBUS_5_TX_TEXT "SLIMBUS_5_TX"
+#define TERT_MI2S_TX_TEXT "TERT_MI2S_TX"
+#define LSM_FUNCTION_TEXT "LSM Function"
+static const char * const mad_audio_mux_text[] = {
+ "None",
+ SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT,
+ SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT,
+ TERT_MI2S_TX_TEXT
+};
+
+struct msm_pcm_route_bdai_pp_params {
+ u16 port_id; /* AFE port ID */
+ unsigned long pp_params_config;
+ bool mute_on;
+ int latency;
+};
+
+static struct msm_pcm_route_bdai_pp_params
+ msm_bedais_pp_params[MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX] = {
+ {HDMI_RX, 0, 0, 0},
+ {DISPLAY_PORT_RX, 0, 0, 0},
+};
+
+static int msm_routing_send_device_pp_params(int port_id, int copp_idx);
+
+static int msm_routing_get_bit_width(unsigned int format)
+{
+ int bit_width;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bit_width = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_width = 16;
+ }
+ return bit_width;
+}
+
+static bool msm_is_resample_needed(int input_sr, int output_sr)
+{
+ bool rc = false;
+
+ if (input_sr != output_sr)
+ rc = true;
+
+ pr_debug("perform resampling (%s) for copp rate (%d)afe rate (%d)",
+ (rc ? "oh yes" : "not really"),
+ input_sr, output_sr);
+
+ return rc;
+}
+
+static void msm_pcm_routing_cfg_pp(int port_id, int copp_idx, int topology,
+ int channels)
+{
+ int rc = 0;
+
+ switch (topology) {
+ case SRS_TRUMEDIA_TOPOLOGY_ID:
+ pr_debug("%s: SRS_TRUMEDIA_TOPOLOGY_ID\n", __func__);
+ msm_dts_srs_tm_init(port_id, copp_idx);
+ break;
+ case DS2_ADM_COPP_TOPOLOGY_ID:
+ pr_debug("%s: DS2_ADM_COPP_TOPOLOGY %d\n",
+ __func__, DS2_ADM_COPP_TOPOLOGY_ID);
+ rc = msm_ds2_dap_init(port_id, copp_idx, channels,
+ is_custom_stereo_on);
+ if (rc < 0)
+ pr_err("%s: DS2 topo_id 0x%x, port %d, CS %d rc %d\n",
+ __func__, topology, port_id,
+ is_custom_stereo_on, rc);
+ break;
+ case DOLBY_ADM_COPP_TOPOLOGY_ID:
+ if (is_ds2_on) {
+ pr_debug("%s: DS2_ADM_COPP_TOPOLOGY\n", __func__);
+ rc = msm_ds2_dap_init(port_id, copp_idx, channels,
+ is_custom_stereo_on);
+ if (rc < 0)
+ pr_err("%s:DS2 topo_id 0x%x, port %d, rc %d\n",
+ __func__, topology, port_id, rc);
+ } else {
+ pr_debug("%s: DOLBY_ADM_COPP_TOPOLOGY_ID\n", __func__);
+ rc = msm_dolby_dap_init(port_id, copp_idx, channels,
+ is_custom_stereo_on);
+ if (rc < 0)
+ pr_err("%s: DS1 topo_id 0x%x, port %d, rc %d\n",
+ __func__, topology, port_id, rc);
+ }
+ break;
+ case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX:
+ pr_debug("%s: DTS_EAGLE_COPP_TOPOLOGY_ID\n", __func__);
+ msm_dts_eagle_init_post(port_id, copp_idx);
+ break;
+ case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE:
+ pr_debug("%s: TOPOLOGY_ID_AUDIOSPHERE\n", __func__);
+ rc = msm_qti_pp_asphere_init(port_id, copp_idx);
+ if (rc < 0)
+ pr_err("%s: topo_id 0x%x, port %d, copp %d, rc %d\n",
+ __func__, topology, port_id, copp_idx, rc);
+ break;
+ default:
+ /* custom topology specific feature param handlers */
+ break;
+ }
+}
+
+static void msm_pcm_routing_deinit_pp(int port_id, int topology)
+{
+ switch (topology) {
+ case SRS_TRUMEDIA_TOPOLOGY_ID:
+ pr_debug("%s: SRS_TRUMEDIA_TOPOLOGY_ID\n", __func__);
+ msm_dts_srs_tm_deinit(port_id);
+ break;
+ case DS2_ADM_COPP_TOPOLOGY_ID:
+ pr_debug("%s: DS2_ADM_COPP_TOPOLOGY_ID %d\n",
+ __func__, DS2_ADM_COPP_TOPOLOGY_ID);
+ msm_ds2_dap_deinit(port_id);
+ break;
+ case DOLBY_ADM_COPP_TOPOLOGY_ID:
+ if (is_ds2_on) {
+ pr_debug("%s: DS2_ADM_COPP_TOPOLOGY_ID\n", __func__);
+ msm_ds2_dap_deinit(port_id);
+ } else {
+ pr_debug("%s: DOLBY_ADM_COPP_TOPOLOGY_ID\n", __func__);
+ msm_dolby_dap_deinit(port_id);
+ }
+ break;
+ case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX:
+ pr_debug("%s: DTS_EAGLE_COPP_TOPOLOGY_ID\n", __func__);
+ msm_dts_eagle_deinit_post(port_id, topology);
+ break;
+ case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE:
+ pr_debug("%s: TOPOLOGY_ID_AUDIOSPHERE\n", __func__);
+ msm_qti_pp_asphere_deinit(port_id);
+ break;
+ default:
+ /* custom topology specific feature deinit handlers */
+ break;
+ }
+}
+
+static void msm_pcm_routng_cfg_matrix_map_pp(struct route_payload payload,
+ int path_type, int perf_mode)
+{
+ int itr = 0, rc = 0;
+
+ if ((path_type == ADM_PATH_PLAYBACK) &&
+ (perf_mode == LEGACY_PCM_MODE) &&
+ is_custom_stereo_on) {
+ for (itr = 0; itr < payload.num_copps; itr++) {
+ if ((payload.port_id[itr] != SLIMBUS_0_RX) &&
+ (payload.port_id[itr] != RT_PROXY_PORT_001_RX)) {
+ continue;
+ }
+
+ rc = msm_qti_pp_send_stereo_to_custom_stereo_cmd(
+ payload.port_id[itr],
+ payload.copp_idx[itr],
+ payload.session_id,
+ Q14_GAIN_ZERO_POINT_FIVE,
+ Q14_GAIN_ZERO_POINT_FIVE,
+ Q14_GAIN_ZERO_POINT_FIVE,
+ Q14_GAIN_ZERO_POINT_FIVE);
+ if (rc < 0)
+ pr_err("%s: err setting custom stereo\n",
+ __func__);
+ }
+ }
+}
+
+#define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
+struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
+ { PRIMARY_I2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_RX},
+ { PRIMARY_I2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_TX},
+ { SLIMBUS_0_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_RX},
+ { SLIMBUS_0_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_TX},
+ { HDMI_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_HDMI},
+ { INT_BT_SCO_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_RX},
+ { INT_BT_SCO_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_TX},
+ { INT_FM_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_RX},
+ { INT_FM_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_TX},
+ { RT_PROXY_PORT_001_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_AFE_PCM_RX},
+ { RT_PROXY_PORT_001_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_AFE_PCM_TX},
+ { AFE_PORT_ID_PRIMARY_PCM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_AUXPCM_RX},
+ { AFE_PORT_ID_PRIMARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_AUXPCM_TX},
+ { VOICE_PLAYBACK_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_VOICE_PLAYBACK_TX},
+ { VOICE2_PLAYBACK_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_VOICE2_PLAYBACK_TX},
+ { VOICE_RECORD_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INCALL_RECORD_RX},
+ { VOICE_RECORD_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INCALL_RECORD_TX},
+ { MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_MI2S_RX},
+ { MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_MI2S_TX},
+ { SECONDARY_I2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SEC_I2S_RX},
+ { SLIMBUS_1_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_RX},
+ { SLIMBUS_1_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_TX},
+ { SLIMBUS_2_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_RX},
+ { SLIMBUS_2_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_TX},
+ { SLIMBUS_3_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_RX},
+ { SLIMBUS_3_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_TX},
+ { SLIMBUS_4_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_RX},
+ { SLIMBUS_4_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_TX},
+ { SLIMBUS_5_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_RX},
+ { SLIMBUS_5_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_TX},
+ { SLIMBUS_6_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_RX},
+ { SLIMBUS_6_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_TX},
+ { SLIMBUS_7_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_RX},
+ { SLIMBUS_7_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_TX},
+ { SLIMBUS_8_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_RX},
+ { SLIMBUS_8_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX},
+ { SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_RX},
+ { SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_TX},
+ { SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_1_TX},
+ { AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_MI2S_RX},
+ { AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_MI2S_TX},
+ { AFE_PORT_ID_SECONDARY_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_MI2S_RX},
+ { AFE_PORT_ID_SECONDARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_MI2S_TX},
+ { AFE_PORT_ID_PRIMARY_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_MI2S_RX},
+ { AFE_PORT_ID_PRIMARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_MI2S_TX},
+ { AFE_PORT_ID_TERTIARY_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_MI2S_RX},
+ { AFE_PORT_ID_TERTIARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_MI2S_TX},
+ { AUDIO_PORT_ID_I2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_AUDIO_I2S_RX},
+ { AFE_PORT_ID_SECONDARY_PCM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_AUXPCM_RX},
+ { AFE_PORT_ID_SECONDARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_AUXPCM_TX},
+ { AFE_PORT_ID_SPDIF_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SPDIF_RX},
+ { AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_MI2S_RX_SD1},
+ { AFE_PORT_ID_QUINARY_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUIN_MI2S_RX},
+ { AFE_PORT_ID_QUINARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUIN_MI2S_TX},
+ { AFE_PORT_ID_SENARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SENARY_MI2S_TX},
+ { AFE_PORT_ID_PRIMARY_TDM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_RX_0},
+ { AFE_PORT_ID_PRIMARY_TDM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_TX_0},
+ { AFE_PORT_ID_PRIMARY_TDM_RX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_RX_1},
+ { AFE_PORT_ID_PRIMARY_TDM_TX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_TX_1},
+ { AFE_PORT_ID_PRIMARY_TDM_RX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_RX_2},
+ { AFE_PORT_ID_PRIMARY_TDM_TX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_TX_2},
+ { AFE_PORT_ID_PRIMARY_TDM_RX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_RX_3},
+ { AFE_PORT_ID_PRIMARY_TDM_TX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_TX_3},
+ { AFE_PORT_ID_PRIMARY_TDM_RX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_RX_4},
+ { AFE_PORT_ID_PRIMARY_TDM_TX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_TX_4},
+ { AFE_PORT_ID_PRIMARY_TDM_RX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_RX_5},
+ { AFE_PORT_ID_PRIMARY_TDM_TX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_TX_5},
+ { AFE_PORT_ID_PRIMARY_TDM_RX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_RX_6},
+ { AFE_PORT_ID_PRIMARY_TDM_TX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_TX_6},
+ { AFE_PORT_ID_PRIMARY_TDM_RX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_RX_7},
+ { AFE_PORT_ID_PRIMARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_PRI_TDM_TX_7},
+ { AFE_PORT_ID_SECONDARY_TDM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_RX_0},
+ { AFE_PORT_ID_SECONDARY_TDM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_TX_0},
+ { AFE_PORT_ID_SECONDARY_TDM_RX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_RX_1},
+ { AFE_PORT_ID_SECONDARY_TDM_TX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_TX_1},
+ { AFE_PORT_ID_SECONDARY_TDM_RX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_RX_2},
+ { AFE_PORT_ID_SECONDARY_TDM_TX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_TX_2},
+ { AFE_PORT_ID_SECONDARY_TDM_RX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_RX_3},
+ { AFE_PORT_ID_SECONDARY_TDM_TX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_TX_3},
+ { AFE_PORT_ID_SECONDARY_TDM_RX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_RX_4},
+ { AFE_PORT_ID_SECONDARY_TDM_TX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_TX_4},
+ { AFE_PORT_ID_SECONDARY_TDM_RX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_RX_5},
+ { AFE_PORT_ID_SECONDARY_TDM_TX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_TX_5},
+ { AFE_PORT_ID_SECONDARY_TDM_RX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_RX_6},
+ { AFE_PORT_ID_SECONDARY_TDM_TX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_TX_6},
+ { AFE_PORT_ID_SECONDARY_TDM_RX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_RX_7},
+ { AFE_PORT_ID_SECONDARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_SEC_TDM_TX_7},
+ { AFE_PORT_ID_TERTIARY_TDM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_RX_0},
+ { AFE_PORT_ID_TERTIARY_TDM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_TX_0},
+ { AFE_PORT_ID_TERTIARY_TDM_RX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_RX_1},
+ { AFE_PORT_ID_TERTIARY_TDM_TX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_TX_1},
+ { AFE_PORT_ID_TERTIARY_TDM_RX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_RX_2},
+ { AFE_PORT_ID_TERTIARY_TDM_TX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_TX_2},
+ { AFE_PORT_ID_TERTIARY_TDM_RX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_RX_3},
+ { AFE_PORT_ID_TERTIARY_TDM_TX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_TX_3},
+ { AFE_PORT_ID_TERTIARY_TDM_RX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_RX_4},
+ { AFE_PORT_ID_TERTIARY_TDM_TX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_TX_4},
+ { AFE_PORT_ID_TERTIARY_TDM_RX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_RX_5},
+ { AFE_PORT_ID_TERTIARY_TDM_TX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_TX_5},
+ { AFE_PORT_ID_TERTIARY_TDM_RX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_RX_6},
+ { AFE_PORT_ID_TERTIARY_TDM_TX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_TX_6},
+ { AFE_PORT_ID_TERTIARY_TDM_RX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_RX_7},
+ { AFE_PORT_ID_TERTIARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_TDM_TX_7},
+ { AFE_PORT_ID_QUATERNARY_TDM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_RX_0},
+ { AFE_PORT_ID_QUATERNARY_TDM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_TX_0},
+ { AFE_PORT_ID_QUATERNARY_TDM_RX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_RX_1},
+ { AFE_PORT_ID_QUATERNARY_TDM_TX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_TX_1},
+ { AFE_PORT_ID_QUATERNARY_TDM_RX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_RX_2},
+ { AFE_PORT_ID_QUATERNARY_TDM_TX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_TX_2},
+ { AFE_PORT_ID_QUATERNARY_TDM_RX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_RX_3},
+ { AFE_PORT_ID_QUATERNARY_TDM_TX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_TX_3},
+ { AFE_PORT_ID_QUATERNARY_TDM_RX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_RX_4},
+ { AFE_PORT_ID_QUATERNARY_TDM_TX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_TX_4},
+ { AFE_PORT_ID_QUATERNARY_TDM_RX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_RX_5},
+ { AFE_PORT_ID_QUATERNARY_TDM_TX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_TX_5},
+ { AFE_PORT_ID_QUATERNARY_TDM_RX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_RX_6},
+ { AFE_PORT_ID_QUATERNARY_TDM_TX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_TX_6},
+ { AFE_PORT_ID_QUATERNARY_TDM_RX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_RX_7},
+ { AFE_PORT_ID_QUATERNARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_TDM_TX_7},
+ { INT_BT_A2DP_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_A2DP_RX},
+ { AFE_PORT_ID_USB_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_RX},
+ { AFE_PORT_ID_USB_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_TX},
+ { DISPLAY_PORT_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_DISPLAY_PORT},
+ { AFE_PORT_ID_TERTIARY_PCM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_AUXPCM_RX},
+ { AFE_PORT_ID_TERTIARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_TERT_AUXPCM_TX},
+ { AFE_PORT_ID_QUATERNARY_PCM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_AUXPCM_RX},
+ { AFE_PORT_ID_QUATERNARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_QUAT_AUXPCM_TX},
+ { AFE_PORT_ID_INT0_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT0_MI2S_RX},
+ { AFE_PORT_ID_INT0_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT0_MI2S_TX},
+ { AFE_PORT_ID_INT1_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT1_MI2S_RX},
+ { AFE_PORT_ID_INT1_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT1_MI2S_TX},
+ { AFE_PORT_ID_INT2_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT2_MI2S_RX},
+ { AFE_PORT_ID_INT2_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT2_MI2S_TX},
+ { AFE_PORT_ID_INT3_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT3_MI2S_RX},
+ { AFE_PORT_ID_INT3_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT3_MI2S_TX},
+ { AFE_PORT_ID_INT4_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT4_MI2S_RX},
+ { AFE_PORT_ID_INT4_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT4_MI2S_TX},
+ { AFE_PORT_ID_INT5_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT5_MI2S_RX},
+ { AFE_PORT_ID_INT5_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT5_MI2S_TX},
+ { AFE_PORT_ID_INT6_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT6_MI2S_RX},
+ { AFE_PORT_ID_INT6_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT6_MI2S_TX},
+};
+
+/* Track ASM playback & capture sessions of DAI */
+static struct msm_pcm_routing_fdai_data
+ fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+ /* MULTIMEDIA1 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA2 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA3 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA4 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA5 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA6 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA7*/
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA8 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA9 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA10 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA11 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA12 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA13 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA14 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA15 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA16 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA17 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA18 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA19 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+};
+
+static unsigned long session_copp_map[MSM_FRONTEND_DAI_MM_SIZE][2]
+ [MSM_BACKEND_DAI_MAX];
+static struct msm_pcm_routing_app_type_data app_type_cfg[MAX_APP_TYPES];
+static struct msm_pcm_stream_app_type_cfg
+ fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MM_SIZE][2];
+
+/* The caller of this should aqcuire routing lock */
+void msm_pcm_routing_get_bedai_info(int be_idx,
+ struct msm_pcm_routing_bdai_data *be_dai)
+{
+ if (be_idx >= 0 && be_idx < MSM_BACKEND_DAI_MAX)
+ memcpy(be_dai, &msm_bedais[be_idx],
+ sizeof(struct msm_pcm_routing_bdai_data));
+}
+
+/* The caller of this should aqcuire routing lock */
+void msm_pcm_routing_get_fedai_info(int fe_idx, int sess_type,
+ struct msm_pcm_routing_fdai_data *fe_dai)
+{
+ if ((sess_type == SESSION_TYPE_TX) || (sess_type == SESSION_TYPE_RX))
+ memcpy(fe_dai, &fe_dai_map[fe_idx][sess_type],
+ sizeof(struct msm_pcm_routing_fdai_data));
+}
+
+void msm_pcm_routing_acquire_lock(void)
+{
+ mutex_lock(&routing_lock);
+}
+
+void msm_pcm_routing_release_lock(void)
+{
+ mutex_unlock(&routing_lock);
+}
+
+static int msm_pcm_routing_get_app_type_idx(int app_type)
+{
+ int idx;
+
+ pr_debug("%s: app_type: %d\n", __func__, app_type);
+ for (idx = 0; idx < MAX_APP_TYPES; idx++) {
+ if (app_type_cfg[idx].app_type == app_type)
+ return idx;
+ }
+ pr_info("%s: App type not available, fallback to default\n", __func__);
+ return 0;
+}
+
+void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
+ int acdb_dev_id, int sample_rate, int session_type)
+{
+ pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fedai_id, session_type, app_type,
+ acdb_dev_id, sample_rate);
+ if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ pr_err("%s: Invalid machine driver ID %d\n",
+ __func__, fedai_id);
+ return;
+ }
+ if (session_type != SESSION_TYPE_RX &&
+ session_type != SESSION_TYPE_TX) {
+ pr_err("%s: Invalid session type %d\n",
+ __func__, session_type);
+ return;
+ }
+ fe_dai_app_type_cfg[fedai_id][session_type].app_type = app_type;
+ fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id = acdb_dev_id;
+ fe_dai_app_type_cfg[fedai_id][session_type].sample_rate = sample_rate;
+}
+
+/**
+ * msm_pcm_routing_get_stream_app_type_cfg
+ *
+ * Receives fedai_id, session_type and populates app_type, acdb_dev_id, &
+ * sample rate. Returns 0 on success. On failure returns
+ * -EINVAL and does not alter passed values.
+ *
+ * fedai_id - Passed value, front end ID for which app type config is wanted
+ * session_type - Passed value, session type for which app type config
+ * is wanted
+ * app_type - Returned value, app type used by app type config
+ * acdb_dev_id - Returned value, ACDB device ID used by app type config
+ * sample_rate - Returned value, sample rate used by app type config
+ */
+int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
+ int *app_type, int *acdb_dev_id, int *sample_rate)
+{
+ int ret = 0;
+
+ if (app_type == NULL) {
+ pr_err("%s: NULL pointer sent for app_type\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ } else if (acdb_dev_id == NULL) {
+ pr_err("%s: NULL pointer sent for acdb_dev_id\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ } else if (sample_rate == NULL) {
+ pr_err("%s: NULL pointer sent for sample rate\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ } else if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ pr_err("%s: Invalid FE ID %d\n",
+ __func__, fedai_id);
+ ret = -EINVAL;
+ goto done;
+ } else if (session_type != SESSION_TYPE_RX &&
+ session_type != SESSION_TYPE_TX) {
+ pr_err("%s: Invalid session type %d\n",
+ __func__, session_type);
+ ret = -EINVAL;
+ goto done;
+ }
+ *app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ *acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
+ *sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
+
+ pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fedai_id, session_type,
+ *app_type, *acdb_dev_id, *sample_rate);
+done:
+ return ret;
+}
+EXPORT_SYMBOL(msm_pcm_routing_get_stream_app_type_cfg);
+
+static struct cal_block_data *msm_routing_find_topology_by_path(int path)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ list_for_each_safe(ptr, next,
+ &cal_data->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ if (((struct audio_cal_info_adm_top *)cal_block->cal_info)
+ ->path == path) {
+ return cal_block;
+ }
+ }
+ pr_debug("%s: Can't find topology for path %d\n", __func__, path);
+ return NULL;
+}
+
+static struct cal_block_data *msm_routing_find_topology(int path,
+ int app_type,
+ int acdb_id,
+ int sample_rate)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_adm_top *cal_info;
+
+ pr_debug("%s\n", __func__);
+
+ list_for_each_safe(ptr, next,
+ &cal_data->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ cal_info = (struct audio_cal_info_adm_top *)
+ cal_block->cal_info;
+ if ((cal_info->path == path) &&
+ (cal_info->app_type == app_type) &&
+ (cal_info->acdb_id == acdb_id) &&
+ (cal_info->sample_rate == sample_rate)) {
+ return cal_block;
+ }
+ }
+ pr_debug("%s: Can't find topology for path %d, app %d, acdb_id %d sample_rate %d defaulting to search by path\n",
+ __func__, path, app_type, acdb_id, sample_rate);
+ return msm_routing_find_topology_by_path(path);
+}
+
+static int msm_routing_get_adm_topology(int path, int fedai_id,
+ int session_type)
+{
+ int topology = NULL_COPP_TOPOLOGY;
+ struct cal_block_data *cal_block = NULL;
+ int app_type = 0, acdb_dev_id = 0, sample_rate = 0;
+
+ pr_debug("%s\n", __func__);
+
+ path = get_cal_path(path);
+ if (cal_data == NULL)
+ goto done;
+
+ mutex_lock(&cal_data->lock);
+
+ app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
+ sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
+
+ cal_block = msm_routing_find_topology(path, app_type,
+ acdb_dev_id, sample_rate);
+ if (cal_block == NULL)
+ goto unlock;
+
+ topology = ((struct audio_cal_info_adm_top *)
+ cal_block->cal_info)->topology;
+unlock:
+ mutex_unlock(&cal_data->lock);
+done:
+ pr_debug("%s: Using topology %d\n", __func__, topology);
+ return topology;
+}
+
+static uint8_t is_be_dai_extproc(int be_dai)
+{
+ if (be_dai == MSM_BACKEND_DAI_EXTPROC_RX ||
+ be_dai == MSM_BACKEND_DAI_EXTPROC_TX ||
+ be_dai == MSM_BACKEND_DAI_EXTPROC_EC_TX)
+ return 1;
+ else
+ return 0;
+}
+
+static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
+ int path_type, int perf_mode)
+{
+ int i, port_type, j, num_copps = 0;
+ struct route_payload payload;
+
+ port_type = ((path_type == ADM_PATH_PLAYBACK ||
+ path_type == ADM_PATH_COMPRESSED_RX) ?
+ MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
+
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (!is_be_dai_extproc(i) &&
+ (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+ (msm_bedais[i].active) &&
+ (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+ for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+ unsigned long copp =
+ session_copp_map[fedai_id][sess_type][i];
+ if (test_bit(j, &copp)) {
+ payload.port_id[num_copps] =
+ msm_bedais[i].port_id;
+ payload.copp_idx[num_copps] = j;
+ num_copps++;
+ }
+ }
+ }
+ }
+
+ if (num_copps) {
+ payload.num_copps = num_copps;
+ payload.session_id = fe_dai_map[fedai_id][sess_type].strm_id;
+ payload.app_type =
+ fe_dai_app_type_cfg[fedai_id][sess_type].app_type;
+ payload.acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][sess_type].acdb_dev_id;
+ payload.sample_rate =
+ fe_dai_app_type_cfg[fedai_id][sess_type].sample_rate;
+ adm_matrix_map(path_type, payload, perf_mode);
+ msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
+ }
+}
+
+void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
+ int stream_type)
+{
+ int i, session_type, path_type, port_type;
+ u32 mode = 0;
+
+ if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ /* bad ID assigned in machine driver */
+ pr_err("%s: bad MM ID\n", __func__);
+ return;
+ }
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+ session_type = SESSION_TYPE_RX;
+ path_type = ADM_PATH_PLAYBACK;
+ port_type = MSM_AFE_PORT_TYPE_RX;
+ } else {
+ session_type = SESSION_TYPE_TX;
+ path_type = ADM_PATH_LIVE_REC;
+ port_type = MSM_AFE_PORT_TYPE_TX;
+ }
+
+ mutex_lock(&routing_lock);
+
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (!is_be_dai_extproc(i) &&
+ (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+ (msm_bedais[i].active) &&
+ (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+ mode = afe_get_port_type(msm_bedais[i].port_id);
+ adm_connect_afe_port(mode, dspst_id,
+ msm_bedais[i].port_id);
+ break;
+ }
+ }
+ mutex_unlock(&routing_lock);
+}
+
+int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
+ int dspst_id, int stream_type,
+ uint32_t compr_passthr_mode)
+{
+ int i, j, session_type, path_type, port_type, topology, num_copps = 0;
+ struct route_payload payload;
+ u32 channels, sample_rate;
+ u16 bit_width = 16;
+
+ pr_debug("%s:fe_id[%d] perf_mode[%d] id[%d] stream_type[%d] passt[%d]",
+ __func__, fe_id, perf_mode, dspst_id,
+ stream_type, compr_passthr_mode);
+
+ if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ /* bad ID assigned in machine driver */
+ pr_err("%s: bad MM ID %d\n", __func__, fe_id);
+ return -EINVAL;
+ }
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+ session_type = SESSION_TYPE_RX;
+ if (compr_passthr_mode != LEGACY_PCM)
+ path_type = ADM_PATH_COMPRESSED_RX;
+ else
+ path_type = ADM_PATH_PLAYBACK;
+ port_type = MSM_AFE_PORT_TYPE_RX;
+ } else if (stream_type == SNDRV_PCM_STREAM_CAPTURE) {
+ session_type = SESSION_TYPE_TX;
+ path_type = ADM_PATH_LIVE_REC;
+ port_type = MSM_AFE_PORT_TYPE_TX;
+ } else {
+ pr_err("%s: invalid stream type %d\n", __func__, stream_type);
+ return -EINVAL;
+ }
+
+ mutex_lock(&routing_lock);
+
+ payload.num_copps = 0; /* only RX needs to use payload */
+ fe_dai_map[fe_id][session_type].strm_id = dspst_id;
+ /* re-enable EQ if active */
+ msm_qti_pp_send_eq_values(fe_id);
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (test_bit(fe_id, &msm_bedais[i].fe_sessions))
+ msm_bedais[i].compr_passthr_mode = compr_passthr_mode;
+
+ if (!is_be_dai_extproc(i) &&
+ (afe_get_port_type(msm_bedais[i].port_id) ==
+ port_type) &&
+ (msm_bedais[i].active) &&
+ (test_bit(fe_id, &msm_bedais[i].fe_sessions))) {
+ int app_type, app_type_idx, copp_idx, acdb_dev_id;
+
+ /*
+ * check if ADM needs to be configured with different
+ * channel mapping than backend
+ */
+ if (!msm_bedais[i].adm_override_ch)
+ channels = msm_bedais[i].channel;
+ else
+ channels = msm_bedais[i].adm_override_ch;
+
+ bit_width = msm_routing_get_bit_width(
+ msm_bedais[i].format);
+ app_type =
+ fe_dai_app_type_cfg[fe_id][session_type].app_type;
+ if (app_type) {
+ app_type_idx =
+ msm_pcm_routing_get_app_type_idx(
+ app_type);
+ sample_rate =
+ fe_dai_app_type_cfg[fe_id][session_type].sample_rate;
+ bit_width =
+ app_type_cfg[app_type_idx].bit_width;
+ } else {
+ sample_rate = msm_bedais[i].sample_rate;
+ }
+ acdb_dev_id =
+ fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(path_type,
+ fe_id, session_type);
+ if (compr_passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
+ topology = COMPRESS_PASSTHROUGH_NONE_TOPOLOGY;
+ pr_err("%s: Before adm open topology %d\n", __func__,
+ topology);
+
+ copp_idx =
+ adm_open(msm_bedais[i].port_id,
+ path_type, sample_rate, channels,
+ topology, perf_mode, bit_width,
+ app_type, acdb_dev_id);
+ if ((copp_idx < 0) ||
+ (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s:adm open failed coppid:%d\n",
+ __func__, copp_idx);
+ mutex_unlock(&routing_lock);
+ return -EINVAL;
+ }
+ pr_debug("%s: set idx bit of fe:%d, type: %d, be:%d\n",
+ __func__, fe_id, session_type, i);
+ set_bit(copp_idx,
+ &session_copp_map[fe_id][session_type][i]);
+
+ if (msm_is_resample_needed(
+ sample_rate,
+ msm_bedais[i].sample_rate))
+ adm_copp_mfc_cfg(
+ msm_bedais[i].port_id, copp_idx,
+ msm_bedais[i].sample_rate);
+
+ for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+ unsigned long copp =
+ session_copp_map[fe_id][session_type][i];
+ if (test_bit(j, &copp)) {
+ payload.port_id[num_copps] =
+ msm_bedais[i].port_id;
+ payload.copp_idx[num_copps] = j;
+ num_copps++;
+ }
+ }
+ if (compr_passthr_mode != COMPRESSED_PASSTHROUGH_DSD) {
+ msm_routing_send_device_pp_params(
+ msm_bedais[i].port_id,
+ copp_idx);
+ }
+ }
+ }
+ if (num_copps) {
+ payload.num_copps = num_copps;
+ payload.session_id = fe_dai_map[fe_id][session_type].strm_id;
+ payload.app_type =
+ fe_dai_app_type_cfg[fe_id][session_type].app_type;
+ payload.acdb_dev_id =
+ fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
+ adm_matrix_map(path_type, payload, perf_mode);
+ msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
+ }
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static u32 msm_pcm_routing_get_voc_sessionid(u16 val)
+{
+ u32 session_id;
+
+ switch (val) {
+ case MSM_FRONTEND_DAI_CS_VOICE:
+ session_id = voc_get_session_id(VOICE_SESSION_NAME);
+ break;
+ case MSM_FRONTEND_DAI_VOLTE:
+ session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ break;
+ case MSM_FRONTEND_DAI_VOWLAN:
+ session_id = voc_get_session_id(VOWLAN_SESSION_NAME);
+ break;
+ case MSM_FRONTEND_DAI_VOICE2:
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+ break;
+ case MSM_FRONTEND_DAI_QCHAT:
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ break;
+ case MSM_FRONTEND_DAI_VOIP:
+ session_id = voc_get_session_id(VOIP_SESSION_NAME);
+ break;
+ case MSM_FRONTEND_DAI_VOICEMMODE1:
+ session_id = voc_get_session_id(VOICEMMODE1_NAME);
+ break;
+ case MSM_FRONTEND_DAI_VOICEMMODE2:
+ session_id = voc_get_session_id(VOICEMMODE2_NAME);
+ break;
+ default:
+ session_id = 0;
+ }
+
+ pr_debug("%s session_id 0x%x", __func__, session_id);
+ return session_id;
+}
+
+int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
+ int dspst_id, int stream_type)
+{
+ int i, j, session_type, path_type, port_type, topology, num_copps = 0;
+ struct route_payload payload;
+ u32 channels, sample_rate;
+ uint16_t bits_per_sample = 16;
+
+ if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ /* bad ID assigned in machine driver */
+ pr_err("%s: bad MM ID %d\n", __func__, fedai_id);
+ return -EINVAL;
+ }
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+ session_type = SESSION_TYPE_RX;
+ path_type = ADM_PATH_PLAYBACK;
+ port_type = MSM_AFE_PORT_TYPE_RX;
+ } else {
+ session_type = SESSION_TYPE_TX;
+ path_type = ADM_PATH_LIVE_REC;
+ port_type = MSM_AFE_PORT_TYPE_TX;
+ }
+
+ mutex_lock(&routing_lock);
+
+ payload.num_copps = 0; /* only RX needs to use payload */
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
+ fe_dai_map[fedai_id][session_type].perf_mode = perf_mode;
+
+ /* re-enable EQ if active */
+ msm_qti_pp_send_eq_values(fedai_id);
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (!is_be_dai_extproc(i) &&
+ (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+ (msm_bedais[i].active) &&
+ (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+ int app_type, app_type_idx, copp_idx, acdb_dev_id;
+ /*
+ * check if ADM needs to be configured with different
+ * channel mapping than backend
+ */
+ if (!msm_bedais[i].adm_override_ch)
+ channels = msm_bedais[i].channel;
+ else
+ channels = msm_bedais[i].adm_override_ch;
+ msm_bedais[i].compr_passthr_mode =
+ LEGACY_PCM;
+
+ bits_per_sample = msm_routing_get_bit_width(
+ msm_bedais[i].format);
+
+ app_type =
+ fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ if (app_type) {
+ app_type_idx =
+ msm_pcm_routing_get_app_type_idx(app_type);
+ sample_rate =
+ fe_dai_app_type_cfg[fedai_id][session_type].
+ sample_rate;
+ bits_per_sample =
+ app_type_cfg[app_type_idx].bit_width;
+ } else
+ sample_rate = msm_bedais[i].sample_rate;
+
+ acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(path_type,
+ fedai_id, session_type);
+ copp_idx = adm_open(msm_bedais[i].port_id, path_type,
+ sample_rate, channels, topology,
+ perf_mode, bits_per_sample,
+ app_type, acdb_dev_id);
+ if ((copp_idx < 0) ||
+ (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: adm open failed copp_idx:%d\n",
+ __func__, copp_idx);
+ mutex_unlock(&routing_lock);
+ return -EINVAL;
+ }
+ pr_debug("%s: setting idx bit of fe:%d, type: %d, be:%d\n",
+ __func__, fedai_id, session_type, i);
+ set_bit(copp_idx,
+ &session_copp_map[fedai_id][session_type][i]);
+
+ if (msm_is_resample_needed(
+ sample_rate,
+ msm_bedais[i].sample_rate))
+ adm_copp_mfc_cfg(
+ msm_bedais[i].port_id, copp_idx,
+ msm_bedais[i].sample_rate);
+
+ for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+ unsigned long copp =
+ session_copp_map[fedai_id][session_type][i];
+ if (test_bit(j, &copp)) {
+ payload.port_id[num_copps] =
+ msm_bedais[i].port_id;
+ payload.copp_idx[num_copps] = j;
+ num_copps++;
+ }
+ }
+ if ((perf_mode == LEGACY_PCM_MODE) &&
+ (msm_bedais[i].compr_passthr_mode ==
+ LEGACY_PCM))
+ msm_pcm_routing_cfg_pp(msm_bedais[i].port_id,
+ copp_idx, topology,
+ channels);
+ }
+ }
+ if (num_copps) {
+ payload.num_copps = num_copps;
+ payload.session_id = fe_dai_map[fedai_id][session_type].strm_id;
+ payload.app_type =
+ fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ payload.acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
+ payload.sample_rate =
+ fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
+ adm_matrix_map(path_type, payload, perf_mode);
+ msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
+ }
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+int msm_pcm_routing_reg_phy_stream_v2(int fedai_id, int perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info)
+{
+ if (msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
+ stream_type)) {
+ pr_err("%s: failed to reg phy stream\n", __func__);
+ return -EINVAL;
+ }
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+ fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
+ else
+ fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
+ return 0;
+}
+
+void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
+{
+ int i, port_type, session_type, path_type, topology;
+ struct msm_pcm_routing_fdai_data *fdai;
+
+ if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ /* bad ID assigned in machine driver */
+ pr_err("%s: bad MM ID\n", __func__);
+ return;
+ }
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+ port_type = MSM_AFE_PORT_TYPE_RX;
+ session_type = SESSION_TYPE_RX;
+ path_type = ADM_PATH_PLAYBACK;
+ } else {
+ port_type = MSM_AFE_PORT_TYPE_TX;
+ session_type = SESSION_TYPE_TX;
+ path_type = ADM_PATH_LIVE_REC;
+ }
+
+ mutex_lock(&routing_lock);
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (!is_be_dai_extproc(i) &&
+ (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+ (msm_bedais[i].active) &&
+ (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+ int idx;
+ unsigned long copp =
+ session_copp_map[fedai_id][session_type][i];
+ fdai = &fe_dai_map[fedai_id][session_type];
+
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++)
+ if (test_bit(idx, &copp))
+ break;
+
+ if (idx >= MAX_COPPS_PER_PORT || idx < 0) {
+ pr_debug("%s: copp idx is invalid, exiting\n",
+ __func__);
+ continue;
+ }
+ topology = adm_get_topology_for_port_copp_idx(
+ msm_bedais[i].port_id, idx);
+ adm_close(msm_bedais[i].port_id, fdai->perf_mode, idx);
+ pr_debug("%s:copp:%ld,idx bit fe:%d,type:%d,be:%d\n",
+ __func__, copp, fedai_id, session_type, i);
+ clear_bit(idx,
+ &session_copp_map[fedai_id][session_type][i]);
+ if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID ||
+ topology == DS2_ADM_COPP_TOPOLOGY_ID) &&
+ (fdai->perf_mode == LEGACY_PCM_MODE) &&
+ (msm_bedais[i].compr_passthr_mode ==
+ LEGACY_PCM))
+ msm_pcm_routing_deinit_pp(msm_bedais[i].port_id,
+ topology);
+ }
+ }
+
+ fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+ fe_dai_map[fedai_id][session_type].be_srate = 0;
+ mutex_unlock(&routing_lock);
+}
+
+/* Check if FE/BE route is set */
+static bool msm_pcm_routing_route_is_set(u16 be_id, u16 fe_id)
+{
+ bool rc = false;
+
+ if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ /* recheck FE ID in the mixer control defined in this file */
+ pr_err("%s: bad MM ID\n", __func__);
+ return rc;
+ }
+
+ if (test_bit(fe_id, &msm_bedais[be_id].fe_sessions))
+ rc = true;
+
+ return rc;
+}
+
+static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
+{
+ int session_type, path_type, topology;
+ u32 channels, sample_rate;
+ uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_fdai_data *fdai;
+
+ pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
+
+ if (val > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ /* recheck FE ID in the mixer control defined in this file */
+ pr_err("%s: bad MM ID\n", __func__);
+ return;
+ }
+
+ if (afe_get_port_type(msm_bedais[reg].port_id) ==
+ MSM_AFE_PORT_TYPE_RX) {
+ session_type = SESSION_TYPE_RX;
+ if (msm_bedais[reg].compr_passthr_mode != LEGACY_PCM)
+ path_type = ADM_PATH_COMPRESSED_RX;
+ else
+ path_type = ADM_PATH_PLAYBACK;
+ } else {
+ session_type = SESSION_TYPE_TX;
+ path_type = ADM_PATH_LIVE_REC;
+ }
+
+ mutex_lock(&routing_lock);
+ if (set) {
+ if (!test_bit(val, &msm_bedais[reg].fe_sessions) &&
+ ((msm_bedais[reg].port_id == VOICE_PLAYBACK_TX) ||
+ (msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
+ voc_start_playback(set, msm_bedais[reg].port_id);
+
+ set_bit(val, &msm_bedais[reg].fe_sessions);
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
+ INVALID_SESSION) {
+ int app_type, app_type_idx, copp_idx, acdb_dev_id;
+ /*
+ * check if ADM needs to be configured with different
+ * channel mapping than backend
+ */
+ if (!msm_bedais[reg].adm_override_ch)
+ channels = msm_bedais[reg].channel;
+ else
+ channels = msm_bedais[reg].adm_override_ch;
+ if (session_type == SESSION_TYPE_TX &&
+ fdai->be_srate &&
+ (fdai->be_srate != msm_bedais[reg].sample_rate)) {
+ pr_debug("%s: flush strm %d diff BE rates\n",
+ __func__, fdai->strm_id);
+
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
+
+ bits_per_sample = msm_routing_get_bit_width(
+ msm_bedais[reg].format);
+
+ app_type =
+ fe_dai_app_type_cfg[val][session_type].app_type;
+ if (app_type) {
+ app_type_idx =
+ msm_pcm_routing_get_app_type_idx(app_type);
+ sample_rate =
+ fe_dai_app_type_cfg[val][session_type].
+ sample_rate;
+ bits_per_sample =
+ app_type_cfg[app_type_idx].bit_width;
+ } else
+ sample_rate = msm_bedais[reg].sample_rate;
+
+ topology = msm_routing_get_adm_topology(path_type, val,
+ session_type);
+ acdb_dev_id =
+ fe_dai_app_type_cfg[val][session_type].acdb_dev_id;
+ copp_idx = adm_open(msm_bedais[reg].port_id, path_type,
+ sample_rate, channels, topology,
+ fdai->perf_mode, bits_per_sample,
+ app_type, acdb_dev_id);
+ if ((copp_idx < 0) ||
+ (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: adm open failed\n", __func__);
+ mutex_unlock(&routing_lock);
+ return;
+ }
+ pr_debug("%s: setting idx bit of fe:%d, type: %d, be:%d\n",
+ __func__, val, session_type, reg);
+ set_bit(copp_idx,
+ &session_copp_map[val][session_type][reg]);
+
+ if (msm_is_resample_needed(
+ sample_rate,
+ msm_bedais[reg].sample_rate))
+ adm_copp_mfc_cfg(
+ msm_bedais[reg].port_id, copp_idx,
+ msm_bedais[reg].sample_rate);
+
+ if (session_type == SESSION_TYPE_RX &&
+ fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ fdai->event_info.priv_data);
+
+ msm_pcm_routing_build_matrix(val, session_type,
+ path_type,
+ fdai->perf_mode);
+ if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
+ (msm_bedais[reg].compr_passthr_mode ==
+ LEGACY_PCM))
+ msm_pcm_routing_cfg_pp(msm_bedais[reg].port_id,
+ copp_idx, topology,
+ channels);
+ }
+ } else {
+ if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
+ ((msm_bedais[reg].port_id == VOICE_PLAYBACK_TX) ||
+ (msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
+ voc_start_playback(set, msm_bedais[reg].port_id);
+ clear_bit(val, &msm_bedais[reg].fe_sessions);
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
+ INVALID_SESSION) {
+ int idx;
+ int port_id;
+ unsigned long copp =
+ session_copp_map[val][session_type][reg];
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++)
+ if (test_bit(idx, &copp))
+ break;
+
+ port_id = msm_bedais[reg].port_id;
+ topology = adm_get_topology_for_port_copp_idx(port_id,
+ idx);
+ adm_close(msm_bedais[reg].port_id, fdai->perf_mode,
+ idx);
+ pr_debug("%s: copp: %ld, reset idx bit fe:%d, type: %d, be:%d topology=0x%x\n",
+ __func__, copp, val, session_type, reg,
+ topology);
+ clear_bit(idx,
+ &session_copp_map[val][session_type][reg]);
+ if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID ||
+ topology == DS2_ADM_COPP_TOPOLOGY_ID) &&
+ (fdai->perf_mode == LEGACY_PCM_MODE) &&
+ (msm_bedais[reg].compr_passthr_mode ==
+ LEGACY_PCM))
+ msm_pcm_routing_deinit_pp(
+ msm_bedais[reg].port_id,
+ topology);
+ msm_pcm_routing_build_matrix(val, session_type,
+ path_type,
+ fdai->perf_mode);
+ }
+ }
+ if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
+ || (msm_bedais[reg].port_id == VOICE_RECORD_TX))
+ voc_start_record(msm_bedais[reg].port_id, set, voc_session_id);
+
+ mutex_unlock(&routing_lock);
+}
+
+static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_dapm_update *update = NULL;
+
+ if (ucontrol->value.integer.value[0] &&
+ msm_pcm_routing_route_is_set(mc->reg, mc->shift) == false) {
+ msm_pcm_routing_process_audio(mc->reg, mc->shift, 1);
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ } else if (!ucontrol->value.integer.value[0] &&
+ msm_pcm_routing_route_is_set(mc->reg, mc->shift) == true) {
+ msm_pcm_routing_process_audio(mc->reg, mc->shift, 0);
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ }
+
+ return 1;
+}
+
+static void msm_pcm_routing_process_voice(u16 reg, u16 val, int set)
+{
+ u32 session_id = 0;
+ u16 path_type;
+
+ pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
+
+ session_id = msm_pcm_routing_get_voc_sessionid(val);
+
+ pr_debug("%s: FE DAI 0x%x session_id 0x%x\n",
+ __func__, val, session_id);
+
+ mutex_lock(&routing_lock);
+
+ if (set)
+ set_bit(val, &msm_bedais[reg].fe_sessions);
+ else
+ clear_bit(val, &msm_bedais[reg].fe_sessions);
+
+ if (val == MSM_FRONTEND_DAI_DTMF_RX &&
+ afe_get_port_type(msm_bedais[reg].port_id) ==
+ MSM_AFE_PORT_TYPE_RX) {
+ pr_debug("%s(): set=%d port id=0x%x for dtmf generation\n",
+ __func__, set, msm_bedais[reg].port_id);
+ afe_set_dtmf_gen_rx_portid(msm_bedais[reg].port_id, set);
+ }
+
+ if (afe_get_port_type(msm_bedais[reg].port_id) ==
+ MSM_AFE_PORT_TYPE_RX)
+ path_type = RX_PATH;
+ else
+ path_type = TX_PATH;
+
+ if (set) {
+ if (msm_bedais[reg].active) {
+ voc_set_route_flag(session_id, path_type, 1);
+ voc_set_device_config(session_id, path_type,
+ msm_bedais[reg].channel, msm_bedais[reg].port_id);
+
+ if (voc_get_route_flag(session_id, TX_PATH) &&
+ voc_get_route_flag(session_id, RX_PATH))
+ voc_enable_device(session_id);
+ } else {
+ pr_debug("%s BE is not active\n", __func__);
+ }
+ } else {
+ voc_set_route_flag(session_id, path_type, 0);
+ voc_disable_device(session_id);
+ }
+
+ mutex_unlock(&routing_lock);
+
+}
+
+static int msm_routing_get_voice_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ mutex_lock(&routing_lock);
+
+ if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ mutex_unlock(&routing_lock);
+
+ pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_routing_put_voice_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_dapm_update *update = NULL;
+
+ if (ucontrol->value.integer.value[0]) {
+ msm_pcm_routing_process_voice(mc->reg, mc->shift, 1);
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ } else {
+ msm_pcm_routing_process_voice(mc->reg, mc->shift, 0);
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ }
+
+ return 1;
+}
+
+static int msm_routing_get_voice_stub_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ mutex_lock(&routing_lock);
+
+ if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ mutex_unlock(&routing_lock);
+
+ pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_routing_put_voice_stub_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_dapm_update *update = NULL;
+
+ if (ucontrol->value.integer.value[0]) {
+ mutex_lock(&routing_lock);
+ set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+ mutex_unlock(&routing_lock);
+
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ } else {
+ mutex_lock(&routing_lock);
+ clear_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+ mutex_unlock(&routing_lock);
+
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ }
+
+ pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+ ucontrol->value.integer.value[0]);
+
+ return 1;
+}
+
+static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = fm_switch_enable;
+ pr_debug("%s: FM Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_update *update = NULL;
+
+ pr_debug("%s: FM Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0])
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ else
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ fm_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_get_hfp_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = hfp_switch_enable;
+ pr_debug("%s: HFP Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_hfp_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_update *update = NULL;
+
+ pr_debug("%s: HFP Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0])
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol,
+ 1, update);
+ else
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol,
+ 0, update);
+ hfp_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_get_pri_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = pri_mi2s_switch_enable;
+ pr_debug("%s: PRI MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_pri_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_update *update = NULL;
+
+ pr_debug("%s: PRI MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0])
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ else
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ pri_mi2s_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_get_sec_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = sec_mi2s_switch_enable;
+ pr_debug("%s: SEC MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_sec_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_update *update = NULL;
+
+ pr_debug("%s: SEC MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0])
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ else
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ sec_mi2s_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_get_tert_mi2s_switch_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = tert_mi2s_switch_enable;
+ pr_debug("%s: TERT MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_tert_mi2s_switch_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_update *update = NULL;
+
+ pr_debug("%s: TERT MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0])
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ else
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ tert_mi2s_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_get_quat_mi2s_switch_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = quat_mi2s_switch_enable;
+ pr_debug("%s: QUAT MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_quat_mi2s_switch_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_update *update = NULL;
+
+ pr_debug("%s: QUAT MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0])
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ else
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ quat_mi2s_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_get_fm_pcmrx_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = fm_pcmrx_switch_enable;
+ pr_debug("%s: FM Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_fm_pcmrx_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_update *update = NULL;
+
+ pr_debug("%s: FM Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0])
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+ update);
+ else
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+ update);
+ fm_pcmrx_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_lsm_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = lsm_mux_slim_port;
+ return 0;
+}
+
+static int msm_routing_lsm_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int mux = ucontrol->value.enumerated.item[0];
+ int lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
+ struct snd_soc_dapm_update *update = NULL;
+
+ pr_debug("%s: LSM enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX;
+ break;
+ case 2:
+ lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX;
+ break;
+ case 3:
+ lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX;
+ break;
+ case 4:
+ lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX;
+ break;
+ case 5:
+ lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX;
+ break;
+ case 6:
+ lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
+ break;
+ case 7:
+ lsm_port = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ default:
+ pr_err("Default lsm port");
+ break;
+ }
+ set_lsm_port(lsm_port);
+
+ if (ucontrol->value.integer.value[0]) {
+ lsm_mux_slim_port = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e,
+ update);
+ } else {
+ snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e,
+ update);
+ lsm_mux_slim_port = ucontrol->value.integer.value[0];
+ }
+
+ return 0;
+}
+
+static int msm_routing_lsm_func_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ u16 port_id;
+ enum afe_mad_type mad_type;
+
+ pr_debug("%s: enter\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+ if (!strcmp(kcontrol->id.name, mad_audio_mux_text[i]))
+ break;
+
+ if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+ WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ /*Check for Tertiary TX port*/
+ if (!strcmp(kcontrol->id.name, mad_audio_mux_text[7])) {
+ ucontrol->value.integer.value[0] = MADSWAUDIO;
+ return 0;
+ }
+
+ port_id = i * 2 + 1 + SLIMBUS_0_RX;
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ switch (mad_type) {
+ case MAD_HW_NONE:
+ ucontrol->value.integer.value[0] = MADNONE;
+ break;
+ case MAD_HW_AUDIO:
+ ucontrol->value.integer.value[0] = MADAUDIO;
+ break;
+ case MAD_HW_BEACON:
+ ucontrol->value.integer.value[0] = MADBEACON;
+ break;
+ case MAD_HW_ULTRASOUND:
+ ucontrol->value.integer.value[0] = MADULTRASOUND;
+ break;
+ case MAD_SW_AUDIO:
+ ucontrol->value.integer.value[0] = MADSWAUDIO;
+ break;
+ default:
+ WARN(1, "Unknown\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_routing_lsm_func_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ u16 port_id;
+ enum afe_mad_type mad_type;
+
+ pr_debug("%s: enter\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+ if (!strcmp(kcontrol->id.name, mad_audio_mux_text[i]))
+ break;
+
+ if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+ WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ port_id = i * 2 + 1 + SLIMBUS_0_RX;
+ switch (ucontrol->value.integer.value[0]) {
+ case MADNONE:
+ mad_type = MAD_HW_NONE;
+ break;
+ case MADAUDIO:
+ mad_type = MAD_HW_AUDIO;
+ break;
+ case MADBEACON:
+ mad_type = MAD_HW_BEACON;
+ break;
+ case MADULTRASOUND:
+ mad_type = MAD_HW_ULTRASOUND;
+ break;
+ case MADSWAUDIO:
+ mad_type = MAD_SW_AUDIO;
+ break;
+ default:
+ WARN(1, "Unknown\n");
+ return -EINVAL;
+ }
+
+ /*Check for Tertiary TX port*/
+ if (!strcmp(kcontrol->id.name, mad_audio_mux_text[7])) {
+ port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ mad_type = MAD_SW_AUDIO;
+ }
+
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ return afe_port_set_mad_type(port_id, mad_type);
+}
+
+static const char *const adm_override_chs_text[] = {"Zero", "One", "Two"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(slim_7_rx_adm_override_chs,
+ adm_override_chs_text);
+
+static int msm_routing_adm_get_backend_idx(struct snd_kcontrol *kcontrol)
+{
+ int backend_id;
+
+ if (strnstr(kcontrol->id.name, "SLIM7_RX", sizeof("SLIM7_RX"))) {
+ backend_id = MSM_BACKEND_DAI_SLIMBUS_7_RX;
+ } else {
+ pr_err("%s: unsupported backend id: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return backend_id;
+}
+static int msm_routing_adm_channel_config_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int backend_id = msm_routing_adm_get_backend_idx(kcontrol);
+
+ if (backend_id >= 0) {
+ mutex_lock(&routing_lock);
+ ucontrol->value.integer.value[0] =
+ msm_bedais[backend_id].adm_override_ch;
+ pr_debug("%s: adm channel count %ld for BE:%d\n", __func__,
+ ucontrol->value.integer.value[0], backend_id);
+ mutex_unlock(&routing_lock);
+ }
+
+ return 0;
+}
+
+static int msm_routing_adm_channel_config_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int backend_id = msm_routing_adm_get_backend_idx(kcontrol);
+
+ if (backend_id >= 0) {
+ mutex_lock(&routing_lock);
+ msm_bedais[backend_id].adm_override_ch =
+ ucontrol->value.integer.value[0];
+ pr_debug("%s:updating BE :%d adm channels: %d\n",
+ __func__, backend_id,
+ msm_bedais[backend_id].adm_override_ch);
+ mutex_unlock(&routing_lock);
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new adm_channel_config_controls[] = {
+ SOC_ENUM_EXT("SLIM7_RX ADM Channels", slim_7_rx_adm_override_chs,
+ msm_routing_adm_channel_config_get,
+ msm_routing_adm_channel_config_put),
+};
+
+static int msm_routing_slim_0_rx_aanc_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ mutex_lock(&routing_lock);
+ ucontrol->value.integer.value[0] = slim0_rx_aanc_fb_port;
+ mutex_unlock(&routing_lock);
+ pr_debug("%s: AANC Mux Port %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+};
+
+static int msm_routing_slim_0_rx_aanc_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct aanc_data aanc_info;
+
+ mutex_lock(&routing_lock);
+ memset(&aanc_info, 0x00, sizeof(aanc_info));
+ pr_debug("%s: AANC Mux Port %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ slim0_rx_aanc_fb_port = ucontrol->value.integer.value[0];
+ if (ucontrol->value.integer.value[0] == 0) {
+ aanc_info.aanc_active = false;
+ aanc_info.aanc_tx_port = 0;
+ aanc_info.aanc_rx_port = 0;
+ } else {
+ aanc_info.aanc_active = true;
+ aanc_info.aanc_rx_port = SLIMBUS_0_RX;
+ aanc_info.aanc_tx_port =
+ (SLIMBUS_0_RX - 1 + (slim0_rx_aanc_fb_port * 2));
+ }
+ afe_set_aanc_info(&aanc_info);
+ mutex_unlock(&routing_lock);
+ return 0;
+};
+static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = 0, shift = 0;
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ idx = mc->shift/(sizeof(msm_bedais[mc->reg].port_sessions[0]) * 8);
+ shift = mc->shift%(sizeof(msm_bedais[mc->reg].port_sessions[0]) * 8);
+
+ if (idx >= BE_DAI_PORT_SESSIONS_IDX_MAX) {
+ pr_err("%s: Invalid idx = %d\n", __func__, idx);
+ return -EINVAL;
+ }
+
+ if (test_bit(shift,
+ (unsigned long *)&msm_bedais[mc->reg].port_sessions[idx]))
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_routing_put_port_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = 0, shift = 0;
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ idx = mc->shift/(sizeof(msm_bedais[mc->reg].port_sessions[0]) * 8);
+ shift = mc->shift%(sizeof(msm_bedais[mc->reg].port_sessions[0]) * 8);
+
+ if (idx >= BE_DAI_PORT_SESSIONS_IDX_MAX) {
+ pr_err("%s: Invalid idx = %d\n", __func__, idx);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: reg 0x%x shift 0x%x val %ld idx %d reminder shift %d\n",
+ __func__, mc->reg, mc->shift,
+ ucontrol->value.integer.value[0], idx, shift);
+
+ if (ucontrol->value.integer.value[0]) {
+ afe_loopback(1, msm_bedais[mc->reg].port_id,
+ msm_bedais[mc->shift].port_id);
+ set_bit(shift,
+ (unsigned long *)&msm_bedais[mc->reg].port_sessions[idx]);
+ } else {
+ afe_loopback(0, msm_bedais[mc->reg].port_id,
+ msm_bedais[mc->shift].port_id);
+ clear_bit(shift,
+ (unsigned long *)&msm_bedais[mc->reg].port_sessions[idx]);
+ }
+
+ return 1;
+}
+
+static int msm_routing_ec_ref_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ec_ref_rx = %d", __func__, msm_route_ec_ref_rx);
+ mutex_lock(&routing_lock);
+ ucontrol->value.integer.value[0] = msm_route_ec_ref_rx;
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ec_ref_port_id;
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ int mux = ucontrol->value.enumerated.item[0];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_update *update = NULL;
+
+ mutex_lock(&routing_lock);
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm_route_ec_ref_rx = 0;
+ ec_ref_port_id = AFE_PORT_INVALID;
+ break;
+ case 1:
+ msm_route_ec_ref_rx = 1;
+ ec_ref_port_id = SLIMBUS_0_RX;
+ break;
+ case 2:
+ msm_route_ec_ref_rx = 2;
+ ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
+ break;
+ case 3:
+ msm_route_ec_ref_rx = 3;
+ ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ break;
+ case 4:
+ msm_route_ec_ref_rx = 4;
+ ec_ref_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case 5:
+ msm_route_ec_ref_rx = 5;
+ ec_ref_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case 6:
+ msm_route_ec_ref_rx = 6;
+ ec_ref_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
+ case 7:
+ msm_route_ec_ref_rx = 7;
+ ec_ref_port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+ break;
+ case 9:
+ msm_route_ec_ref_rx = 9;
+ ec_ref_port_id = SLIMBUS_5_RX;
+ break;
+ case 10:
+ msm_route_ec_ref_rx = 10;
+ ec_ref_port_id = SLIMBUS_1_TX;
+ break;
+ case 11:
+ msm_route_ec_ref_rx = 11;
+ ec_ref_port_id = AFE_PORT_ID_QUATERNARY_TDM_TX_1;
+ break;
+ case 12:
+ msm_route_ec_ref_rx = 12;
+ ec_ref_port_id = AFE_PORT_ID_QUATERNARY_TDM_RX;
+ break;
+ case 13:
+ msm_route_ec_ref_rx = 13;
+ ec_ref_port_id = AFE_PORT_ID_QUATERNARY_TDM_RX_1;
+ break;
+ case 14:
+ msm_route_ec_ref_rx = 14;
+ ec_ref_port_id = AFE_PORT_ID_QUATERNARY_TDM_RX_2;
+ break;
+ case 15:
+ msm_route_ec_ref_rx = 15;
+ ec_ref_port_id = SLIMBUS_6_RX;
+ break;
+ case 16:
+ msm_route_ec_ref_rx = 16;
+ ec_ref_port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+ break;
+ case 17:
+ msm_route_ec_ref_rx = 17;
+ ec_ref_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ break;
+ case 18:
+ msm_route_ec_ref_rx = 18;
+ ec_ref_port_id = AFE_PORT_ID_TERTIARY_TDM_TX;
+ break;
+ case 19:
+ msm_route_ec_ref_rx = 19;
+ ec_ref_port_id = AFE_PORT_ID_USB_RX;
+ break;
+ default:
+ msm_route_ec_ref_rx = 0; /* NONE */
+ pr_err("%s EC ref rx %ld not valid\n",
+ __func__, ucontrol->value.integer.value[0]);
+ ec_ref_port_id = AFE_PORT_INVALID;
+ break;
+ }
+ adm_ec_ref_rx_id(ec_ref_port_id);
+ pr_debug("%s: msm_route_ec_ref_rx = %d\n",
+ __func__, msm_route_ec_ref_rx);
+ mutex_unlock(&routing_lock);
+ snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e, update);
+ return 0;
+}
+
+static const char *const ec_ref_rx[] = { "None", "SLIM_RX", "I2S_RX",
+ "PRI_MI2S_TX", "SEC_MI2S_TX",
+ "TERT_MI2S_TX", "QUAT_MI2S_TX", "SEC_I2S_RX", "PROXY_RX",
+ "SLIM_5_RX", "SLIM_1_TX", "QUAT_TDM_TX_1",
+ "QUAT_TDM_RX_0", "QUAT_TDM_RX_1", "QUAT_TDM_RX_2", "SLIM_6_RX",
+ "TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0", "USB_AUDIO_RX"};
+
+static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_rx), ec_ref_rx),
+};
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul1 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL1 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul2 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL2 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul3 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL3 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul4 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL4 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul5 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL5 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul6 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL6 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul8 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL8 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL9 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul18 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL18 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul19 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL19 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ext_ec_ref_rx = %x\n", __func__, msm_route_ext_ec_ref);
+
+ mutex_lock(&routing_lock);
+ ucontrol->value.integer.value[0] = msm_route_ext_ec_ref;
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static int msm_routing_ext_ec_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist =
+ dapm_kcontrol_get_wlist(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ int mux = ucontrol->value.enumerated.item[0];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int ret = 1;
+ bool state = true;
+ uint16_t ext_ec_ref_port_id;
+ struct snd_soc_dapm_update *update = NULL;
+
+ mutex_lock(&routing_lock);
+ msm_route_ext_ec_ref = ucontrol->value.integer.value[0];
+
+ switch (msm_route_ext_ec_ref) {
+ case EXT_EC_REF_PRI_MI2S_TX:
+ ext_ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ break;
+ case EXT_EC_REF_SEC_MI2S_TX:
+ ext_ec_ref_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case EXT_EC_REF_TERT_MI2S_TX:
+ ext_ec_ref_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case EXT_EC_REF_QUAT_MI2S_TX:
+ ext_ec_ref_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
+ case EXT_EC_REF_QUIN_MI2S_TX:
+ ext_ec_ref_port_id = AFE_PORT_ID_QUINARY_MI2S_TX;
+ break;
+ case EXT_EC_REF_SLIM_1_TX:
+ ext_ec_ref_port_id = SLIMBUS_1_TX;
+ break;
+ case EXT_EC_REF_NONE:
+ default:
+ ext_ec_ref_port_id = AFE_PORT_INVALID;
+ state = false;
+ break;
+ }
+
+ pr_debug("%s: val = %d ext_ec_ref_port_id = 0x%0x state = %d\n",
+ __func__, msm_route_ext_ec_ref, ext_ec_ref_port_id, state);
+
+ if (!voc_set_ext_ec_ref(ext_ec_ref_port_id, state)) {
+ mutex_unlock(&routing_lock);
+ snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e,
+ update);
+ } else {
+ ret = -EINVAL;
+ mutex_unlock(&routing_lock);
+ }
+ return ret;
+}
+
+static const char * const ext_ec_ref_rx[] = {"NONE", "PRI_MI2S_TX",
+ "SEC_MI2S_TX", "TERT_MI2S_TX",
+ "QUAT_MI2S_TX", "QUIN_MI2S_TX",
+ "SLIM_1_TX"};
+
+static const struct soc_enum msm_route_ext_ec_ref_rx_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ext_ec_ref_rx), ext_ec_ref_rx),
+};
+
+static const struct snd_kcontrol_new voc_ext_ec_mux =
+ SOC_DAPM_ENUM_EXT("VOC_EXT_EC MUX Mux", msm_route_ext_ec_ref_rx_enum[0],
+ msm_routing_ext_ec_get, msm_routing_ext_ec_put);
+
+
+static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+
+};
+
+static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new secondary_mi2s_rx2_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_SD1,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int4_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new display_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+ /* incall music delivery mixer */
+static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new incall_music2_delivery_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_4_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_7_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new usb_audio_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new quat_auxpcm_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_QUINARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_QUINARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul3_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul17_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul18_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul19_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_6_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new usb_audio_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_USB_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new pri_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new int0_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new int4_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tert_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new quat_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new quin_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tert_aux_pcm_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new quat_aux_pcm_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_7_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_8_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_EXTPROC_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_EXTPROC_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_EXTPROC_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_1_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_Voice", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_Voice", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_Voice", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voice", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX_Voice", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX_Voice", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX_Voice", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_Voice2", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_Voice2", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice2",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_Voice2", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voice2", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX_Voice2", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX_Voice2", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_volte_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_VoLTE", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_VoLTE",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_VoLTE", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_VoLTE", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_VoLTE", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX_VoLTE", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX_VoLTE", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX_VoLTE", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX_VoLTE", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_vowlan_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_VoWLAN", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_VoWLAN", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_VoWLAN",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_VoWLAN", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_VoWLAN", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_VoWLAN", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX_VoWLAN", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX_VoWLAN", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX_VoWLAN", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX_VoWLAN", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voicemmode1_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_MMode1", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_MMode1", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_MMode1",
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT_BT_SCO_TX_MMode1",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_MMode1",
+ MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_MMode1",
+ MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_MMode1",
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX_MMode1",
+ MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_MMode1",
+ MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_MMode1",
+ MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX_MMode1",
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1,
+ 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX_MMode1",
+ MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1,
+ 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX_MMode1",
+ MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX_MMode1",
+ MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX_MMode1", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voicemmode2_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_MMode2", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_MMode2", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_MMode2",
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT_BT_SCO_TX_MMode2",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_MMode2",
+ MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_MMode2",
+ MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_MMode2",
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX_MMode2",
+ MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_MMode2",
+ MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_MMode2",
+ MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX_MMode2",
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2,
+ 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX_MMode2",
+ MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2,
+ 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX_MMode2",
+ MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX_MMode2",
+ MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX_MMode2",
+ MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
+ 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_Voip", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voip", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_Voip", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_Voip", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voip", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX_Voip", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX_Voip", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX_Voip", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
+ SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voice2_stub_mixer_controls[] = {
+ SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new tx_volte_stub_mixer_controls[] = {
+ SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new tx_qchat_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_QCHAT", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_QCHAT",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_QCHAT", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_QCHAT", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_QCHAT", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX_QCHAT", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX_QCHAT", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX_QCHAT", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_RX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_RX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_RX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_RX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new aux_pcm_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sec_auxpcm_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new tert_auxpcm_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new quat_auxpcm_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sbus_1_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sbus_3_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_AFE_PCM_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_AUXPCM_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sbus_6_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new afe_pcm_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+
+static const struct snd_kcontrol_new hdmi_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new display_port_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new mi2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new primary_mi2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_QUINARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new quat_mi2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_rx_0_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_rx_1_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_rx_2_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new tert_tdm_rx_3_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_rx_0_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_rx_1_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_rx_2_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new quat_tdm_rx_3_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new tert_mi2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new slim_fm_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
+static const struct snd_kcontrol_new slim1_fm_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
+static const struct snd_kcontrol_new slim3_fm_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
+static const struct snd_kcontrol_new slim4_fm_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
+static const struct snd_kcontrol_new slim6_fm_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
+static const struct snd_kcontrol_new pcm_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
+ msm_routing_put_fm_pcmrx_switch_mixer);
+
+static const struct snd_kcontrol_new pri_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_pri_mi2s_switch_mixer,
+ msm_routing_put_pri_mi2s_switch_mixer);
+
+static const struct snd_kcontrol_new sec_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_sec_mi2s_switch_mixer,
+ msm_routing_put_sec_mi2s_switch_mixer);
+
+static const struct snd_kcontrol_new tert_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_tert_mi2s_switch_mixer,
+ msm_routing_put_tert_mi2s_switch_mixer);
+
+static const struct snd_kcontrol_new quat_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_quat_mi2s_switch_mixer,
+ msm_routing_put_quat_mi2s_switch_mixer);
+
+static const struct snd_kcontrol_new hfp_pri_aux_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_hfp_switch_mixer,
+ msm_routing_put_hfp_switch_mixer);
+
+static const struct snd_kcontrol_new hfp_aux_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_hfp_switch_mixer,
+ msm_routing_put_hfp_switch_mixer);
+
+static const struct snd_kcontrol_new hfp_int_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_hfp_switch_mixer,
+ msm_routing_put_hfp_switch_mixer);
+
+static const struct soc_enum lsm_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
+
+static const struct snd_kcontrol_new lsm1_mux =
+ SOC_DAPM_ENUM_EXT("LSM1 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm2_mux =
+ SOC_DAPM_ENUM_EXT("LSM2 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm3_mux =
+ SOC_DAPM_ENUM_EXT("LSM3 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm4_mux =
+ SOC_DAPM_ENUM_EXT("LSM4 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm5_mux =
+ SOC_DAPM_ENUM_EXT("LSM5 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm6_mux =
+ SOC_DAPM_ENUM_EXT("LSM6 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm7_mux =
+ SOC_DAPM_ENUM_EXT("LSM7 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm8_mux =
+ SOC_DAPM_ENUM_EXT("LSM8 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+
+static const char * const lsm_func_text[] = {
+ "None", "AUDIO", "BEACON", "ULTRASOUND", "SWAUDIO",
+};
+static const struct soc_enum lsm_func_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_func_text), lsm_func_text);
+static const struct snd_kcontrol_new lsm_function[] = {
+ SOC_ENUM_EXT(SLIMBUS_0_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_1_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_2_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_3_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_4_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_5_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(TERT_MI2S_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+};
+
+static const char * const aanc_slim_0_rx_text[] = {
+ "ZERO", "SLIMBUS_0_TX", "SLIMBUS_1_TX", "SLIMBUS_2_TX", "SLIMBUS_3_TX",
+ "SLIMBUS_4_TX", "SLIMBUS_5_TX", "SLIMBUS_6_TX"
+};
+
+static const struct soc_enum aanc_slim_0_rx_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aanc_slim_0_rx_text),
+ aanc_slim_0_rx_text);
+
+static const struct snd_kcontrol_new aanc_slim_0_rx_mux[] = {
+ SOC_ENUM_EXT("AANC_SLIM_0_RX MUX", aanc_slim_0_rx_enum,
+ msm_routing_slim_0_rx_aanc_mux_get,
+ msm_routing_slim_0_rx_aanc_mux_put)
+};
+
+static int msm_routing_get_stereo_to_custom_stereo_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = is_custom_stereo_on;
+ return 0;
+}
+
+static int msm_routing_put_stereo_to_custom_stereo_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int flag = 0, i = 0, rc = 0, idx = 0;
+ int be_index = 0, port_id, topo_id;
+ unsigned int session_id = 0;
+ uint16_t op_FL_ip_FL_weight = 0;
+ uint16_t op_FL_ip_FR_weight = 0;
+ uint16_t op_FR_ip_FL_weight = 0;
+ uint16_t op_FR_ip_FR_weight = 0;
+
+ flag = ucontrol->value.integer.value[0];
+ pr_debug("%s E flag %d\n", __func__, flag);
+
+ if ((is_custom_stereo_on && flag) || (!is_custom_stereo_on && !flag)) {
+ pr_err("%s: is_custom_stereo_on %d, flag %d\n",
+ __func__, is_custom_stereo_on, flag);
+ return 0;
+ }
+ is_custom_stereo_on = flag ? true : false;
+ pr_debug("%s:is_custom_stereo_on %d\n", __func__, is_custom_stereo_on);
+ for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) {
+ port_id = msm_bedais[be_index].port_id;
+ if (!msm_bedais[be_index].active)
+ continue;
+ if ((port_id != SLIMBUS_0_RX) &&
+ (port_id != RT_PROXY_PORT_001_RX) &&
+ (port_id != AFE_PORT_ID_PRIMARY_MI2S_RX))
+ continue;
+
+ for_each_set_bit(i, &msm_bedais[be_index].fe_sessions,
+ MSM_FRONTEND_DAI_MM_SIZE) {
+ if (fe_dai_map[i][SESSION_TYPE_RX].perf_mode !=
+ LEGACY_PCM_MODE)
+ goto skip_send_custom_stereo;
+ session_id =
+ fe_dai_map[i][SESSION_TYPE_RX].strm_id;
+ if (is_custom_stereo_on) {
+ op_FL_ip_FL_weight =
+ Q14_GAIN_ZERO_POINT_FIVE;
+ op_FL_ip_FR_weight =
+ Q14_GAIN_ZERO_POINT_FIVE;
+ op_FR_ip_FL_weight =
+ Q14_GAIN_ZERO_POINT_FIVE;
+ op_FR_ip_FR_weight =
+ Q14_GAIN_ZERO_POINT_FIVE;
+ } else {
+ op_FL_ip_FL_weight = Q14_GAIN_UNITY;
+ op_FL_ip_FR_weight = 0;
+ op_FR_ip_FL_weight = 0;
+ op_FR_ip_FR_weight = Q14_GAIN_UNITY;
+ }
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
+ unsigned long copp =
+ session_copp_map[i]
+ [SESSION_TYPE_RX][be_index];
+ if (!test_bit(idx, &copp))
+ goto skip_send_custom_stereo;
+ topo_id = adm_get_topology_for_port_copp_idx(
+ msm_bedais[be_index].port_id, idx);
+ if (topo_id < 0)
+ pr_debug("%s:Err:custom stereo topo %d",
+ __func__, topo_id);
+ pr_debug("idx %d\n", idx);
+ if (topo_id == DS2_ADM_COPP_TOPOLOGY_ID)
+ rc = msm_ds2_dap_set_custom_stereo_onoff
+ (msm_bedais[be_index].port_id,
+ idx, is_custom_stereo_on);
+ else if (topo_id == DOLBY_ADM_COPP_TOPOLOGY_ID)
+ rc = dolby_dap_set_custom_stereo_onoff(
+ msm_bedais[be_index].port_id,
+ idx, is_custom_stereo_on);
+ else
+ rc = msm_qti_pp_send_stereo_to_custom_stereo_cmd
+ (msm_bedais[be_index].port_id,
+ idx, session_id,
+ op_FL_ip_FL_weight,
+ op_FL_ip_FR_weight,
+ op_FR_ip_FL_weight,
+ op_FR_ip_FR_weight);
+ if (rc < 0)
+skip_send_custom_stereo:
+ pr_err("%s: err setting custom stereo\n",
+ __func__);
+ }
+
+ }
+ }
+ return 0;
+}
+
+static const struct snd_kcontrol_new stereo_to_custom_stereo_controls[] = {
+ SOC_SINGLE_EXT("Set Custom Stereo OnOff", SND_SOC_NOPM, 0,
+ 1, 0, msm_routing_get_stereo_to_custom_stereo_control,
+ msm_routing_put_stereo_to_custom_stereo_control),
+};
+
+static int msm_routing_get_app_type_cfg_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 0;
+}
+
+static int msm_routing_put_app_type_cfg_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i = 0, j;
+ int num_app_types = ucontrol->value.integer.value[i++];
+
+ pr_debug("%s\n", __func__);
+
+ memset(app_type_cfg, 0, MAX_APP_TYPES*
+ sizeof(struct msm_pcm_routing_app_type_data));
+ if (num_app_types > MAX_APP_TYPES) {
+ pr_err("%s: number of app types exceed the max supported\n",
+ __func__);
+ return -EINVAL;
+ }
+ for (j = 0; j < num_app_types; j++) {
+ app_type_cfg[j].app_type =
+ ucontrol->value.integer.value[i++];
+ app_type_cfg[j].sample_rate =
+ ucontrol->value.integer.value[i++];
+ app_type_cfg[j].bit_width =
+ ucontrol->value.integer.value[i++];
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new app_type_cfg_controls[] = {
+ SOC_SINGLE_MULTI_EXT("App Type Config", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, 128, msm_routing_get_app_type_cfg_control,
+ msm_routing_put_app_type_cfg_control),
+};
+
+static int msm_routing_get_use_ds1_or_ds2_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = is_ds2_on;
+ return 0;
+}
+
+static int msm_routing_put_use_ds1_or_ds2_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ is_ds2_on = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static const struct snd_kcontrol_new use_ds1_or_ds2_controls[] = {
+ SOC_SINGLE_EXT("DS2 OnOff", SND_SOC_NOPM, 0,
+ 1, 0, msm_routing_get_use_ds1_or_ds2_control,
+ msm_routing_put_use_ds1_or_ds2_control),
+};
+
+int msm_routing_get_rms_value_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ int rc = 0;
+ int be_idx = 0;
+ char *param_value;
+ int *update_param_value;
+ uint32_t param_length = sizeof(uint32_t);
+ uint32_t param_payload_len = RMS_PAYLOAD_LEN * sizeof(uint32_t);
+
+ param_value = kzalloc(param_length, GFP_KERNEL);
+ if (!param_value)
+ return -ENOMEM;
+
+ for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++)
+ if (msm_bedais[be_idx].port_id == SLIMBUS_0_TX)
+ break;
+ if ((be_idx < MSM_BACKEND_DAI_MAX) && msm_bedais[be_idx].active) {
+ rc = adm_get_params(SLIMBUS_0_TX, 0,
+ RMS_MODULEID_APPI_PASSTHRU,
+ RMS_PARAM_FIRST_SAMPLE,
+ param_length + param_payload_len,
+ param_value);
+ if (rc) {
+ pr_err("%s: get parameters failed:%d\n", __func__, rc);
+ kfree(param_value);
+ return -EINVAL;
+ }
+ update_param_value = (int *)param_value;
+ ucontrol->value.integer.value[0] = update_param_value[0];
+
+ pr_debug("%s: FROM DSP value[0] 0x%x\n",
+ __func__, update_param_value[0]);
+ }
+ kfree(param_value);
+ return 0;
+}
+
+static int msm_voc_session_id_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ voc_session_id = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: voc_session_id=%u\n", __func__, voc_session_id);
+
+ return 0;
+}
+
+static int msm_voc_session_id_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = voc_session_id;
+
+ return 0;
+}
+
+static struct snd_kcontrol_new msm_voc_session_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Voc VSID", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, 1, msm_voc_session_id_get,
+ msm_voc_session_id_put),
+};
+
+static int msm_sound_focus_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(struct sound_focus_param);
+
+ return 0;
+}
+
+static int msm_voice_sound_focus_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct sound_focus_param soundFocusData;
+
+ memcpy((void *)&soundFocusData, ucontrol->value.bytes.data,
+ sizeof(struct sound_focus_param));
+ ret = voc_set_sound_focus(soundFocusData);
+ if (ret) {
+ pr_err("%s: Error setting Sound Focus Params, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int msm_voice_sound_focus_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct sound_focus_param soundFocusData;
+
+ memset(&soundFocusData, 0, sizeof(struct sound_focus_param));
+
+ ret = voc_get_sound_focus(&soundFocusData);
+ if (ret) {
+ pr_err("%s: Error getting Sound Focus Params, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ memcpy(ucontrol->value.bytes.data, (void *)&soundFocusData,
+ sizeof(struct sound_focus_param));
+
+done:
+ return ret;
+}
+
+static int msm_source_tracking_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(struct source_tracking_param);
+
+ return 0;
+}
+
+static int msm_voice_source_tracking_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct source_tracking_param sourceTrackingData;
+
+ memset(&sourceTrackingData, 0, sizeof(struct source_tracking_param));
+
+ ret = voc_get_source_tracking(&sourceTrackingData);
+ if (ret) {
+ pr_err("%s: Error getting Source Tracking Params, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ memcpy(ucontrol->value.bytes.data, (void *)&sourceTrackingData,
+ sizeof(struct source_tracking_param));
+
+done:
+ return ret;
+}
+
+static int msm_audio_get_copp_idx_from_port_id(int port_id, int session_type,
+ int *copp_idx)
+{
+ int i, idx, be_idx;
+ int ret = 0;
+ unsigned long copp;
+
+ pr_debug("%s: Enter, port_id=%d\n", __func__, port_id);
+
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port validation failed id 0x%x ret %d\n",
+ __func__, port_id, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) {
+ if (msm_bedais[be_idx].port_id == port_id)
+ break;
+ }
+ if (be_idx >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: Invalid be id %d\n", __func__, be_idx);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions,
+ MSM_FRONTEND_DAI_MM_SIZE) {
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
+ copp = session_copp_map[i]
+ [session_type][be_idx];
+ if (test_bit(idx, &copp))
+ break;
+ }
+ if (idx >= MAX_COPPS_PER_PORT)
+ continue;
+ else
+ break;
+ }
+ if (i >= MSM_FRONTEND_DAI_MM_SIZE) {
+ pr_err("%s: Invalid FE, exiting\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ *copp_idx = idx;
+ pr_debug("%s: copp_idx=%d\n", __func__, *copp_idx);
+
+done:
+ return ret;
+}
+
+static int msm_audio_sound_focus_derive_port_id(struct snd_kcontrol *kcontrol,
+ const char *prefix, int *port_id)
+{
+ int ret = 0;
+
+ pr_debug("%s: Enter, prefix:%s\n", __func__, prefix);
+
+ /*
+ * Mixer control name will be like "Sound Focus Audio Tx SLIMBUS_0"
+ * where the prefix is "Sound Focus Audio Tx ". Skip the prefix
+ * and compare the string with the backend name to derive the port id.
+ */
+ if (!strcmp(kcontrol->id.name + strlen(prefix),
+ "SLIMBUS_0")) {
+ *port_id = SLIMBUS_0_TX;
+ } else if (!strcmp(kcontrol->id.name + strlen(prefix),
+ "TERT_MI2S")) {
+ *port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ } else {
+ pr_err("%s: mixer ctl name=%s, could not derive valid port id\n",
+ __func__, kcontrol->id.name);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ pr_debug("%s: mixer ctl name=%s, derived port_id=%d\n",
+ __func__, kcontrol->id.name, *port_id);
+
+done:
+ return ret;
+}
+
+static int msm_audio_sound_focus_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct sound_focus_param soundFocusData;
+ int port_id, copp_idx;
+
+ ret = msm_audio_sound_focus_derive_port_id(kcontrol,
+ "Sound Focus Audio Tx ", &port_id);
+ if (ret != 0) {
+ pr_err("%s: Error in deriving port id, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_audio_get_copp_idx_from_port_id(port_id, SESSION_TYPE_TX,
+ &copp_idx);
+ if (ret) {
+ pr_err("%s: Could not get copp idx for port_id=%d\n",
+ __func__, port_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy((void *)&soundFocusData, ucontrol->value.bytes.data,
+ sizeof(struct sound_focus_param));
+
+ ret = adm_set_sound_focus(port_id, copp_idx, soundFocusData);
+ if (ret) {
+ pr_err("%s: Error setting Sound Focus Params, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int msm_audio_sound_focus_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct sound_focus_param soundFocusData;
+ int port_id, copp_idx;
+
+ ret = msm_audio_sound_focus_derive_port_id(kcontrol,
+ "Sound Focus Audio Tx ", &port_id);
+ if (ret) {
+ pr_err("%s: Error in deriving port id, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_audio_get_copp_idx_from_port_id(port_id, SESSION_TYPE_TX,
+ &copp_idx);
+ if (ret) {
+ pr_err("%s: Could not get copp idx for port_id=%d\n",
+ __func__, port_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = adm_get_sound_focus(port_id, copp_idx, &soundFocusData);
+ if (ret) {
+ pr_err("%s: Error getting Sound Focus Params, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(ucontrol->value.bytes.data, (void *)&soundFocusData,
+ sizeof(struct sound_focus_param));
+
+done:
+ return ret;
+}
+
+static int msm_audio_source_tracking_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct source_tracking_param sourceTrackingData;
+ int port_id, copp_idx;
+
+ ret = msm_audio_sound_focus_derive_port_id(kcontrol,
+ "Source Tracking Audio Tx ", &port_id);
+ if (ret) {
+ pr_err("%s: Error in deriving port id, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_audio_get_copp_idx_from_port_id(port_id, SESSION_TYPE_TX,
+ &copp_idx);
+ if (ret) {
+ pr_err("%s: Could not get copp idx for port_id=%d\n",
+ __func__, port_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = adm_get_source_tracking(port_id, copp_idx, &sourceTrackingData);
+ if (ret) {
+ pr_err("%s: Error getting Source Tracking Params, err=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(ucontrol->value.bytes.data, (void *)&sourceTrackingData,
+ sizeof(struct source_tracking_param));
+
+done:
+ return ret;
+}
+
+static const struct snd_kcontrol_new msm_source_tracking_controls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Sound Focus Voice Tx SLIMBUS_0",
+ .info = msm_sound_focus_info,
+ .get = msm_voice_sound_focus_get,
+ .put = msm_voice_sound_focus_put,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Source Tracking Voice Tx SLIMBUS_0",
+ .info = msm_source_tracking_info,
+ .get = msm_voice_source_tracking_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Sound Focus Audio Tx SLIMBUS_0",
+ .info = msm_sound_focus_info,
+ .get = msm_audio_sound_focus_get,
+ .put = msm_audio_sound_focus_put,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Source Tracking Audio Tx SLIMBUS_0",
+ .info = msm_source_tracking_info,
+ .get = msm_audio_source_tracking_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Sound Focus Voice Tx TERT_MI2S",
+ .info = msm_sound_focus_info,
+ .get = msm_voice_sound_focus_get,
+ .put = msm_voice_sound_focus_put,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Source Tracking Voice Tx TERT_MI2S",
+ .info = msm_source_tracking_info,
+ .get = msm_voice_source_tracking_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Sound Focus Audio Tx TERT_MI2S",
+ .info = msm_sound_focus_info,
+ .get = msm_audio_sound_focus_get,
+ .put = msm_audio_sound_focus_put,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Source Tracking Audio Tx TERT_MI2S",
+ .info = msm_source_tracking_info,
+ .get = msm_audio_source_tracking_get,
+ },
+};
+
+static int spkr_prot_put_vi_lch_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int item;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ pr_debug("%s item is %d\n", __func__,
+ ucontrol->value.enumerated.item[0]);
+ mutex_lock(&routing_lock);
+ item = ucontrol->value.enumerated.item[0];
+ if (item < e->items) {
+ pr_debug("%s RX DAI ID %d TX DAI id %d\n",
+ __func__, e->shift_l, e->values[item]);
+ if (e->shift_l < MSM_BACKEND_DAI_MAX &&
+ e->values[item] < MSM_BACKEND_DAI_MAX)
+ /* Enable feedback TX path */
+ ret = afe_spk_prot_feed_back_cfg(
+ msm_bedais[e->values[item]].port_id,
+ msm_bedais[e->shift_l].port_id, 1, 0, 1);
+ else {
+ pr_debug("%s values are out of range item %d\n",
+ __func__, e->values[item]);
+ /* Disable feedback TX path */
+ if (e->values[item] == MSM_BACKEND_DAI_MAX)
+ ret = afe_spk_prot_feed_back_cfg(0, 0, 0, 0, 0);
+ else
+ ret = -EINVAL;
+ }
+ } else {
+ pr_err("%s item value is out of range item\n", __func__);
+ ret = -EINVAL;
+ }
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
+static int spkr_prot_put_vi_rch_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int item;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ pr_debug("%s item is %d\n", __func__,
+ ucontrol->value.enumerated.item[0]);
+ mutex_lock(&routing_lock);
+ item = ucontrol->value.enumerated.item[0];
+ if (item < e->items) {
+ pr_debug("%s RX DAI ID %d TX DAI id %d\n",
+ __func__, e->shift_l, e->values[item]);
+ if (e->shift_l < MSM_BACKEND_DAI_MAX &&
+ e->values[item] < MSM_BACKEND_DAI_MAX)
+ /* Enable feedback TX path */
+ ret = afe_spk_prot_feed_back_cfg(
+ msm_bedais[e->values[item]].port_id,
+ msm_bedais[e->shift_l].port_id,
+ 1, 1, 1);
+ else {
+ pr_debug("%s values are out of range item %d\n",
+ __func__, e->values[item]);
+ /* Disable feedback TX path */
+ if (e->values[item] == MSM_BACKEND_DAI_MAX)
+ ret = afe_spk_prot_feed_back_cfg(0,
+ 0, 0, 0, 0);
+ else
+ ret = -EINVAL;
+ }
+ } else {
+ pr_err("%s item value is out of range item\n", __func__);
+ ret = -EINVAL;
+ }
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
+static int spkr_prot_get_vi_lch_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static int spkr_prot_get_vi_rch_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s\n", __func__);
+ ucontrol->value.enumerated.item[0] = 0;
+ return 0;
+}
+
+static const char * const slim0_rx_vi_fb_tx_lch_mux_text[] = {
+ "ZERO", "SLIM4_TX"
+};
+
+static const char * const slim0_rx_vi_fb_tx_rch_mux_text[] = {
+ "ZERO", "SLIM4_TX"
+};
+
+static const char * const mi2s_rx_vi_fb_tx_mux_text[] = {
+ "ZERO", "SENARY_TX"
+};
+
+static const int const slim0_rx_vi_fb_tx_lch_value[] = {
+ MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SLIMBUS_4_TX
+};
+
+static const int const slim0_rx_vi_fb_tx_rch_value[] = {
+ MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SLIMBUS_4_TX
+};
+
+static const int const mi2s_rx_vi_fb_tx_value[] = {
+ MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SENARY_MI2S_TX
+};
+
+static const struct soc_enum slim0_rx_vi_fb_lch_mux_enum =
+ SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0,
+ ARRAY_SIZE(slim0_rx_vi_fb_tx_lch_mux_text),
+ slim0_rx_vi_fb_tx_lch_mux_text, slim0_rx_vi_fb_tx_lch_value);
+
+static const struct soc_enum slim0_rx_vi_fb_rch_mux_enum =
+ SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0,
+ ARRAY_SIZE(slim0_rx_vi_fb_tx_rch_mux_text),
+ slim0_rx_vi_fb_tx_rch_mux_text, slim0_rx_vi_fb_tx_rch_value);
+
+static const struct soc_enum mi2s_rx_vi_fb_mux_enum =
+ SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_PRI_MI2S_RX, 0, 0,
+ ARRAY_SIZE(mi2s_rx_vi_fb_tx_mux_text),
+ mi2s_rx_vi_fb_tx_mux_text, mi2s_rx_vi_fb_tx_value);
+
+static const struct snd_kcontrol_new slim0_rx_vi_fb_lch_mux =
+ SOC_DAPM_ENUM_EXT("SLIM0_RX_VI_FB_LCH_MUX",
+ slim0_rx_vi_fb_lch_mux_enum, spkr_prot_get_vi_lch_port,
+ spkr_prot_put_vi_lch_port);
+
+static const struct snd_kcontrol_new slim0_rx_vi_fb_rch_mux =
+ SOC_DAPM_ENUM_EXT("SLIM0_RX_VI_FB_RCH_MUX",
+ slim0_rx_vi_fb_rch_mux_enum, spkr_prot_get_vi_rch_port,
+ spkr_prot_put_vi_rch_port);
+
+static const struct snd_kcontrol_new mi2s_rx_vi_fb_mux =
+ SOC_DAPM_ENUM_EXT("PRI_MI2S_RX_VI_FB_MUX",
+ mi2s_rx_vi_fb_mux_enum, spkr_prot_get_vi_lch_port,
+ spkr_prot_put_vi_lch_port);
+
+static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
+ /* Frontend AIF */
+ /* Widget name equals to Front-End DAI name<Need confirmation>,
+ * Stream name must contains substring of front-end dai name
+ */
+ SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL9", "MultiMedia9 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL10", "MultiMedia10 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL11", "MultiMedia11 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL12", "MultiMedia12 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL13", "MultiMedia13 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL14", "MultiMedia14 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL15", "MultiMedia15 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL16", "MultiMedia16 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE2_UL", "Voice2 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VoWLAN_DL", "VoWLAN Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VoWLAN_UL", "VoWLAN Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICEMMODE1_DL",
+ "VoiceMMode1 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICEMMODE1_UL",
+ "VoiceMMode1 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICEMMODE2_DL",
+ "VoiceMMode2 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICEMMODE2_UL",
+ "VoiceMMode2 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIM0_UL_HL", "SLIMBUS0_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("CPE_LSM_UL_HL", "CPE LSM capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM1_DL_HL", "SLIMBUS1_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIM1_UL_HL", "SLIMBUS1_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM3_DL_HL", "SLIMBUS3_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIM3_UL_HL", "SLIMBUS3_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM4_DL_HL", "SLIMBUS4_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIM4_UL_HL", "SLIMBUS4_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM6_DL_HL", "SLIMBUS6_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIM6_UL_HL", "SLIMBUS6_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM8_DL_HL", "SLIMBUS8_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIM8_UL_HL", "SLIMBUS8_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INTFM_DL_HL", "INT_FM_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT0_MI2S_DL_HL",
+ "INT0 MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT4_MI2S_DL_HL",
+ "INT4 MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_MI2S_DL_HL",
+ "Primary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_MI2S_DL_HL",
+ "Secondary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_MI2S_DL_HL",
+ "Tertiary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_MI2S_DL_HL",
+ "Quaternary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("AUXPCM_DL_HL", "AUXPCM_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AUXPCM_UL_HL", "AUXPCM_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_MI2S_UL_HL",
+ "Tertiary MI2S_TX Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_MI2S_UL_HL",
+ "Secondary MI2S_TX Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_MI2S_UL_HL",
+ "Primary MI2S_TX Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_UL_HL",
+ "Quaternary MI2S_TX Hostless Capture",
+ 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_RX_0_DL_HL",
+ "Primary TDM0 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_TX_0_UL_HL",
+ "Primary TDM0 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_RX_1_DL_HL",
+ "Primary TDM1 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_TX_1_UL_HL",
+ "Primary TDM1 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_RX_2_DL_HL",
+ "Primary TDM2 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_TX_2_UL_HL",
+ "Primary TDM2 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_RX_3_DL_HL",
+ "Primary TDM3 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_TX_3_UL_HL",
+ "Primary TDM3 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_RX_4_DL_HL",
+ "Primary TDM4 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_TX_4_UL_HL",
+ "Primary TDM4 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_RX_5_DL_HL",
+ "Primary TDM5 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_TX_5_UL_HL",
+ "Primary TDM5 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_RX_6_DL_HL",
+ "Primary TDM6 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_TX_6_UL_HL",
+ "Primary TDM6 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_RX_7_DL_HL",
+ "Primary TDM7 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_TX_7_UL_HL",
+ "Primary TDM7 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_0_DL_HL",
+ "Secondary TDM0 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_0_UL_HL",
+ "Secondary TDM0 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_1_DL_HL",
+ "Secondary TDM1 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_1_UL_HL",
+ "Secondary TDM1 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_2_DL_HL",
+ "Secondary TDM2 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_2_UL_HL",
+ "Secondary TDM2 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_3_DL_HL",
+ "Secondary TDM3 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_3_UL_HL",
+ "Secondary TDM3 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_4_DL_HL",
+ "Secondary TDM4 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_4_UL_HL",
+ "Secondary TDM4 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_5_DL_HL",
+ "Secondary TDM5 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_5_UL_HL",
+ "Secondary TDM5 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_6_DL_HL",
+ "Secondary TDM6 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_6_UL_HL",
+ "Secondary TDM6 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_7_DL_HL",
+ "Secondary TDM7 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_7_UL_HL",
+ "Secondary TDM7 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_0_DL_HL",
+ "Tertiary TDM0 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_0_UL_HL",
+ "Tertiary TDM0 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_1_DL_HL",
+ "Tertiary TDM1 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_1_UL_HL",
+ "Tertiary TDM1 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_2_DL_HL",
+ "Tertiary TDM2 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_2_UL_HL",
+ "Tertiary TDM2 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_3_DL_HL",
+ "Tertiary TDM3 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_3_UL_HL",
+ "Tertiary TDM3 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_4_DL_HL",
+ "Tertiary TDM4 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_4_UL_HL",
+ "Tertiary TDM4 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_5_DL_HL",
+ "Tertiary TDM5 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_5_UL_HL",
+ "Tertiary TDM5 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_6_DL_HL",
+ "Tertiary TDM6 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_6_UL_HL",
+ "Tertiary TDM6 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_7_DL_HL",
+ "Tertiary TDM7 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_7_UL_HL",
+ "Tertiary TDM7 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_0_DL_HL",
+ "Quaternary TDM0 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_0_UL_HL",
+ "Quaternary TDM0 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_1_DL_HL",
+ "Quaternary TDM1 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_1_UL_HL",
+ "Quaternary TDM1 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_2_DL_HL",
+ "Quaternary TDM2 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_2_UL_HL",
+ "Quaternary TDM2 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_3_DL_HL",
+ "Quaternary TDM3 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_3_UL_HL",
+ "Quaternary TDM3 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_4_DL_HL",
+ "Quaternary TDM4 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_4_UL_HL",
+ "Quaternary TDM4 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_5_DL_HL",
+ "Quaternary TDM5 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_5_UL_HL",
+ "Quaternary TDM5 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_6_DL_HL",
+ "Quaternary TDM6 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_6_UL_HL",
+ "Quaternary TDM6 Hostless Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_7_DL_HL",
+ "Quaternary TDM7 Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_7_UL_HL",
+ "Quaternary TDM7 Hostless Capture",
+ 0, 0, 0, 0),
+
+ /* LSM */
+ SND_SOC_DAPM_AIF_OUT("LSM1_UL_HL", "Listen 1 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM2_UL_HL", "Listen 2 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM3_UL_HL", "Listen 3 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM4_UL_HL", "Listen 4 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM5_UL_HL", "Listen 5 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM6_UL_HL", "Listen 6 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM7_UL_HL", "Listen 7 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM8_UL_HL", "Listen 8 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QCHAT_DL", "QCHAT Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QCHAT_UL", "QCHAT Capture", 0, 0, 0, 0),
+ /* Backend AIF */
+ /* Stream name equals to backend dai link stream name */
+ SND_SOC_DAPM_AIF_OUT("PRI_I2S_RX", "Primary I2S Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_I2S_RX", "Secondary I2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SPDIF_RX", "SPDIF Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_RX", "Slimbus2 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT", "Display Port Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_MI2S_RX", "Tertiary MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX", "Secondary MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX_SD1",
+ "Secondary MI2S Playback SD1",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_MI2S_RX", "Primary MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT0_MI2S_RX", "INT0 MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT4_MI2S_RX", "INT4 MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUIN_MI2S_RX", "Quinary MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT2_MI2S_TX", "INT2 MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT3_MI2S_TX", "INT3 MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_2_TX", "Slimbus2 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_MI2S_TX", "Quinary MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SENARY_MI2S_TX", "Senary MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT_BT_SCO_TX", "Internal BT-SCO Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT_BT_A2DP_RX", "Internal BT-A2DP Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT_FM_RX", "Internal FM Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT_FM_TX", "Internal FM Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PCM_RX", "AFE Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PCM_TX", "AFE Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_RX_0", "Primary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_TX_0", "Primary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_RX_1", "Primary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_TX_1", "Primary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_RX_2", "Primary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_TX_2", "Primary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_RX_3", "Primary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_TX_3", "Primary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_RX_4", "Primary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_TX_4", "Primary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_RX_5", "Primary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_TX_5", "Primary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_RX_6", "Primary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_TX_6", "Primary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_TDM_RX_7", "Primary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_TDM_TX_7", "Primary TDM7 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_0", "Secondary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_0", "Secondary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_1", "Secondary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_1", "Secondary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_2", "Secondary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_2", "Secondary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_3", "Secondary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_3", "Secondary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_4", "Secondary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_4", "Secondary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_5", "Secondary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_5", "Secondary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_6", "Secondary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_6", "Secondary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_7", "Secondary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_7", "Secondary TDM7 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_0", "Tertiary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_0", "Tertiary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_1", "Tertiary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_1", "Tertiary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_2", "Tertiary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_2", "Tertiary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_3", "Tertiary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_3", "Tertiary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_4", "Tertiary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_4", "Tertiary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_5", "Tertiary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_5", "Tertiary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_6", "Tertiary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_6", "Tertiary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_7", "Tertiary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_7", "Tertiary TDM7 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_0", "Quaternary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_0", "Quaternary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_1", "Quaternary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_1", "Quaternary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_2", "Quaternary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_2", "Quaternary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_3", "Quaternary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_3", "Quaternary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_4", "Quaternary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_4", "Quaternary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_5", "Quaternary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_5", "Quaternary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_6", "Quaternary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_6", "Quaternary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_7", "Quaternary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_7", "Quaternary TDM7 Capture",
+ 0, 0, 0, 0),
+ /* incall */
+ SND_SOC_DAPM_AIF_OUT("VOICE_PLAYBACK_TX", "Voice Farend Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE2_PLAYBACK_TX", "Voice2 Farend Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_RX", "Slimbus4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INCALL_RECORD_TX", "Voice Uplink Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INCALL_RECORD_RX", "Voice Downlink Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_4_TX", "Slimbus4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SENARY_TX", "Senary_mi2s Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_5_TX", "Slimbus5 Capture", 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_AUX_PCM_RX", "Sec AUX PCM Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_AUX_PCM_TX", "Sec AUX PCM Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_AUX_PCM_RX", "Tert AUX PCM Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_AUX_PCM_TX", "Tert AUX PCM Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_AUX_PCM_RX", "Quat AUX PCM Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_AUX_PCM_TX", "Quat AUX PCM Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICE_STUB_DL", "VOICE_STUB Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE_STUB_UL", "VOICE_STUB Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICE2_STUB_DL", "VOICE2_STUB Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE2_STUB_UL", "VOICE2_STUB Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOLTE_STUB_DL", "VOLTE_STUB Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOLTE_STUB_UL", "VOLTE_STUB Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("STUB_RX", "Stub Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("STUB_TX", "Stub Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("STUB_1_TX", "Stub1 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_RX", "Slimbus3 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_3_TX", "Slimbus3 Capture", 0, 0, 0, 0),
+ /* In- call recording */
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_RX", "Slimbus6 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_6_TX", "Slimbus6 Capture", 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_7_RX", "Slimbus7 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_7_TX", "Slimbus7 Capture", 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_8_RX", "Slimbus8 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_8_TX", "Slimbus8 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("USB_AUDIO_RX", "USB Audio Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("USB_AUDIO_TX", "USB Audio Capture", 0, 0, 0, 0),
+
+ /* Switch Definitions */
+ SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
+ &slim_fm_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("SLIMBUS1_DL_HL", SND_SOC_NOPM, 0, 0,
+ &slim1_fm_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("SLIMBUS3_DL_HL", SND_SOC_NOPM, 0, 0,
+ &slim3_fm_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("SLIMBUS4_DL_HL", SND_SOC_NOPM, 0, 0,
+ &slim4_fm_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("SLIMBUS6_DL_HL", SND_SOC_NOPM, 0, 0,
+ &slim6_fm_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &pcm_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("PRI_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &pri_mi2s_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("SEC_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &sec_mi2s_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("TERT_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &tert_mi2s_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("QUAT_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &quat_mi2s_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("HFP_PRI_AUX_UL_HL", SND_SOC_NOPM, 0, 0,
+ &hfp_pri_aux_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("HFP_AUX_UL_HL", SND_SOC_NOPM, 0, 0,
+ &hfp_aux_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("HFP_INT_UL_HL", SND_SOC_NOPM, 0, 0,
+ &hfp_int_switch_mixer_controls),
+
+ /* Mux Definitions */
+ SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm1_mux),
+ SND_SOC_DAPM_MUX("LSM2 MUX", SND_SOC_NOPM, 0, 0, &lsm2_mux),
+ SND_SOC_DAPM_MUX("LSM3 MUX", SND_SOC_NOPM, 0, 0, &lsm3_mux),
+ SND_SOC_DAPM_MUX("LSM4 MUX", SND_SOC_NOPM, 0, 0, &lsm4_mux),
+ SND_SOC_DAPM_MUX("LSM5 MUX", SND_SOC_NOPM, 0, 0, &lsm5_mux),
+ SND_SOC_DAPM_MUX("LSM6 MUX", SND_SOC_NOPM, 0, 0, &lsm6_mux),
+ SND_SOC_DAPM_MUX("LSM7 MUX", SND_SOC_NOPM, 0, 0, &lsm7_mux),
+ SND_SOC_DAPM_MUX("LSM8 MUX", SND_SOC_NOPM, 0, 0, &lsm8_mux),
+
+ /* Mixer definitions */
+ SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_i2s_rx_mixer_controls, ARRAY_SIZE(sec_i2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_rx_mixer_controls, ARRAY_SIZE(slimbus_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_2_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_2_rx_mixer_controls, ARRAY_SIZE(slimbus_2_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_5_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_5_rx_mixer_controls, ARRAY_SIZE(slimbus_5_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_7_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_7_rx_mixer_controls, ARRAY_SIZE(slimbus_7_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
+ hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
+ SND_SOC_DAPM_MIXER("DISPLAY_PORT Mixer", SND_SOC_NOPM, 0, 0,
+ display_port_mixer_controls, ARRAY_SIZE(display_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SPDIF_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ spdif_rx_mixer_controls, ARRAY_SIZE(spdif_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ mi2s_rx_mixer_controls, ARRAY_SIZE(mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quaternary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tertiary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(tertiary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ secondary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(secondary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX_SD1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ secondary_mi2s_rx2_mixer_controls,
+ ARRAY_SIZE(secondary_mi2s_rx2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ primary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(primary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT0_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ int0_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(int0_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT4_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ int4_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(int4_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quinary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(quinary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_tx_0_mixer_controls,
+ ARRAY_SIZE(pri_tdm_tx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_tx_0_mixer_controls,
+ ARRAY_SIZE(sec_tdm_tx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_tx_0_mixer_controls,
+ ARRAY_SIZE(tert_tdm_tx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_tx_0_mixer_controls,
+ ARRAY_SIZE(quat_tdm_tx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia3 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul3_mixer_controls, ARRAY_SIZE(mmul3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul18_mixer_controls, ARRAY_SIZE(mmul18_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia19 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)),
+ SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_auxpcm_rx_mixer_controls, ARRAY_SIZE(sec_auxpcm_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_auxpcm_rx_mixer_controls,
+ ARRAY_SIZE(tert_auxpcm_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_auxpcm_rx_mixer_controls,
+ ARRAY_SIZE(quat_auxpcm_rx_mixer_controls)),
+ /* incall */
+ SND_SOC_DAPM_MIXER("Incall_Music Audio Mixer", SND_SOC_NOPM, 0, 0,
+ incall_music_delivery_mixer_controls,
+ ARRAY_SIZE(incall_music_delivery_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Incall_Music_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ incall_music2_delivery_mixer_controls,
+ ARRAY_SIZE(incall_music2_delivery_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_4_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_4_rx_mixer_controls,
+ ARRAY_SIZE(slimbus_4_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_6_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_6_rx_mixer_controls,
+ ARRAY_SIZE(slimbus_6_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("USB_AUDIO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ usb_audio_rx_mixer_controls,
+ ARRAY_SIZE(usb_audio_rx_mixer_controls)),
+ /* Voice Mixer */
+ SND_SOC_DAPM_MIXER("PRI_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0, pri_rx_voice_mixer_controls,
+ ARRAY_SIZE(pri_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ sec_i2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(sec_i2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ sec_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(sec_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIM_0_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ slimbus_rx_voice_mixer_controls,
+ ARRAY_SIZE(slimbus_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ bt_sco_rx_voice_mixer_controls,
+ ARRAY_SIZE(bt_sco_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("AFE_PCM_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ afe_pcm_rx_voice_mixer_controls,
+ ARRAY_SIZE(afe_pcm_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("AUX_PCM_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ aux_pcm_rx_voice_mixer_controls,
+ ARRAY_SIZE(aux_pcm_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ sec_aux_pcm_rx_voice_mixer_controls,
+ ARRAY_SIZE(sec_aux_pcm_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_AUX_PCM_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ tert_aux_pcm_rx_voice_mixer_controls,
+ ARRAY_SIZE(tert_aux_pcm_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_AUX_PCM_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ quat_aux_pcm_rx_voice_mixer_controls,
+ ARRAY_SIZE(quat_aux_pcm_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("HDMI_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ hdmi_rx_voice_mixer_controls,
+ ARRAY_SIZE(hdmi_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ pri_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(pri_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT0_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ int0_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(int0_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT4_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ int4_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(int4_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ tert_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(tert_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ quat_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(quat_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ quin_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(quin_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voice_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls,
+ ARRAY_SIZE(tx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voice2_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_voice2_mixer_controls,
+ ARRAY_SIZE(tx_voice2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voip_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_voip_mixer_controls,
+ ARRAY_SIZE(tx_voip_mixer_controls)),
+ SND_SOC_DAPM_MIXER("VoLTE_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_volte_mixer_controls,
+ ARRAY_SIZE(tx_volte_mixer_controls)),
+ SND_SOC_DAPM_MIXER("VoWLAN_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_vowlan_mixer_controls,
+ ARRAY_SIZE(tx_vowlan_mixer_controls)),
+ SND_SOC_DAPM_MIXER("VoiceMMode1_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_voicemmode1_mixer_controls,
+ ARRAY_SIZE(tx_voicemmode1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("VoiceMMode2_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_voicemmode2_mixer_controls,
+ ARRAY_SIZE(tx_voicemmode2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INTERNAL_A2DP_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ int_bt_a2dp_rx_mixer_controls,
+ ARRAY_SIZE(int_bt_a2dp_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ int_fm_rx_mixer_controls, ARRAY_SIZE(int_fm_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("AFE_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ afe_pcm_rx_mixer_controls, ARRAY_SIZE(afe_pcm_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voice Stub Tx Mixer", SND_SOC_NOPM, 0, 0,
+ tx_voice_stub_mixer_controls, ARRAY_SIZE(tx_voice_stub_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voice2 Stub Tx Mixer", SND_SOC_NOPM, 0, 0,
+ tx_voice2_stub_mixer_controls,
+ ARRAY_SIZE(tx_voice2_stub_mixer_controls)),
+ SND_SOC_DAPM_MIXER("VoLTE Stub Tx Mixer", SND_SOC_NOPM, 0, 0,
+ tx_volte_stub_mixer_controls, ARRAY_SIZE(tx_volte_stub_mixer_controls)),
+ SND_SOC_DAPM_MIXER("STUB_RX Mixer", SND_SOC_NOPM, 0, 0,
+ stub_rx_mixer_controls, ARRAY_SIZE(stub_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_1_rx_mixer_controls, ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_3_RX_Voice Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_3_rx_mixer_controls, ARRAY_SIZE(slimbus_3_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIM_6_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ slimbus_6_rx_voice_mixer_controls,
+ ARRAY_SIZE(slimbus_6_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIM_7_RX_Voice Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_7_rx_voice_mixer_controls,
+ ARRAY_SIZE(slimbus_7_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIM_8_RX_Voice Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_8_rx_voice_mixer_controls,
+ ARRAY_SIZE(slimbus_8_rx_voice_mixer_controls)),
+ /* port mixer */
+ SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, sbus_0_rx_port_mixer_controls,
+ ARRAY_SIZE(sbus_0_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("AUX_PCM_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, aux_pcm_rx_port_mixer_controls,
+ ARRAY_SIZE(aux_pcm_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_AUXPCM_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, sec_auxpcm_rx_port_mixer_controls,
+ ARRAY_SIZE(sec_auxpcm_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_AUXPCM_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, tert_auxpcm_rx_port_mixer_controls,
+ ARRAY_SIZE(tert_auxpcm_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_AUXPCM_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, quat_auxpcm_rx_port_mixer_controls,
+ ARRAY_SIZE(quat_auxpcm_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ sbus_1_rx_port_mixer_controls,
+ ARRAY_SIZE(sbus_1_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ bt_sco_rx_port_mixer_controls,
+ ARRAY_SIZE(bt_sco_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("AFE_PCM_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, afe_pcm_rx_port_mixer_controls,
+ ARRAY_SIZE(afe_pcm_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("HDMI_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, hdmi_rx_port_mixer_controls,
+ ARRAY_SIZE(hdmi_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, display_port_rx_port_mixer_controls,
+ ARRAY_SIZE(display_port_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls,
+ ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_3_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, sbus_3_rx_port_mixer_controls,
+ ARRAY_SIZE(sbus_3_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_6_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, sbus_6_rx_port_mixer_controls,
+ ARRAY_SIZE(sbus_6_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ mi2s_rx_port_mixer_controls, ARRAY_SIZE(mi2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ primary_mi2s_rx_port_mixer_controls,
+ ARRAY_SIZE(primary_mi2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ sec_mi2s_rx_port_mixer_controls,
+ ARRAY_SIZE(sec_mi2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ tert_mi2s_rx_port_mixer_controls,
+ ARRAY_SIZE(tert_mi2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ quat_mi2s_rx_port_mixer_controls,
+ ARRAY_SIZE(quat_mi2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_0_port_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_0_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_1 Port Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_1_port_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_1_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_2 Port Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_2_port_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_2_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_3 Port Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_3_port_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_3_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_0_port_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_0_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_1 Port Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_1_port_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_1_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_2 Port Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_2_port_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_2_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_3 Port Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_3_port_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_3_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QCHAT_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_qchat_mixer_controls,
+ ARRAY_SIZE(tx_qchat_mixer_controls)),
+ SND_SOC_DAPM_MIXER("USB_AUDIO_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0, usb_audio_rx_voice_mixer_controls,
+ ARRAY_SIZE(usb_audio_rx_voice_mixer_controls)),
+ /* Virtual Pins to force backends ON atm */
+ SND_SOC_DAPM_OUTPUT("BE_OUT"),
+ SND_SOC_DAPM_INPUT("BE_IN"),
+
+ SND_SOC_DAPM_MUX("SLIM0_RX_VI_FB_LCH_MUX", SND_SOC_NOPM, 0, 0,
+ &slim0_rx_vi_fb_lch_mux),
+ SND_SOC_DAPM_MUX("SLIM0_RX_VI_FB_RCH_MUX", SND_SOC_NOPM, 0, 0,
+ &slim0_rx_vi_fb_rch_mux),
+ SND_SOC_DAPM_MUX("PRI_MI2S_RX_VI_FB_MUX", SND_SOC_NOPM, 0, 0,
+ &mi2s_rx_vi_fb_mux),
+
+ SND_SOC_DAPM_MUX("VOC_EXT_EC MUX", SND_SOC_NOPM, 0, 0,
+ &voc_ext_ec_mux),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL1 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul1),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL2 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul2),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL3 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul3),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL4 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul4),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL5 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul5),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL6 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul6),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL8 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul8),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul9),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul17),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL18 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul18),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL19 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul19),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ {"PRI_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
+
+ {"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
+
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
+
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SLIMBUS_2_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SLIMBUS_2_RX", NULL, "SLIMBUS_2_RX Audio Mixer"},
+
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SLIMBUS_5_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SLIMBUS_5_RX", NULL, "SLIMBUS_5_RX Audio Mixer"},
+
+ {"HDMI Mixer", "MultiMedia1", "MM_DL1"},
+ {"HDMI Mixer", "MultiMedia2", "MM_DL2"},
+ {"HDMI Mixer", "MultiMedia3", "MM_DL3"},
+ {"HDMI Mixer", "MultiMedia4", "MM_DL4"},
+ {"HDMI Mixer", "MultiMedia5", "MM_DL5"},
+ {"HDMI Mixer", "MultiMedia6", "MM_DL6"},
+ {"HDMI Mixer", "MultiMedia7", "MM_DL7"},
+ {"HDMI Mixer", "MultiMedia8", "MM_DL8"},
+ {"HDMI Mixer", "MultiMedia9", "MM_DL9"},
+ {"HDMI Mixer", "MultiMedia10", "MM_DL10"},
+ {"HDMI Mixer", "MultiMedia11", "MM_DL11"},
+ {"HDMI Mixer", "MultiMedia12", "MM_DL12"},
+ {"HDMI Mixer", "MultiMedia13", "MM_DL13"},
+ {"HDMI Mixer", "MultiMedia14", "MM_DL14"},
+ {"HDMI Mixer", "MultiMedia15", "MM_DL15"},
+ {"HDMI Mixer", "MultiMedia16", "MM_DL16"},
+ {"HDMI", NULL, "HDMI Mixer"},
+
+ {"DISPLAY_PORT Mixer", "MultiMedia1", "MM_DL1"},
+ {"DISPLAY_PORT Mixer", "MultiMedia2", "MM_DL2"},
+ {"DISPLAY_PORT Mixer", "MultiMedia3", "MM_DL3"},
+ {"DISPLAY_PORT Mixer", "MultiMedia4", "MM_DL4"},
+ {"DISPLAY_PORT Mixer", "MultiMedia5", "MM_DL5"},
+ {"DISPLAY_PORT Mixer", "MultiMedia6", "MM_DL6"},
+ {"DISPLAY_PORT Mixer", "MultiMedia7", "MM_DL7"},
+ {"DISPLAY_PORT Mixer", "MultiMedia8", "MM_DL8"},
+ {"DISPLAY_PORT Mixer", "MultiMedia9", "MM_DL9"},
+ {"DISPLAY_PORT Mixer", "MultiMedia10", "MM_DL10"},
+ {"DISPLAY_PORT Mixer", "MultiMedia11", "MM_DL11"},
+ {"DISPLAY_PORT Mixer", "MultiMedia12", "MM_DL12"},
+ {"DISPLAY_PORT Mixer", "MultiMedia13", "MM_DL13"},
+ {"DISPLAY_PORT Mixer", "MultiMedia14", "MM_DL14"},
+ {"DISPLAY_PORT Mixer", "MultiMedia15", "MM_DL15"},
+ {"DISPLAY_PORT Mixer", "MultiMedia16", "MM_DL16"},
+ {"DISPLAY_PORT", NULL, "DISPLAY_PORT Mixer"},
+
+ {"SPDIF_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SPDIF_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SPDIF_RX", NULL, "SPDIF_RX Audio Mixer"},
+
+ /* incall */
+ {"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"Incall_Music Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"Incall_Music Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"Incall_Music Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"VOICE_PLAYBACK_TX", NULL, "Incall_Music Audio Mixer"},
+ {"Incall_Music_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"Incall_Music_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"Incall_Music_2 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"Incall_Music_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"VOICE2_PLAYBACK_TX", NULL, "Incall_Music_2 Audio Mixer"},
+ {"SLIMBUS_4_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SLIMBUS_4_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SLIMBUS_4_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_4_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SLIMBUS_4_RX", NULL, "SLIMBUS_4_RX Audio Mixer"},
+
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SLIMBUS_6_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"},
+
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SLIMBUS_7_RX", NULL, "SLIMBUS_7_RX Audio Mixer"},
+
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"USB_AUDIO_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"USB_AUDIO_RX", NULL, "USB_AUDIO_RX Audio Mixer"},
+
+ {"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+ {"MultiMedia4 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+ {"MultiMedia8 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+ {"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+ {"MultiMedia4 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+ {"MultiMedia8 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+ {"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
+ {"MultiMedia1 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
+ {"MultiMedia1 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"MultiMedia1 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"MultiMedia8 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
+ {"MultiMedia8 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia17 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia18 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia19 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia8 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia2 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia17 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"MultiMedia5 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"MI2S_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
+
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
+
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Audio Mixer"},
+
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"},
+
+ {"SEC_MI2S_RX_SD1 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_MI2S_RX_SD1", NULL, "SEC_MI2S_RX_SD1 Audio Mixer"},
+
+ {"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"},
+
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX Audio Mixer"},
+
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX Audio Mixer"},
+
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX Audio Mixer"},
+
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
+
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_TX_0", NULL, "PRI_TDM_TX_0 Audio Mixer"},
+
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
+
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_TX_0", NULL, "SEC_TDM_TX_0 Audio Mixer"},
+
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0 Audio Mixer"},
+
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_TDM_TX_0", NULL, "TERT_TDM_TX_0 Audio Mixer"},
+
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1 Audio Mixer"},
+
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2 Audio Mixer"},
+
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"},
+
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
+
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_TDM_TX_0", NULL, "QUAT_TDM_TX_0 Audio Mixer"},
+
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1 Audio Mixer"},
+
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2 Audio Mixer"},
+
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Audio Mixer"},
+
+ {"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
+ {"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia3 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"MultiMedia2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"MultiMedia6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"MultiMedia1 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"},
+ {"MultiMedia2 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"},
+ {"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia2 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia1 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia2 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia1 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia2 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia3 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
+ {"MultiMedia5 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"MultiMedia3 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
+ {"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
+ {"MultiMedia1 Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"},
+ {"MultiMedia3 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
+ {"MultiMedia5 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
+ {"MultiMedia1 Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"},
+ {"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
+ {"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
+ {"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia2 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia6 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia3 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia5 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia6 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia6 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+
+ {"MultiMedia1 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia1 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia1 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia1 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia1 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia1 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia1 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia1 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
+ {"MultiMedia2 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia2 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia2 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia2 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia2 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia2 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia2 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia2 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
+ {"MultiMedia3 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia3 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia3 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia3 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia3 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia3 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia3 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia3 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
+ {"MultiMedia4 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia4 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia4 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia4 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia4 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia4 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia4 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia4 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
+ {"MultiMedia5 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia5 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia5 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia5 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia5 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia5 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia5 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia5 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
+ {"MultiMedia6 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia6 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia6 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia6 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia6 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia6 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia6 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia6 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
+ {"MultiMedia8 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia8 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia8 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia8 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia8 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia8 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia8 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia8 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
+ {"MultiMedia1 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"MultiMedia2 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"MultiMedia4 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"MultiMedia5 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"MultiMedia6 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"MultiMedia8 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_UL6"},
+ {"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
+
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"INTERNAL_A2DP_RX Audio Mixer", "MultiMedia6", "MM_UL6"},
+ {"INT_BT_A2DP_RX", NULL, "INTERNAL_A2DP_RX Audio Mixer"},
+
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
+
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
+
+ {"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia3 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia17 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia18 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia17 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia18 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia19 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+
+ {"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia3 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia17 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia18 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MM_UL1", NULL, "MultiMedia1 Mixer"},
+ {"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MM_UL2", NULL, "MultiMedia2 Mixer"},
+ {"MM_UL3", NULL, "MultiMedia3 Mixer"},
+ {"MM_UL4", NULL, "MultiMedia4 Mixer"},
+ {"MM_UL5", NULL, "MultiMedia5 Mixer"},
+ {"MM_UL6", NULL, "MultiMedia6 Mixer"},
+ {"MM_UL8", NULL, "MultiMedia8 Mixer"},
+ {"MM_UL17", NULL, "MultiMedia17 Mixer"},
+ {"MM_UL18", NULL, "MultiMedia18 Mixer"},
+ {"MM_UL19", NULL, "MultiMedia19 Mixer"},
+
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
+
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"},
+
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_AUX_PCM_RX", NULL, "TERT_AUX_PCM_RX Audio Mixer"},
+
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUAT_AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_AUX_PCM_RX", NULL, "QUAT_AUX_PCM_RX Audio Mixer"},
+
+ {"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+
+ {"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"PRI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"PRI_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"PRI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"PRI_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"PRI_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
+
+ {"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
+
+ {"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_Voice Mixer"},
+
+ {"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SLIM_0_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SLIM_0_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIM_0_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"SLIM_0_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIM_0_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"SLIM_0_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"SLIM_0_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
+
+ {"SLIM_6_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SLIM_6_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SLIM_6_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SLIM_6_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"SLIM_6_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SLIM_6_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SLIM_6_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIM_6_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"SLIM_6_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIM_6_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"SLIM_6_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"SLIM_6_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"SLIMBUS_6_RX", NULL, "SLIM_6_RX_Voice Mixer"},
+
+ {"USB_AUDIO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"USB_AUDIO_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"USB_AUDIO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"USB_AUDIO_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"USB_AUDIO_RX", NULL, "USB_AUDIO_RX_Voice Mixer"},
+
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
+
+ {"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"AFE_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"AFE_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
+
+ {"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
+
+ {"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
+
+ {"TERT_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"TERT_AUX_PCM_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"TERT_AUX_PCM_RX", NULL, "TERT_AUX_PCM_RX_Voice Mixer"},
+
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"QUAT_AUX_PCM_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"QUAT_AUX_PCM_RX", NULL, "QUAT_AUX_PCM_RX_Voice Mixer"},
+
+ {"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"HDMI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"HDMI_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"HDMI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"HDMI_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"HDMI_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"HDMI", NULL, "HDMI_RX_Voice Mixer"},
+ {"HDMI", NULL, "HDMI_DL_HL"},
+
+ {"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+
+ {"PRI_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"PRI_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"PRI_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"PRI_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_Voice Mixer"},
+
+ {"INT0_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"INT0_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"INT0_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"INT0_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"INT0_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX_Voice Mixer"},
+
+ {"INT4_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"INT4_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"INT4_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"INT4_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"INT4_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_Voice Mixer"},
+
+ {"TERT_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"TERT_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"TERT_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"TERT_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX_Voice Mixer"},
+
+ {"QUAT_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"QUAT_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"QUAT_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX_Voice Mixer"},
+
+ {"QUIN_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"QUIN_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"QUIN_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX_Voice Mixer"},
+
+ {"VOC_EXT_EC MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"CS-VOICE_UL1", NULL, "VOC_EXT_EC MUX"},
+ {"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
+ {"VoLTE_UL", NULL, "VOC_EXT_EC MUX"},
+ {"VOICE2_UL", NULL, "VOC_EXT_EC MUX"},
+ {"VOICEMMODE1_UL", NULL, "VOC_EXT_EC MUX"},
+ {"VOICEMMODE2_UL", NULL, "VOC_EXT_EC MUX"},
+
+ {"AUDIO_REF_EC_UL1 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"AUDIO_REF_EC_UL1 MUX", "QUAT_TDM_RX_0", "QUAT_TDM_RX_0"},
+ {"AUDIO_REF_EC_UL1 MUX", "QUAT_TDM_RX_1", "QUAT_TDM_RX_1"},
+ {"AUDIO_REF_EC_UL1 MUX", "QUAT_TDM_RX_2", "QUAT_TDM_RX_2"},
+ {"AUDIO_REF_EC_UL1 MUX", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+
+ {"AUDIO_REF_EC_UL2 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL2 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL2 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL2 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL3 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL3 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL3 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL3 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL4 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL4 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL4 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL4 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL5 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL5 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL5 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL5 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL6 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL6 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL6 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL6 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL8 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL8 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL8 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL8 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL9 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL9 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL17 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL18 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL19 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"MM_UL1", NULL, "AUDIO_REF_EC_UL1 MUX"},
+ {"MM_UL2", NULL, "AUDIO_REF_EC_UL2 MUX"},
+ {"MM_UL3", NULL, "AUDIO_REF_EC_UL3 MUX"},
+ {"MM_UL4", NULL, "AUDIO_REF_EC_UL4 MUX"},
+ {"MM_UL5", NULL, "AUDIO_REF_EC_UL5 MUX"},
+ {"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"},
+ {"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"},
+ {"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"},
+ {"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"},
+ {"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"},
+ {"MM_UL19", NULL, "AUDIO_REF_EC_UL19 MUX"},
+
+ {"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+ {"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
+ {"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
+ {"Voice_Tx Mixer", "TERT_MI2S_TX_Voice", "TERT_MI2S_TX"},
+ {"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
+ {"Voice_Tx Mixer", "SLIM_7_TX_Voice", "SLIMBUS_7_TX"},
+ {"Voice_Tx Mixer", "SLIM_8_TX_Voice", "SLIMBUS_8_TX"},
+ {"Voice_Tx Mixer", "USB_AUDIO_TX_Voice", "USB_AUDIO_TX"},
+ {"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
+ {"Voice_Tx Mixer", "AFE_PCM_TX_Voice", "PCM_TX"},
+ {"Voice_Tx Mixer", "AUX_PCM_TX_Voice", "AUX_PCM_TX"},
+ {"Voice_Tx Mixer", "SEC_AUX_PCM_TX_Voice", "SEC_AUX_PCM_TX"},
+ {"Voice_Tx Mixer", "TERT_AUX_PCM_TX_Voice", "TERT_AUX_PCM_TX"},
+ {"Voice_Tx Mixer", "QUAT_AUX_PCM_TX_Voice", "QUAT_AUX_PCM_TX"},
+ {"Voice_Tx Mixer", "SEC_MI2S_TX_Voice", "SEC_MI2S_TX"},
+ {"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
+
+ {"Voice2_Tx Mixer", "PRI_TX_Voice2", "PRI_I2S_TX"},
+ {"Voice2_Tx Mixer", "PRI_MI2S_TX_Voice2", "PRI_MI2S_TX"},
+ {"Voice2_Tx Mixer", "MI2S_TX_Voice2", "MI2S_TX"},
+ {"Voice2_Tx Mixer", "TERT_MI2S_TX_Voice2", "TERT_MI2S_TX"},
+ {"Voice2_Tx Mixer", "SLIM_0_TX_Voice2", "SLIMBUS_0_TX"},
+ {"Voice2_Tx Mixer", "SLIM_7_TX_Voice2", "SLIMBUS_7_TX"},
+ {"Voice2_Tx Mixer", "SLIM_8_TX_Voice2", "SLIMBUS_8_TX"},
+ {"Voice2_Tx Mixer", "USB_AUDIO_TX_Voice2", "USB_AUDIO_TX"},
+ {"Voice2_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice2", "INT_BT_SCO_TX"},
+ {"Voice2_Tx Mixer", "AFE_PCM_TX_Voice2", "PCM_TX"},
+ {"Voice2_Tx Mixer", "AUX_PCM_TX_Voice2", "AUX_PCM_TX"},
+ {"Voice2_Tx Mixer", "SEC_AUX_PCM_TX_Voice2", "SEC_AUX_PCM_TX"},
+ {"Voice2_Tx Mixer", "TERT_AUX_PCM_TX_Voice2", "TERT_AUX_PCM_TX"},
+ {"Voice2_Tx Mixer", "QUAT_AUX_PCM_TX_Voice2", "QUAT_AUX_PCM_TX"},
+ {"VOICE2_UL", NULL, "Voice2_Tx Mixer"},
+
+ {"VoLTE_Tx Mixer", "PRI_TX_VoLTE", "PRI_I2S_TX"},
+ {"VoLTE_Tx Mixer", "SLIM_0_TX_VoLTE", "SLIMBUS_0_TX"},
+ {"VoLTE_Tx Mixer", "SLIM_7_TX_VoLTE", "SLIMBUS_7_TX"},
+ {"VoLTE_Tx Mixer", "SLIM_8_TX_VoLTE", "SLIMBUS_8_TX"},
+ {"VoLTE_Tx Mixer", "USB_AUDIO_TX_VoLTE", "USB_AUDIO_TX"},
+ {"VoLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_VoLTE", "INT_BT_SCO_TX"},
+ {"VoLTE_Tx Mixer", "AFE_PCM_TX_VoLTE", "PCM_TX"},
+ {"VoLTE_Tx Mixer", "AUX_PCM_TX_VoLTE", "AUX_PCM_TX"},
+ {"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
+ {"VoLTE_Tx Mixer", "TERT_AUX_PCM_TX_VoLTE", "TERT_AUX_PCM_TX"},
+ {"VoLTE_Tx Mixer", "QUAT_AUX_PCM_TX_VoLTE", "QUAT_AUX_PCM_TX"},
+ {"VoLTE_Tx Mixer", "MI2S_TX_VoLTE", "MI2S_TX"},
+ {"VoLTE_Tx Mixer", "PRI_MI2S_TX_VoLTE", "PRI_MI2S_TX"},
+ {"VoLTE_Tx Mixer", "TERT_MI2S_TX_VoLTE", "TERT_MI2S_TX"},
+ {"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
+
+ {"VoWLAN_Tx Mixer", "PRI_TX_VoWLAN", "PRI_I2S_TX"},
+ {"VoWLAN_Tx Mixer", "SLIM_0_TX_VoWLAN", "SLIMBUS_0_TX"},
+ {"VoWLAN_Tx Mixer", "SLIM_7_TX_VoWLAN", "SLIMBUS_7_TX"},
+ {"VoWLAN_Tx Mixer", "SLIM_8_TX_VoWLAN", "SLIMBUS_8_TX"},
+ {"VoWLAN_Tx Mixer", "USB_AUDIO_TX_VoWLAN", "USB_AUDIO_TX"},
+ {"VoWLAN_Tx Mixer", "INTERNAL_BT_SCO_TX_VoWLAN", "INT_BT_SCO_TX"},
+ {"VoWLAN_Tx Mixer", "AFE_PCM_TX_VoWLAN", "PCM_TX"},
+ {"VoWLAN_Tx Mixer", "AUX_PCM_TX_VoWLAN", "AUX_PCM_TX"},
+ {"VoWLAN_Tx Mixer", "SEC_AUX_PCM_TX_VoWLAN", "SEC_AUX_PCM_TX"},
+ {"VoWLAN_Tx Mixer", "TERT_AUX_PCM_TX_VoWLAN", "TERT_AUX_PCM_TX"},
+ {"VoWLAN_Tx Mixer", "QUAT_AUX_PCM_TX_VoWLAN", "QUAT_AUX_PCM_TX"},
+ {"VoWLAN_Tx Mixer", "MI2S_TX_VoWLAN", "MI2S_TX"},
+ {"VoWLAN_Tx Mixer", "PRI_MI2S_TX_VoWLAN", "PRI_MI2S_TX"},
+ {"VoWLAN_Tx Mixer", "TERT_MI2S_TX_VoWLAN", "TERT_MI2S_TX"},
+ {"VoWLAN_UL", NULL, "VoWLAN_Tx Mixer"},
+
+ {"VoiceMMode1_Tx Mixer", "PRI_TX_MMode1", "PRI_I2S_TX"},
+ {"VoiceMMode1_Tx Mixer", "PRI_MI2S_TX_MMode1", "PRI_MI2S_TX"},
+ {"VoiceMMode1_Tx Mixer", "MI2S_TX_MMode1", "MI2S_TX"},
+ {"VoiceMMode1_Tx Mixer", "TERT_MI2S_TX_MMode1", "TERT_MI2S_TX"},
+ {"VoiceMMode1_Tx Mixer", "INT3_MI2S_TX_MMode1", "INT3_MI2S_TX"},
+ {"VoiceMMode1_Tx Mixer", "SLIM_0_TX_MMode1", "SLIMBUS_0_TX"},
+ {"VoiceMMode1_Tx Mixer", "SLIM_7_TX_MMode1", "SLIMBUS_7_TX"},
+ {"VoiceMMode1_Tx Mixer", "SLIM_8_TX_MMode1", "SLIMBUS_8_TX"},
+ {"VoiceMMode1_Tx Mixer", "USB_AUDIO_TX_MMode1", "USB_AUDIO_TX"},
+ {"VoiceMMode1_Tx Mixer", "INT_BT_SCO_TX_MMode1", "INT_BT_SCO_TX"},
+ {"VoiceMMode1_Tx Mixer", "AFE_PCM_TX_MMode1", "PCM_TX"},
+ {"VoiceMMode1_Tx Mixer", "AUX_PCM_TX_MMode1", "AUX_PCM_TX"},
+ {"VoiceMMode1_Tx Mixer", "SEC_AUX_PCM_TX_MMode1", "SEC_AUX_PCM_TX"},
+ {"VoiceMMode1_Tx Mixer", "TERT_AUX_PCM_TX_MMode1", "TERT_AUX_PCM_TX"},
+ {"VoiceMMode1_Tx Mixer", "QUAT_AUX_PCM_TX_MMode1", "QUAT_AUX_PCM_TX"},
+ {"VOICEMMODE1_UL", NULL, "VoiceMMode1_Tx Mixer"},
+
+ {"VoiceMMode2_Tx Mixer", "PRI_TX_MMode2", "PRI_I2S_TX"},
+ {"VoiceMMode2_Tx Mixer", "PRI_MI2S_TX_MMode2", "PRI_MI2S_TX"},
+ {"VoiceMMode2_Tx Mixer", "MI2S_TX_MMode2", "MI2S_TX"},
+ {"VoiceMMode2_Tx Mixer", "TERT_MI2S_TX_MMode2", "TERT_MI2S_TX"},
+ {"VoiceMMode2_Tx Mixer", "INT3_MI2S_TX_MMode2", "INT3_MI2S_TX"},
+ {"VoiceMMode2_Tx Mixer", "SLIM_0_TX_MMode2", "SLIMBUS_0_TX"},
+ {"VoiceMMode2_Tx Mixer", "SLIM_7_TX_MMode2", "SLIMBUS_7_TX"},
+ {"VoiceMMode2_Tx Mixer", "SLIM_8_TX_MMode2", "SLIMBUS_8_TX"},
+ {"VoiceMMode2_Tx Mixer", "USB_AUDIO_TX_MMode2", "USB_AUDIO_TX"},
+ {"VoiceMMode2_Tx Mixer", "INT_BT_SCO_TX_MMode2", "INT_BT_SCO_TX"},
+ {"VoiceMMode2_Tx Mixer", "AFE_PCM_TX_MMode2", "PCM_TX"},
+ {"VoiceMMode2_Tx Mixer", "AUX_PCM_TX_MMode2", "AUX_PCM_TX"},
+ {"VoiceMMode2_Tx Mixer", "SEC_AUX_PCM_TX_MMode2", "SEC_AUX_PCM_TX"},
+ {"VoiceMMode2_Tx Mixer", "TERT_AUX_PCM_TX_MMode2", "TERT_AUX_PCM_TX"},
+ {"VoiceMMode2_Tx Mixer", "QUAT_AUX_PCM_TX_MMode2", "QUAT_AUX_PCM_TX"},
+ {"VOICEMMODE2_UL", NULL, "VoiceMMode2_Tx Mixer"},
+
+ {"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
+ {"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
+ {"Voip_Tx Mixer", "TERT_MI2S_TX_Voip", "TERT_MI2S_TX"},
+ {"Voip_Tx Mixer", "INT3_MI2S_TX_Voip", "INT3_MI2S_TX"},
+ {"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
+ {"Voip_Tx Mixer", "SLIM_7_TX_Voip", "SLIMBUS_7_TX"},
+ {"Voip_Tx Mixer", "SLIM_8_TX_Voip", "SLIMBUS_8_TX"},
+ {"Voip_Tx Mixer", "USB_AUDIO_TX_Voip", "USB_AUDIO_TX"},
+ {"Voip_Tx Mixer", "INTERNAL_BT_SCO_TX_Voip", "INT_BT_SCO_TX"},
+ {"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
+ {"Voip_Tx Mixer", "AUX_PCM_TX_Voip", "AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "SEC_AUX_PCM_TX_Voip", "SEC_AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "TERT_AUX_PCM_TX_Voip", "TERT_AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "QUAT_AUX_PCM_TX_Voip", "QUAT_AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "PRI_MI2S_TX_Voip", "PRI_MI2S_TX"},
+ {"VOIP_UL", NULL, "Voip_Tx Mixer"},
+
+ {"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
+ {"SLIMBUS_0_RX", NULL, "SLIMBUS_DL_HL"},
+ {"SLIMBUS1_DL_HL", "Switch", "SLIM1_DL_HL"},
+ {"SLIMBUS_1_RX", NULL, "SLIMBUS1_DL_HL"},
+ {"SLIMBUS3_DL_HL", "Switch", "SLIM3_DL_HL"},
+ {"SLIMBUS_3_RX", NULL, "SLIMBUS3_DL_HL"},
+ {"SLIMBUS4_DL_HL", "Switch", "SLIM4_DL_HL"},
+ {"SLIMBUS_4_RX", NULL, "SLIMBUS4_DL_HL"},
+ {"SLIMBUS6_DL_HL", "Switch", "SLIM0_DL_HL"},
+ {"SLIMBUS_6_RX", NULL, "SLIMBUS6_DL_HL"},
+ {"SLIM0_UL_HL", NULL, "SLIMBUS_0_TX"},
+ {"SLIM1_UL_HL", NULL, "SLIMBUS_1_TX"},
+ {"SLIM3_UL_HL", NULL, "SLIMBUS_3_TX"},
+ {"SLIM4_UL_HL", NULL, "SLIMBUS_4_TX"},
+ {"SLIM8_UL_HL", NULL, "SLIMBUS_8_TX"},
+
+ {"LSM1 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM1 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM1 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM1 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM1 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM1_UL_HL", NULL, "LSM1 MUX"},
+
+ {"LSM2 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM2 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM2 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM2 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM2 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM2 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM2_UL_HL", NULL, "LSM2 MUX"},
+
+
+ {"LSM3 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM3 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM3 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM3 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM3 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM3 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM3_UL_HL", NULL, "LSM3 MUX"},
+
+
+ {"LSM4 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM4 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM4 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM4 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM4 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM4 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM4_UL_HL", NULL, "LSM4 MUX"},
+
+ {"LSM5 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM5 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM5 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM5 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM5 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM5 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM5_UL_HL", NULL, "LSM5 MUX"},
+
+ {"LSM6 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM6 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM6 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM6 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM6 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM6_UL_HL", NULL, "LSM6 MUX"},
+
+
+ {"LSM7 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM7 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM7 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM7 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM7 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM7_UL_HL", NULL, "LSM7 MUX"},
+
+
+ {"LSM8 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM8 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM8 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM8 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM8 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM8_UL_HL", NULL, "LSM8 MUX"},
+
+
+ {"CPE_LSM_UL_HL", NULL, "BE_IN"},
+ {"QCHAT_Tx Mixer", "PRI_TX_QCHAT", "PRI_I2S_TX"},
+ {"QCHAT_Tx Mixer", "SLIM_0_TX_QCHAT", "SLIMBUS_0_TX"},
+ {"QCHAT_Tx Mixer", "SLIM_7_TX_QCHAT", "SLIMBUS_7_TX"},
+ {"QCHAT_Tx Mixer", "SLIM_8_TX_QCHAT", "SLIMBUS_8_TX"},
+ {"QCHAT_Tx Mixer", "INTERNAL_BT_SCO_TX_QCHAT", "INT_BT_SCO_TX"},
+ {"QCHAT_Tx Mixer", "AFE_PCM_TX_QCHAT", "PCM_TX"},
+ {"QCHAT_Tx Mixer", "AUX_PCM_TX_QCHAT", "AUX_PCM_TX"},
+ {"QCHAT_Tx Mixer", "SEC_AUX_PCM_TX_QCHAT", "SEC_AUX_PCM_TX"},
+ {"QCHAT_Tx Mixer", "TERT_AUX_PCM_TX_QCHAT", "TERT_AUX_PCM_TX"},
+ {"QCHAT_Tx Mixer", "QUAT_AUX_PCM_TX_QCHAT", "QUAT_AUX_PCM_TX"},
+ {"QCHAT_Tx Mixer", "MI2S_TX_QCHAT", "MI2S_TX"},
+ {"QCHAT_Tx Mixer", "PRI_MI2S_TX_QCHAT", "PRI_MI2S_TX"},
+ {"QCHAT_Tx Mixer", "TERT_MI2S_TX_QCHAT", "TERT_MI2S_TX"},
+ {"QCHAT_Tx Mixer", "INT3_MI2S_TX_QCHAT", "INT3_MI2S_TX"},
+ {"QCHAT_Tx Mixer", "USB_AUDIO_TX_QCHAT", "USB_AUDIO_TX"},
+ {"QCHAT_UL", NULL, "QCHAT_Tx Mixer"},
+
+ {"INT_FM_RX", NULL, "INTFM_DL_HL"},
+ {"INTFM_UL_HL", NULL, "INT_FM_TX"},
+ {"INTHFP_UL_HL", NULL, "HFP_PRI_AUX_UL_HL"},
+ {"HFP_PRI_AUX_UL_HL", "Switch", "AUX_PCM_TX"},
+ {"INTHFP_UL_HL", NULL, "HFP_AUX_UL_HL"},
+ {"HFP_AUX_UL_HL", "Switch", "SEC_AUX_PCM_TX"},
+ {"INTHFP_UL_HL", NULL, "HFP_INT_UL_HL"},
+ {"HFP_INT_UL_HL", "Switch", "INT_BT_SCO_TX"},
+ {"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
+ {"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
+ {"MI2S_RX", NULL, "MI2S_DL_HL"},
+ {"MI2S_UL_HL", NULL, "MI2S_TX"},
+ {"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
+ {"PCM_RX", NULL, "PCM_RX_DL_HL"},
+ {"INT0_MI2S_RX_DL_HL", "Switch", "INT0_MI2S_DL_HL"},
+ {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX_DL_HL"},
+ {"INT4_MI2S_RX_DL_HL", "Switch", "INT4_MI2S_DL_HL"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_DL_HL"},
+ {"PRI_MI2S_RX_DL_HL", "Switch", "PRI_MI2S_DL_HL"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_DL_HL"},
+ {"SEC_MI2S_RX_DL_HL", "Switch", "SEC_MI2S_DL_HL"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_DL_HL"},
+ {"TERT_MI2S_RX_DL_HL", "Switch", "TERT_MI2S_DL_HL"},
+ {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX_DL_HL"},
+
+ {"QUAT_MI2S_RX_DL_HL", "Switch", "QUAT_MI2S_DL_HL"},
+ {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX_DL_HL"},
+ {"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
+ {"TERT_MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
+ {"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
+ {"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_DL_HL"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_DL_HL"},
+ {"TERT_MI2S_RX", NULL, "TERT_MI2S_DL_HL"},
+ {"QUAT_MI2S_UL_HL", NULL, "QUAT_MI2S_TX"},
+
+ {"PRI_TDM_TX_0_UL_HL", NULL, "PRI_TDM_TX_0"},
+ {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0_DL_HL"},
+ {"SEC_TDM_TX_0_UL_HL", NULL, "SEC_TDM_TX_0"},
+ {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0_DL_HL"},
+ {"TERT_TDM_TX_0_UL_HL", NULL, "TERT_TDM_TX_0"},
+ {"TERT_TDM_TX_1_UL_HL", NULL, "TERT_TDM_TX_1"},
+ {"TERT_TDM_TX_2_UL_HL", NULL, "TERT_TDM_TX_2"},
+ {"TERT_TDM_TX_3_UL_HL", NULL, "TERT_TDM_TX_3"},
+ {"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0_DL_HL"},
+ {"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_0_DL_HL"},
+ {"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_0_DL_HL"},
+ {"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_0_DL_HL"},
+ {"QUAT_TDM_TX_0_UL_HL", NULL, "QUAT_TDM_TX_0"},
+ {"QUAT_TDM_TX_1_UL_HL", NULL, "QUAT_TDM_TX_1"},
+ {"QUAT_TDM_TX_2_UL_HL", NULL, "QUAT_TDM_TX_2"},
+ {"QUAT_TDM_TX_3_UL_HL", NULL, "QUAT_TDM_TX_3"},
+ {"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0_DL_HL"},
+ {"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1_DL_HL"},
+ {"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_DL_HL"},
+ {"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3_DL_HL"},
+
+ {"TERT_TDM_RX_0 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"TERT_TDM_RX_0 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"TERT_TDM_RX_0 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"TERT_TDM_RX_0 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"TERT_TDM_RX_0 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"TERT_TDM_RX_0 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"TERT_TDM_RX_0 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"TERT_TDM_RX_0 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"TERT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"TERT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"TERT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"TERT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"TERT_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"TERT_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"TERT_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"TERT_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0 Port Mixer"},
+
+ {"TERT_TDM_RX_1 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"TERT_TDM_RX_1 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"TERT_TDM_RX_1 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"TERT_TDM_RX_1 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"TERT_TDM_RX_1 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"TERT_TDM_RX_1 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"TERT_TDM_RX_1 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"TERT_TDM_RX_1 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"TERT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"TERT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"TERT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"TERT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"TERT_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"TERT_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"TERT_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"TERT_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1 Port Mixer"},
+
+ {"TERT_TDM_RX_2 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"TERT_TDM_RX_2 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"TERT_TDM_RX_2 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"TERT_TDM_RX_2 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"TERT_TDM_RX_2 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"TERT_TDM_RX_2 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"TERT_TDM_RX_2 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"TERT_TDM_RX_2 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"TERT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"TERT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"TERT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"TERT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"TERT_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"TERT_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"TERT_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"TERT_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2 Port Mixer"},
+
+ {"TERT_TDM_RX_3 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"TERT_TDM_RX_3 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"TERT_TDM_RX_3 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"TERT_TDM_RX_3 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"TERT_TDM_RX_3 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"TERT_TDM_RX_3 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"TERT_TDM_RX_3 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"TERT_TDM_RX_3 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"TERT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"TERT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"TERT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"TERT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"TERT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"TERT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"TERT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"TERT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Port Mixer"},
+
+ {"QUAT_TDM_RX_0 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"QUAT_TDM_RX_0 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"QUAT_TDM_RX_0 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"QUAT_TDM_RX_0 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"QUAT_TDM_RX_0 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"QUAT_TDM_RX_0 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"QUAT_TDM_RX_0 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"QUAT_TDM_RX_0 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"QUAT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"QUAT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"QUAT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"QUAT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"QUAT_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"QUAT_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"QUAT_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"QUAT_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Port Mixer"},
+
+ {"QUAT_TDM_RX_1 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"QUAT_TDM_RX_1 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"QUAT_TDM_RX_1 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"QUAT_TDM_RX_1 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"QUAT_TDM_RX_1 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"QUAT_TDM_RX_1 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"QUAT_TDM_RX_1 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"QUAT_TDM_RX_1 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"QUAT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"QUAT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"QUAT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"QUAT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"QUAT_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"QUAT_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"QUAT_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"QUAT_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1 Port Mixer"},
+
+ {"QUAT_TDM_RX_2 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"QUAT_TDM_RX_2 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"QUAT_TDM_RX_2 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"QUAT_TDM_RX_2 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"QUAT_TDM_RX_2 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"QUAT_TDM_RX_2 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"QUAT_TDM_RX_2 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"QUAT_TDM_RX_2 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"QUAT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"QUAT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"QUAT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"QUAT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"QUAT_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"QUAT_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"QUAT_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"QUAT_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2 Port Mixer"},
+
+ {"QUAT_TDM_RX_3 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"QUAT_TDM_RX_3 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"QUAT_TDM_RX_3 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"QUAT_TDM_RX_3 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"QUAT_TDM_RX_3 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"QUAT_TDM_RX_3 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"QUAT_TDM_RX_3 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"QUAT_TDM_RX_3 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"QUAT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"QUAT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"QUAT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"QUAT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"QUAT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"QUAT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"QUAT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"QUAT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Port Mixer"},
+
+ {"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
+ {"AFE_PCM_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"AFE_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"},
+
+ {"AUX_PCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"AUX_PCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"AUX_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"AUX_PCM_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"AUX_PCM_RX", NULL, "AUX_PCM_RX Port Mixer"},
+
+ {"SEC_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SEC_AUXPCM_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"SEC_AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"SEC_AUX_PCM_RX", NULL, "SEC_AUXPCM_RX Port Mixer"},
+
+ {"TERT_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"TERT_AUXPCM_RX Port Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"},
+ {"TERT_AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"TERT_AUX_PCM_RX", NULL, "TERT_AUXPCM_RX Port Mixer"},
+
+ {"QUAT_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"QUAT_AUXPCM_RX Port Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"},
+ {"QUAT_AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"QUAT_AUX_PCM_RX", NULL, "QUAT_AUXPCM_RX Port Mixer"},
+
+ {"Voice Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+ {"Voice Stub Tx Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"Voice Stub Tx Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"Voice Stub Tx Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"},
+ {"Voice Stub Tx Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"},
+ {"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
+ {"Voice Stub Tx Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"Voice Stub Tx Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"Voice Stub Tx Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"Voice Stub Tx Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"Voice Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
+
+ {"VoLTE Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
+ {"VoLTE Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"VoLTE Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+ {"VoLTE Stub Tx Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"VoLTE Stub Tx Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"VoLTE Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
+ {"VoLTE Stub Tx Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"VoLTE Stub Tx Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"VoLTE Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"VoLTE Stub Tx Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"VoLTE Stub Tx Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"VOLTE_STUB_UL", NULL, "VoLTE Stub Tx Mixer"},
+
+ {"Voice2 Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
+ {"Voice2 Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"Voice2 Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+ {"Voice2 Stub Tx Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"Voice2 Stub Tx Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"Voice2 Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
+ {"Voice2 Stub Tx Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"Voice2 Stub Tx Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"Voice2 Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"Voice2 Stub Tx Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"Voice2 Stub Tx Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"VOICE2_STUB_UL", NULL, "Voice2 Stub Tx Mixer"},
+
+ {"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"STUB_RX Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"STUB_RX Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"STUB_RX", NULL, "STUB_RX Mixer"},
+ {"SLIMBUS_1_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIMBUS_1_RX Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"SLIMBUS_1_RX Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
+ {"AFE_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIMBUS_3_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"SLIMBUS_3_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
+
+ {"SLIM_7_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SLIM_7_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SLIM_7_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SLIM_7_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"SLIM_7_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SLIM_7_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SLIM_7_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIM_7_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"SLIM_7_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIM_7_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"SLIM_7_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"SLIM_7_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"SLIMBUS_7_RX", NULL, "SLIM_7_RX_Voice Mixer"},
+
+ {"SLIM_8_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SLIM_8_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SLIM_8_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SLIM_8_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+ {"SLIM_8_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SLIM_8_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SLIM_8_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIM_8_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+ {"SLIM_8_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIM_8_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"SLIM_8_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"SLIM_8_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"SLIMBUS_8_RX", NULL, "SLIM_8_RX_Voice Mixer"},
+
+ {"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"SLIMBUS_1_RX Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"SLIMBUS_1_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
+ {"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
+ {"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
+ {"SLIMBUS_3_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"SLIMBUS_3_RX Port Mixer", "AFE_PCM_RX", "PCM_RX"},
+ {"SLIMBUS_3_RX Port Mixer", "AUX_PCM_RX", "AUX_PCM_RX"},
+ {"SLIMBUS_3_RX Port Mixer", "SLIM_0_RX", "SLIMBUS_0_RX"},
+ {"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX Port Mixer"},
+
+ {"SLIMBUS_6_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"SLIMBUS_6_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Port Mixer"},
+
+ {"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"HDMI", NULL, "HDMI_RX Port Mixer"},
+
+ {"DISPLAY_PORT_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"DISPLAY_PORT", NULL, "DISPLAY_PORT_RX Port Mixer"},
+
+ {"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"SEC_I2S_RX", NULL, "SEC_I2S_RX Port Mixer"},
+
+ {"MI2S_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"MI2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MI2S_RX", NULL, "MI2S_RX Port Mixer"},
+
+ {"PRI_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"PRI_MI2S_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"PRI_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"PRI_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"PRI_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"PRI_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"PRI_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Port Mixer"},
+
+ {"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SEC_MI2S_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"SEC_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"SEC_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"SEC_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Port Mixer"},
+
+ {"TERT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"TERT_MI2S_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"TERT_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"TERT_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"TERT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Port Mixer"},
+
+ {"QUAT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"QUAT_MI2S_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"QUAT_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"QUAT_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"QUAT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"QUAT_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"QUAT_MI2S_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Port Mixer"},
+
+ /* Backend Enablement */
+
+ {"BE_OUT", NULL, "PRI_I2S_RX"},
+ {"BE_OUT", NULL, "SEC_I2S_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_0_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_1_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_2_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_3_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_4_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_5_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_6_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_7_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_8_RX"},
+ {"BE_OUT", NULL, "USB_AUDIO_RX"},
+ {"BE_OUT", NULL, "HDMI"},
+ {"BE_OUT", NULL, "DISPLAY_PORT"},
+ {"BE_OUT", NULL, "SPDIF_RX"},
+ {"BE_OUT", NULL, "MI2S_RX"},
+ {"BE_OUT", NULL, "QUAT_MI2S_RX"},
+ {"BE_OUT", NULL, "QUIN_MI2S_RX"},
+ {"BE_OUT", NULL, "TERT_MI2S_RX"},
+ {"BE_OUT", NULL, "SEC_MI2S_RX"},
+ {"BE_OUT", NULL, "SEC_MI2S_RX_SD1"},
+ {"BE_OUT", NULL, "PRI_MI2S_RX"},
+ {"BE_OUT", NULL, "INT0_MI2S_RX"},
+ {"BE_OUT", NULL, "INT4_MI2S_RX"},
+ {"BE_OUT", NULL, "INT_BT_SCO_RX"},
+ {"BE_OUT", NULL, "INT_BT_A2DP_RX"},
+ {"BE_OUT", NULL, "INT_FM_RX"},
+ {"BE_OUT", NULL, "PCM_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_3_RX"},
+ {"BE_OUT", NULL, "AUX_PCM_RX"},
+ {"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
+ {"BE_OUT", NULL, "TERT_AUX_PCM_RX"},
+ {"BE_OUT", NULL, "QUAT_AUX_PCM_RX"},
+ {"BE_OUT", NULL, "INT_BT_SCO_RX"},
+ {"BE_OUT", NULL, "INT_FM_RX"},
+ {"BE_OUT", NULL, "PCM_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_3_RX"},
+ {"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
+ {"BE_OUT", NULL, "VOICE2_PLAYBACK_TX"},
+ {"BE_OUT", NULL, "PRI_TDM_RX_0"},
+ {"BE_OUT", NULL, "SEC_TDM_RX_0"},
+ {"BE_OUT", NULL, "TERT_TDM_RX_0"},
+ {"BE_OUT", NULL, "TERT_TDM_RX_1"},
+ {"BE_OUT", NULL, "TERT_TDM_RX_2"},
+ {"BE_OUT", NULL, "TERT_TDM_RX_3"},
+ {"BE_OUT", NULL, "QUAT_TDM_RX_0"},
+ {"BE_OUT", NULL, "QUAT_TDM_RX_1"},
+ {"BE_OUT", NULL, "QUAT_TDM_RX_2"},
+ {"BE_OUT", NULL, "QUAT_TDM_RX_3"},
+
+ {"PRI_I2S_TX", NULL, "BE_IN"},
+ {"MI2S_TX", NULL, "BE_IN"},
+ {"QUAT_MI2S_TX", NULL, "BE_IN"},
+ {"QUIN_MI2S_TX", NULL, "BE_IN"},
+ {"PRI_MI2S_TX", NULL, "BE_IN"},
+ {"TERT_MI2S_TX", NULL, "BE_IN"},
+ {"INT2_MI2S_TX", NULL, "BE_IN"},
+ {"INT3_MI2S_TX", NULL, "BE_IN"},
+ {"SEC_MI2S_TX", NULL, "BE_IN"},
+ {"SENARY_MI2S_TX", NULL, "BE_IN" },
+ {"SLIMBUS_0_TX", NULL, "BE_IN" },
+ {"SLIMBUS_1_TX", NULL, "BE_IN" },
+ {"SLIMBUS_3_TX", NULL, "BE_IN" },
+ {"SLIMBUS_4_TX", NULL, "BE_IN" },
+ {"SLIMBUS_5_TX", NULL, "BE_IN" },
+ {"SLIMBUS_6_TX", NULL, "BE_IN" },
+ {"SLIMBUS_7_TX", NULL, "BE_IN" },
+ {"SLIMBUS_8_TX", NULL, "BE_IN" },
+ {"USB_AUDIO_TX", NULL, "BE_IN" },
+ {"INT_BT_SCO_TX", NULL, "BE_IN"},
+ {"INT_FM_TX", NULL, "BE_IN"},
+ {"PCM_TX", NULL, "BE_IN"},
+ {"BE_OUT", NULL, "SLIMBUS_3_RX"},
+ {"BE_OUT", NULL, "STUB_RX"},
+ {"STUB_TX", NULL, "BE_IN"},
+ {"STUB_1_TX", NULL, "BE_IN"},
+ {"BE_OUT", NULL, "AUX_PCM_RX"},
+ {"AUX_PCM_TX", NULL, "BE_IN"},
+ {"SEC_AUX_PCM_TX", NULL, "BE_IN"},
+ {"TERT_AUX_PCM_TX", NULL, "BE_IN"},
+ {"QUAT_AUX_PCM_TX", NULL, "BE_IN"},
+ {"INCALL_RECORD_TX", NULL, "BE_IN"},
+ {"INCALL_RECORD_RX", NULL, "BE_IN"},
+ {"SLIM0_RX_VI_FB_LCH_MUX", "SLIM4_TX", "SLIMBUS_4_TX"},
+ {"SLIM0_RX_VI_FB_RCH_MUX", "SLIM4_TX", "SLIMBUS_4_TX"},
+ {"PRI_MI2S_RX_VI_FB_MUX", "SENARY_TX", "SENARY_TX"},
+ {"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_LCH_MUX"},
+ {"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_RCH_MUX"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_VI_FB_MUX"},
+ {"PRI_TDM_TX_0", NULL, "BE_IN"},
+ {"SEC_TDM_TX_0", NULL, "BE_IN"},
+ {"TERT_TDM_TX_0", NULL, "BE_IN"},
+ {"TERT_TDM_TX_1", NULL, "BE_IN"},
+ {"TERT_TDM_TX_2", NULL, "BE_IN"},
+ {"TERT_TDM_TX_3", NULL, "BE_IN"},
+ {"QUAT_TDM_TX_0", NULL, "BE_IN"},
+ {"QUAT_TDM_TX_1", NULL, "BE_IN"},
+ {"QUAT_TDM_TX_2", NULL, "BE_IN"},
+ {"QUAT_TDM_TX_3", NULL, "BE_IN"},
+};
+
+static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int be_id = rtd->dai_link->be_id;
+
+ if (be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&routing_lock);
+ msm_bedais[be_id].sample_rate = params_rate(params);
+ msm_bedais[be_id].channel = params_channels(params);
+ msm_bedais[be_id].format = params_format(params);
+ pr_debug("%s: BE Sample Rate (%d) format (%d) be_id %d\n",
+ __func__, msm_bedais[be_id].sample_rate,
+ msm_bedais[be_id].format, be_id);
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static int msm_pcm_routing_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int be_id = rtd->dai_link->be_id;
+ int i, session_type, path_type, topology;
+ struct msm_pcm_routing_bdai_data *bedai;
+ struct msm_pcm_routing_fdai_data *fdai;
+
+ pr_debug("%s: substream->pcm->id:%s\n",
+ __func__, substream->pcm->id);
+
+ if (be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+ return -EINVAL;
+ }
+
+ bedai = &msm_bedais[be_id];
+ session_type = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ 0 : 1);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ path_type = ADM_PATH_PLAYBACK;
+ else
+ path_type = ADM_PATH_LIVE_REC;
+
+ mutex_lock(&routing_lock);
+ for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+ fdai = &fe_dai_map[i][session_type];
+ if (fdai->strm_id != INVALID_SESSION) {
+ int idx;
+ int port_id;
+ unsigned long copp =
+ session_copp_map[i][session_type][be_id];
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++)
+ if (test_bit(idx, &copp))
+ break;
+ fdai->be_srate = bedai->sample_rate;
+ port_id = bedai->port_id;
+ topology = adm_get_topology_for_port_copp_idx(port_id,
+ idx);
+ adm_close(bedai->port_id, fdai->perf_mode, idx);
+ pr_debug("%s: copp:%ld,idx bit fe:%d, type:%d,be:%d topology=0x%x\n",
+ __func__, copp, i, session_type, be_id,
+ topology);
+ clear_bit(idx,
+ &session_copp_map[i][session_type][be_id]);
+ if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
+ (bedai->compr_passthr_mode == LEGACY_PCM))
+ msm_pcm_routing_deinit_pp(bedai->port_id,
+ topology);
+ }
+ }
+
+ bedai->compr_passthr_mode = LEGACY_PCM;
+ bedai->active = 0;
+ bedai->sample_rate = 0;
+ bedai->channel = 0;
+ mutex_unlock(&routing_lock);
+
+ return 0;
+}
+
+static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int be_id = rtd->dai_link->be_id;
+ int i, path_type, session_type, topology;
+ struct msm_pcm_routing_bdai_data *bedai;
+ u32 channels, sample_rate;
+ uint16_t bits_per_sample = 16, voc_path_type;
+ struct msm_pcm_routing_fdai_data *fdai;
+ u32 session_id;
+
+ pr_debug("%s: substream->pcm->id:%s\n",
+ __func__, substream->pcm->id);
+
+ if (be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+ return -EINVAL;
+ }
+
+ bedai = &msm_bedais[be_id];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (bedai->compr_passthr_mode != LEGACY_PCM)
+ path_type = ADM_PATH_COMPRESSED_RX;
+ else
+ path_type = ADM_PATH_PLAYBACK;
+ session_type = SESSION_TYPE_RX;
+ } else {
+ path_type = ADM_PATH_LIVE_REC;
+ session_type = SESSION_TYPE_TX;
+ }
+
+ mutex_lock(&routing_lock);
+ if (bedai->active == 1)
+ goto done; /* Ignore prepare if back-end already active */
+
+ /* AFE port is not active at this point. However, still
+ * go ahead setting active flag under the notion that
+ * QDSP6 is able to handle ADM starting before AFE port
+ * is started.
+ */
+ bedai->active = 1;
+
+ for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+ fdai = &fe_dai_map[i][session_type];
+ if (fdai->strm_id != INVALID_SESSION) {
+ int app_type, app_type_idx, copp_idx, acdb_dev_id;
+
+ if (session_type == SESSION_TYPE_TX &&
+ fdai->be_srate &&
+ (fdai->be_srate != bedai->sample_rate)) {
+ pr_debug("%s: flush strm %d diff BE rates\n",
+ __func__,
+ fdai->strm_id);
+
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
+ bits_per_sample = msm_routing_get_bit_width(
+ bedai->format);
+
+ app_type =
+ fe_dai_app_type_cfg[i][session_type].app_type;
+ if (app_type) {
+ app_type_idx =
+ msm_pcm_routing_get_app_type_idx(app_type);
+ sample_rate =
+ fe_dai_app_type_cfg[i][session_type].
+ sample_rate;
+ bits_per_sample =
+ app_type_cfg[app_type_idx].bit_width;
+ } else
+ sample_rate = bedai->sample_rate;
+ /*
+ * check if ADM needs to be configured with different
+ * channel mapping than backend
+ */
+ if (!bedai->adm_override_ch)
+ channels = bedai->channel;
+ else
+ channels = bedai->adm_override_ch;
+ acdb_dev_id =
+ fe_dai_app_type_cfg[i][session_type].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(path_type, i,
+ session_type);
+ copp_idx = adm_open(bedai->port_id, path_type,
+ sample_rate, channels, topology,
+ fdai->perf_mode, bits_per_sample,
+ app_type, acdb_dev_id);
+ if ((copp_idx < 0) ||
+ (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: adm open failed\n", __func__);
+ mutex_unlock(&routing_lock);
+ return -EINVAL;
+ }
+ pr_debug("%s: setting idx bit of fe:%d, type: %d, be:%d\n",
+ __func__, i, session_type, be_id);
+ set_bit(copp_idx,
+ &session_copp_map[i][session_type][be_id]);
+
+ if (msm_is_resample_needed(
+ sample_rate,
+ bedai->sample_rate))
+ adm_copp_mfc_cfg(
+ bedai->port_id, copp_idx,
+ bedai->sample_rate);
+
+ msm_pcm_routing_build_matrix(i, session_type, path_type,
+ fdai->perf_mode);
+ if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
+ (bedai->compr_passthr_mode ==
+ LEGACY_PCM))
+ msm_pcm_routing_cfg_pp(bedai->port_id, copp_idx,
+ topology, channels);
+ }
+ }
+
+ for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MAX) {
+ session_id = msm_pcm_routing_get_voc_sessionid(i);
+ if (session_id) {
+ pr_debug("%s voice session_id: 0x%x",
+ __func__, session_id);
+
+ if (session_type == SESSION_TYPE_TX)
+ voc_path_type = TX_PATH;
+ else
+ voc_path_type = RX_PATH;
+
+ voc_set_route_flag(session_id, voc_path_type, 1);
+ voc_set_device_config(session_id, voc_path_type,
+ bedai->channel, bedai->port_id);
+
+ if (voc_get_route_flag(session_id, RX_PATH) &&
+ voc_get_route_flag(session_id, TX_PATH))
+ voc_enable_device(session_id);
+ }
+ }
+
+done:
+ mutex_unlock(&routing_lock);
+
+ return 0;
+}
+
+static int msm_routing_send_device_pp_params(int port_id, int copp_idx)
+{
+ int index, topo_id, be_idx;
+ unsigned long pp_config = 0;
+ bool mute_on;
+ int latency;
+
+ pr_debug("%s: port_id %d, copp_idx %d\n", __func__, port_id, copp_idx);
+
+ if (port_id != HDMI_RX && port_id != DISPLAY_PORT_RX) {
+ pr_err("%s: Device pp params on invalid port %d\n",
+ __func__, port_id);
+ return -EINVAL;
+ }
+
+ for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) {
+ if (port_id == msm_bedais[be_idx].port_id)
+ break;
+ }
+
+ if (be_idx >= MSM_BACKEND_DAI_MAX) {
+ pr_debug("%s: Invalid be id %d\n", __func__, be_idx);
+ return -EINVAL;
+ }
+
+ for (index = 0; index < MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX; index++) {
+ if (msm_bedais_pp_params[index].port_id == port_id)
+ break;
+ }
+ if (index >= MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX) {
+ pr_err("%s: Invalid backend pp params index %d\n",
+ __func__, index);
+ return -EINVAL;
+ }
+
+ topo_id = adm_get_topology_for_port_copp_idx(port_id, copp_idx);
+ if (topo_id != COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY) {
+ pr_err("%s: Invalid passthrough topology 0x%x\n",
+ __func__, topo_id);
+ return -EINVAL;
+ }
+
+ pp_config = msm_bedais_pp_params[index].pp_params_config;
+ if (test_bit(ADM_PP_PARAM_MUTE_BIT, &pp_config)) {
+ pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__);
+ clear_bit(ADM_PP_PARAM_MUTE_BIT, &pp_config);
+ mute_on = msm_bedais_pp_params[index].mute_on;
+ if ((msm_bedais[be_idx].active) &&
+ (msm_bedais[be_idx].compr_passthr_mode !=
+ LEGACY_PCM))
+ adm_send_compressed_device_mute(port_id,
+ copp_idx,
+ mute_on);
+ }
+ if (test_bit(ADM_PP_PARAM_LATENCY_BIT, &pp_config)) {
+ pr_debug("%s: ADM_PP_PARAM_LATENCY\n", __func__);
+ clear_bit(ADM_PP_PARAM_LATENCY_BIT,
+ &pp_config);
+ latency = msm_bedais_pp_params[index].latency;
+ if ((msm_bedais[be_idx].active) &&
+ (msm_bedais[be_idx].compr_passthr_mode !=
+ LEGACY_PCM))
+ adm_send_compressed_device_latency(port_id,
+ copp_idx,
+ latency);
+ }
+ return 0;
+}
+
+static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int pp_id = ucontrol->value.integer.value[0];
+ int port_id = 0;
+ int index, be_idx, i, topo_id, idx;
+ bool mute;
+ int latency;
+
+ pr_debug("%s: pp_id: 0x%x\n", __func__, pp_id);
+
+ for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) {
+ port_id = msm_bedais[be_idx].port_id;
+ if (port_id == HDMI_RX || port_id == DISPLAY_PORT_RX)
+ break;
+ }
+
+ if (be_idx >= MSM_BACKEND_DAI_MAX) {
+ pr_debug("%s: Invalid be id %d\n", __func__, be_idx);
+ return -EINVAL;
+ }
+
+ for (index = 0; index < MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX; index++) {
+ if (msm_bedais_pp_params[index].port_id == port_id)
+ break;
+ }
+ if (index >= MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX) {
+ pr_err("%s: Invalid pp params backend index %d\n",
+ __func__, index);
+ return -EINVAL;
+ }
+
+ for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions,
+ MSM_FRONTEND_DAI_MM_SIZE) {
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
+ unsigned long copp =
+ session_copp_map[i]
+ [SESSION_TYPE_RX][be_idx];
+ if (!test_bit(idx, &copp))
+ continue;
+ topo_id = adm_get_topology_for_port_copp_idx(port_id,
+ idx);
+ if (topo_id != COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY)
+ continue;
+ pr_debug("%s: port: 0x%x, copp %ld, be active: %d, passt: %d\n",
+ __func__, port_id, copp, msm_bedais[be_idx].active,
+ msm_bedais[be_idx].compr_passthr_mode);
+ switch (pp_id) {
+ case ADM_PP_PARAM_MUTE_ID:
+ pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__);
+ mute = ucontrol->value.integer.value[1] ? true : false;
+ msm_bedais_pp_params[index].mute_on = mute;
+ set_bit(ADM_PP_PARAM_MUTE_BIT,
+ &msm_bedais_pp_params[index].pp_params_config);
+ if ((msm_bedais[be_idx].active) &&
+ (msm_bedais[be_idx].compr_passthr_mode !=
+ LEGACY_PCM))
+ adm_send_compressed_device_mute(port_id,
+ idx, mute);
+ break;
+ case ADM_PP_PARAM_LATENCY_ID:
+ pr_debug("%s: ADM_PP_PARAM_LATENCY\n", __func__);
+ msm_bedais_pp_params[index].latency =
+ ucontrol->value.integer.value[1];
+ set_bit(ADM_PP_PARAM_LATENCY_BIT,
+ &msm_bedais_pp_params[index].pp_params_config);
+ latency = msm_bedais_pp_params[index].latency =
+ ucontrol->value.integer.value[1];
+ if ((msm_bedais[be_idx].active) &&
+ (msm_bedais[be_idx].compr_passthr_mode !=
+ LEGACY_PCM))
+ adm_send_compressed_device_latency(port_id,
+ idx, latency);
+ break;
+ default:
+ pr_info("%s, device pp param %d not supported\n",
+ __func__, pp_id);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int msm_routing_get_device_pp_params_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s:msm_routing_get_device_pp_params_mixer", __func__);
+ return 0;
+}
+
+static const struct snd_kcontrol_new device_pp_params_mixer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Device PP Params", SND_SOC_NOPM, 0, 0xFFFFFFFF,
+ 0, 3, msm_routing_get_device_pp_params_mixer,
+ msm_routing_put_device_pp_params_mixer),
+};
+
+static struct snd_pcm_ops msm_routing_pcm_ops = {
+ .hw_params = msm_pcm_routing_hw_params,
+ .close = msm_pcm_routing_close,
+ .prepare = msm_pcm_routing_prepare,
+};
+
+/* Not used but frame seems to require it */
+static int msm_routing_probe(struct snd_soc_platform *platform)
+{
+ snd_soc_dapm_new_controls(&platform->component.dapm, msm_qdsp6_widgets,
+ ARRAY_SIZE(msm_qdsp6_widgets));
+ snd_soc_dapm_add_routes(&platform->component.dapm, intercon,
+ ARRAY_SIZE(intercon));
+
+ snd_soc_dapm_new_widgets(platform->component.dapm.card);
+
+ snd_soc_add_platform_controls(platform, lsm_function,
+ ARRAY_SIZE(lsm_function));
+
+ snd_soc_add_platform_controls(platform, aanc_slim_0_rx_mux,
+ ARRAY_SIZE(aanc_slim_0_rx_mux));
+
+ snd_soc_add_platform_controls(platform, msm_voc_session_controls,
+ ARRAY_SIZE(msm_voc_session_controls));
+
+ snd_soc_add_platform_controls(platform, app_type_cfg_controls,
+ ARRAY_SIZE(app_type_cfg_controls));
+
+ snd_soc_add_platform_controls(platform,
+ stereo_to_custom_stereo_controls,
+ ARRAY_SIZE(stereo_to_custom_stereo_controls));
+
+ msm_qti_pp_add_controls(platform);
+
+ msm_dts_srs_tm_add_controls(platform);
+
+ msm_dolby_dap_add_controls(platform);
+
+ snd_soc_add_platform_controls(platform,
+ use_ds1_or_ds2_controls,
+ ARRAY_SIZE(use_ds1_or_ds2_controls));
+
+ snd_soc_add_platform_controls(platform,
+ device_pp_params_mixer_controls,
+ ARRAY_SIZE(device_pp_params_mixer_controls));
+
+ msm_dts_eagle_add_controls(platform);
+
+ snd_soc_add_platform_controls(platform, msm_source_tracking_controls,
+ ARRAY_SIZE(msm_source_tracking_controls));
+ snd_soc_add_platform_controls(platform, adm_channel_config_controls,
+ ARRAY_SIZE(adm_channel_config_controls));
+ return 0;
+}
+
+int msm_routing_pcm_new(struct snd_soc_pcm_runtime *runtime)
+{
+ return msm_pcm_routing_hwdep_new(runtime, msm_bedais);
+}
+
+void msm_routing_pcm_free(struct snd_pcm *pcm)
+{
+ msm_pcm_routing_hwdep_free(pcm);
+}
+
+static struct snd_soc_platform_driver msm_soc_routing_platform = {
+ .ops = &msm_routing_pcm_ops,
+ .probe = msm_routing_probe,
+ .pcm_new = msm_routing_pcm_new,
+ .pcm_free = msm_routing_pcm_free,
+};
+
+static int msm_routing_pcm_probe(struct platform_device *pdev)
+{
+
+ dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_routing_platform);
+}
+
+static int msm_routing_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_pcm_routing_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-routing"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_pcm_routing_dt_match);
+
+static struct platform_driver msm_routing_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-routing",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_routing_dt_match,
+ },
+ .probe = msm_routing_pcm_probe,
+ .remove = msm_routing_pcm_remove,
+};
+
+int msm_routing_check_backend_enabled(int fedai_id)
+{
+ int i;
+
+ if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ /* bad ID assigned in machine driver */
+ pr_err("%s: bad MM ID\n", __func__);
+ return 0;
+ }
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+ return msm_bedais[i].active;
+ }
+ return 0;
+}
+
+static int get_cal_path(int path_type)
+{
+ if (path_type == ADM_PATH_PLAYBACK ||
+ path_type == ADM_PATH_COMPRESSED_RX)
+ return RX_DEVICE;
+ else
+ return TX_DEVICE;
+}
+
+static int msm_routing_set_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ ret = cal_utils_set_cal(data_size, data, cal_data, 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static void msm_routing_delete_cal_data(void)
+{
+ pr_debug("%s\n", __func__);
+
+ cal_utils_destroy_cal_types(1, &cal_data);
+}
+
+static int msm_routing_init_cal_data(void)
+{
+ int ret = 0;
+ struct cal_type_info cal_type_info = {
+ {ADM_TOPOLOGY_CAL_TYPE,
+ {NULL, NULL, NULL,
+ msm_routing_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num}
+ };
+ pr_debug("%s\n", __func__);
+
+ ret = cal_utils_create_cal_types(1, &cal_data,
+ &cal_type_info);
+ if (ret < 0) {
+ pr_err("%s: could not create cal type!\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return ret;
+err:
+ msm_routing_delete_cal_data();
+ return ret;
+}
+
+static int __init msm_soc_routing_platform_init(void)
+{
+ mutex_init(&routing_lock);
+ if (msm_routing_init_cal_data())
+ pr_err("%s: could not init cal data!\n", __func__);
+
+ return platform_driver_register(&msm_routing_pcm_driver);
+}
+module_init(msm_soc_routing_platform_init);
+
+static void __exit msm_soc_routing_platform_exit(void)
+{
+ msm_routing_delete_cal_data();
+ platform_driver_unregister(&msm_routing_pcm_driver);
+}
+module_exit(msm_soc_routing_platform_exit);
+
+MODULE_DESCRIPTION("MSM routing platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
new file mode 100644
index 0000000..d64fd64
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -0,0 +1,472 @@
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_PCM_ROUTING_H
+#define _MSM_PCM_ROUTING_H
+#include <sound/apr_audio-v2.h>
+
+#define LPASS_BE_PRI_I2S_RX "PRIMARY_I2S_RX"
+#define LPASS_BE_PRI_I2S_TX "PRIMARY_I2S_TX"
+#define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX"
+#define LPASS_BE_SLIMBUS_0_TX "SLIMBUS_0_TX"
+#define LPASS_BE_HDMI "HDMI"
+#define LPASS_BE_DISPLAY_PORT "DISPLAY_PORT"
+#define LPASS_BE_INT_BT_SCO_RX "INT_BT_SCO_RX"
+#define LPASS_BE_INT_BT_SCO_TX "INT_BT_SCO_TX"
+#define LPASS_BE_INT_BT_A2DP_RX "INT_BT_A2DP_RX"
+#define LPASS_BE_INT_FM_RX "INT_FM_RX"
+#define LPASS_BE_INT_FM_TX "INT_FM_TX"
+#define LPASS_BE_AFE_PCM_RX "RT_PROXY_DAI_001_RX"
+#define LPASS_BE_AFE_PCM_TX "RT_PROXY_DAI_002_TX"
+#define LPASS_BE_AUXPCM_RX "AUX_PCM_RX"
+#define LPASS_BE_AUXPCM_TX "AUX_PCM_TX"
+#define LPASS_BE_SEC_AUXPCM_RX "SEC_AUX_PCM_RX"
+#define LPASS_BE_SEC_AUXPCM_TX "SEC_AUX_PCM_TX"
+#define LPASS_BE_TERT_AUXPCM_RX "TERT_AUX_PCM_RX"
+#define LPASS_BE_TERT_AUXPCM_TX "TERT_AUX_PCM_TX"
+#define LPASS_BE_QUAT_AUXPCM_RX "QUAT_AUX_PCM_RX"
+#define LPASS_BE_QUAT_AUXPCM_TX "QUAT_AUX_PCM_TX"
+#define LPASS_BE_VOICE_PLAYBACK_TX "VOICE_PLAYBACK_TX"
+#define LPASS_BE_VOICE2_PLAYBACK_TX "VOICE2_PLAYBACK_TX"
+#define LPASS_BE_INCALL_RECORD_RX "INCALL_RECORD_RX"
+#define LPASS_BE_INCALL_RECORD_TX "INCALL_RECORD_TX"
+#define LPASS_BE_SEC_I2S_RX "SECONDARY_I2S_RX"
+#define LPASS_BE_SPDIF_RX "SPDIF_RX"
+
+#define LPASS_BE_MI2S_RX "MI2S_RX"
+#define LPASS_BE_MI2S_TX "MI2S_TX"
+#define LPASS_BE_QUAT_MI2S_RX "QUAT_MI2S_RX"
+#define LPASS_BE_QUAT_MI2S_TX "QUAT_MI2S_TX"
+#define LPASS_BE_SEC_MI2S_RX "SEC_MI2S_RX"
+#define LPASS_BE_SEC_MI2S_RX_SD1 "SEC_MI2S_RX_SD1"
+#define LPASS_BE_SEC_MI2S_TX "SEC_MI2S_TX"
+#define LPASS_BE_PRI_MI2S_RX "PRI_MI2S_RX"
+#define LPASS_BE_PRI_MI2S_TX "PRI_MI2S_TX"
+#define LPASS_BE_TERT_MI2S_RX "TERTIARY_MI2S_RX"
+#define LPASS_BE_TERT_MI2S_TX "TERTIARY_MI2S_TX"
+#define LPASS_BE_AUDIO_I2S_RX "AUDIO_I2S_RX"
+#define LPASS_BE_STUB_RX "STUB_RX"
+#define LPASS_BE_STUB_TX "STUB_TX"
+#define LPASS_BE_SLIMBUS_1_RX "SLIMBUS_1_RX"
+#define LPASS_BE_SLIMBUS_1_TX "SLIMBUS_1_TX"
+#define LPASS_BE_STUB_1_TX "STUB_1_TX"
+#define LPASS_BE_SLIMBUS_2_RX "SLIMBUS_2_RX"
+#define LPASS_BE_SLIMBUS_2_TX "SLIMBUS_2_TX"
+#define LPASS_BE_SLIMBUS_3_RX "SLIMBUS_3_RX"
+#define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
+#define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
+#define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
+#define LPASS_BE_SLIMBUS_5_RX "SLIMBUS_5_RX"
+#define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX"
+#define LPASS_BE_SLIMBUS_6_RX "SLIMBUS_6_RX"
+#define LPASS_BE_SLIMBUS_6_TX "SLIMBUS_6_TX"
+#define LPASS_BE_QUIN_MI2S_RX "QUIN_MI2S_RX"
+#define LPASS_BE_QUIN_MI2S_TX "QUIN_MI2S_TX"
+#define LPASS_BE_SENARY_MI2S_TX "SENARY_MI2S_TX"
+
+#define LPASS_BE_PRI_TDM_RX_0 "PRI_TDM_RX_0"
+#define LPASS_BE_PRI_TDM_TX_0 "PRI_TDM_TX_0"
+#define LPASS_BE_PRI_TDM_RX_1 "PRI_TDM_RX_1"
+#define LPASS_BE_PRI_TDM_TX_1 "PRI_TDM_TX_1"
+#define LPASS_BE_PRI_TDM_RX_2 "PRI_TDM_RX_2"
+#define LPASS_BE_PRI_TDM_TX_2 "PRI_TDM_TX_2"
+#define LPASS_BE_PRI_TDM_RX_3 "PRI_TDM_RX_3"
+#define LPASS_BE_PRI_TDM_TX_3 "PRI_TDM_TX_3"
+#define LPASS_BE_PRI_TDM_RX_4 "PRI_TDM_RX_4"
+#define LPASS_BE_PRI_TDM_TX_4 "PRI_TDM_TX_4"
+#define LPASS_BE_PRI_TDM_RX_5 "PRI_TDM_RX_5"
+#define LPASS_BE_PRI_TDM_TX_5 "PRI_TDM_TX_5"
+#define LPASS_BE_PRI_TDM_RX_6 "PRI_TDM_RX_6"
+#define LPASS_BE_PRI_TDM_TX_6 "PRI_TDM_TX_6"
+#define LPASS_BE_PRI_TDM_RX_7 "PRI_TDM_RX_7"
+#define LPASS_BE_PRI_TDM_TX_7 "PRI_TDM_TX_7"
+#define LPASS_BE_SEC_TDM_RX_0 "SEC_TDM_RX_0"
+#define LPASS_BE_SEC_TDM_TX_0 "SEC_TDM_TX_0"
+#define LPASS_BE_SEC_TDM_RX_1 "SEC_TDM_RX_1"
+#define LPASS_BE_SEC_TDM_TX_1 "SEC_TDM_TX_1"
+#define LPASS_BE_SEC_TDM_RX_2 "SEC_TDM_RX_2"
+#define LPASS_BE_SEC_TDM_TX_2 "SEC_TDM_TX_2"
+#define LPASS_BE_SEC_TDM_RX_3 "SEC_TDM_RX_3"
+#define LPASS_BE_SEC_TDM_TX_3 "SEC_TDM_TX_3"
+#define LPASS_BE_SEC_TDM_RX_4 "SEC_TDM_RX_4"
+#define LPASS_BE_SEC_TDM_TX_4 "SEC_TDM_TX_4"
+#define LPASS_BE_SEC_TDM_RX_5 "SEC_TDM_RX_5"
+#define LPASS_BE_SEC_TDM_TX_5 "SEC_TDM_TX_5"
+#define LPASS_BE_SEC_TDM_RX_6 "SEC_TDM_RX_6"
+#define LPASS_BE_SEC_TDM_TX_6 "SEC_TDM_TX_6"
+#define LPASS_BE_SEC_TDM_RX_7 "SEC_TDM_RX_7"
+#define LPASS_BE_SEC_TDM_TX_7 "SEC_TDM_TX_7"
+#define LPASS_BE_TERT_TDM_RX_0 "TERT_TDM_RX_0"
+#define LPASS_BE_TERT_TDM_TX_0 "TERT_TDM_TX_0"
+#define LPASS_BE_TERT_TDM_RX_1 "TERT_TDM_RX_1"
+#define LPASS_BE_TERT_TDM_TX_1 "TERT_TDM_TX_1"
+#define LPASS_BE_TERT_TDM_RX_2 "TERT_TDM_RX_2"
+#define LPASS_BE_TERT_TDM_TX_2 "TERT_TDM_TX_2"
+#define LPASS_BE_TERT_TDM_RX_3 "TERT_TDM_RX_3"
+#define LPASS_BE_TERT_TDM_TX_3 "TERT_TDM_TX_3"
+#define LPASS_BE_TERT_TDM_RX_4 "TERT_TDM_RX_4"
+#define LPASS_BE_TERT_TDM_TX_4 "TERT_TDM_TX_4"
+#define LPASS_BE_TERT_TDM_RX_5 "TERT_TDM_RX_5"
+#define LPASS_BE_TERT_TDM_TX_5 "TERT_TDM_TX_5"
+#define LPASS_BE_TERT_TDM_RX_6 "TERT_TDM_RX_6"
+#define LPASS_BE_TERT_TDM_TX_6 "TERT_TDM_TX_6"
+#define LPASS_BE_TERT_TDM_RX_7 "TERT_TDM_RX_7"
+#define LPASS_BE_TERT_TDM_TX_7 "TERT_TDM_TX_7"
+#define LPASS_BE_QUAT_TDM_RX_0 "QUAT_TDM_RX_0"
+#define LPASS_BE_QUAT_TDM_TX_0 "QUAT_TDM_TX_0"
+#define LPASS_BE_QUAT_TDM_RX_1 "QUAT_TDM_RX_1"
+#define LPASS_BE_QUAT_TDM_TX_1 "QUAT_TDM_TX_1"
+#define LPASS_BE_QUAT_TDM_RX_2 "QUAT_TDM_RX_2"
+#define LPASS_BE_QUAT_TDM_TX_2 "QUAT_TDM_TX_2"
+#define LPASS_BE_QUAT_TDM_RX_3 "QUAT_TDM_RX_3"
+#define LPASS_BE_QUAT_TDM_TX_3 "QUAT_TDM_TX_3"
+#define LPASS_BE_QUAT_TDM_RX_4 "QUAT_TDM_RX_4"
+#define LPASS_BE_QUAT_TDM_TX_4 "QUAT_TDM_TX_4"
+#define LPASS_BE_QUAT_TDM_RX_5 "QUAT_TDM_RX_5"
+#define LPASS_BE_QUAT_TDM_TX_5 "QUAT_TDM_TX_5"
+#define LPASS_BE_QUAT_TDM_RX_6 "QUAT_TDM_RX_6"
+#define LPASS_BE_QUAT_TDM_TX_6 "QUAT_TDM_TX_6"
+#define LPASS_BE_QUAT_TDM_RX_7 "QUAT_TDM_RX_7"
+#define LPASS_BE_QUAT_TDM_TX_7 "QUAT_TDM_TX_7"
+
+#define LPASS_BE_SLIMBUS_7_RX "SLIMBUS_7_RX"
+#define LPASS_BE_SLIMBUS_7_TX "SLIMBUS_7_TX"
+#define LPASS_BE_SLIMBUS_8_RX "SLIMBUS_8_RX"
+#define LPASS_BE_SLIMBUS_8_TX "SLIMBUS_8_TX"
+
+#define LPASS_BE_USB_AUDIO_RX "USB_AUDIO_RX"
+#define LPASS_BE_USB_AUDIO_TX "USB_AUDIO_TX"
+
+#define LPASS_BE_INT0_MI2S_RX "INT0_MI2S_RX"
+#define LPASS_BE_INT0_MI2S_TX "INT0_MI2S_TX"
+#define LPASS_BE_INT1_MI2S_RX "INT1_MI2S_RX"
+#define LPASS_BE_INT1_MI2S_TX "INT1_MI2S_TX"
+#define LPASS_BE_INT2_MI2S_RX "INT2_MI2S_RX"
+#define LPASS_BE_INT2_MI2S_TX "INT2_MI2S_TX"
+#define LPASS_BE_INT3_MI2S_RX "INT3_MI2S_RX"
+#define LPASS_BE_INT3_MI2S_TX "INT3_MI2S_TX"
+#define LPASS_BE_INT4_MI2S_RX "INT4_MI2S_RX"
+#define LPASS_BE_INT4_MI2S_TX "INT4_MI2S_TX"
+#define LPASS_BE_INT5_MI2S_RX "INT5_MI2S_RX"
+#define LPASS_BE_INT5_MI2S_TX "INT5_MI2S_TX"
+#define LPASS_BE_INT6_MI2S_RX "INT6_MI2S_RX"
+#define LPASS_BE_INT6_MI2S_TX "INT6_MI2S_TX"
+/* For multimedia front-ends, asm session is allocated dynamically.
+ * Hence, asm session/multimedia front-end mapping has to be maintained.
+ * Due to this reason, additional multimedia front-end must be placed before
+ * non-multimedia front-ends.
+ */
+
+enum {
+ MSM_FRONTEND_DAI_MULTIMEDIA1 = 0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3,
+ MSM_FRONTEND_DAI_MULTIMEDIA4,
+ MSM_FRONTEND_DAI_MULTIMEDIA5,
+ MSM_FRONTEND_DAI_MULTIMEDIA6,
+ MSM_FRONTEND_DAI_MULTIMEDIA7,
+ MSM_FRONTEND_DAI_MULTIMEDIA8,
+ MSM_FRONTEND_DAI_MULTIMEDIA9,
+ MSM_FRONTEND_DAI_MULTIMEDIA10,
+ MSM_FRONTEND_DAI_MULTIMEDIA11,
+ MSM_FRONTEND_DAI_MULTIMEDIA12,
+ MSM_FRONTEND_DAI_MULTIMEDIA13,
+ MSM_FRONTEND_DAI_MULTIMEDIA14,
+ MSM_FRONTEND_DAI_MULTIMEDIA15,
+ MSM_FRONTEND_DAI_MULTIMEDIA16,
+ MSM_FRONTEND_DAI_MULTIMEDIA17,
+ MSM_FRONTEND_DAI_MULTIMEDIA18,
+ MSM_FRONTEND_DAI_MULTIMEDIA19,
+ MSM_FRONTEND_DAI_CS_VOICE,
+ MSM_FRONTEND_DAI_VOIP,
+ MSM_FRONTEND_DAI_AFE_RX,
+ MSM_FRONTEND_DAI_AFE_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB,
+ MSM_FRONTEND_DAI_VOLTE,
+ MSM_FRONTEND_DAI_DTMF_RX,
+ MSM_FRONTEND_DAI_VOICE2,
+ MSM_FRONTEND_DAI_QCHAT,
+ MSM_FRONTEND_DAI_VOLTE_STUB,
+ MSM_FRONTEND_DAI_LSM1,
+ MSM_FRONTEND_DAI_LSM2,
+ MSM_FRONTEND_DAI_LSM3,
+ MSM_FRONTEND_DAI_LSM4,
+ MSM_FRONTEND_DAI_LSM5,
+ MSM_FRONTEND_DAI_LSM6,
+ MSM_FRONTEND_DAI_LSM7,
+ MSM_FRONTEND_DAI_LSM8,
+ MSM_FRONTEND_DAI_VOICE2_STUB,
+ MSM_FRONTEND_DAI_VOWLAN,
+ MSM_FRONTEND_DAI_VOICEMMODE1,
+ MSM_FRONTEND_DAI_VOICEMMODE2,
+ MSM_FRONTEND_DAI_MAX,
+};
+
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA19 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA19
+
+enum {
+ MSM_BACKEND_DAI_PRI_I2S_RX = 0,
+ MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_BACKEND_DAI_HDMI_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_BACKEND_DAI_MI2S_RX,
+ MSM_BACKEND_DAI_MI2S_TX,
+ MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ MSM_BACKEND_DAI_SLIMBUS_2_TX,
+ MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ MSM_BACKEND_DAI_SLIMBUS_6_TX,
+ MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_BACKEND_DAI_SLIMBUS_8_RX,
+ MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ MSM_BACKEND_DAI_EXTPROC_RX,
+ MSM_BACKEND_DAI_EXTPROC_TX,
+ MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_BACKEND_DAI_AUDIO_I2S_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_BACKEND_DAI_SECONDARY_MI2S_RX_SD1,
+ MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_BACKEND_DAI_QUINARY_MI2S_TX,
+ MSM_BACKEND_DAI_SENARY_MI2S_TX,
+ MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_BACKEND_DAI_PRI_TDM_RX_4,
+ MSM_BACKEND_DAI_PRI_TDM_TX_4,
+ MSM_BACKEND_DAI_PRI_TDM_RX_5,
+ MSM_BACKEND_DAI_PRI_TDM_TX_5,
+ MSM_BACKEND_DAI_PRI_TDM_RX_6,
+ MSM_BACKEND_DAI_PRI_TDM_TX_6,
+ MSM_BACKEND_DAI_PRI_TDM_RX_7,
+ MSM_BACKEND_DAI_PRI_TDM_TX_7,
+ MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ MSM_BACKEND_DAI_SEC_TDM_RX_4,
+ MSM_BACKEND_DAI_SEC_TDM_TX_4,
+ MSM_BACKEND_DAI_SEC_TDM_RX_5,
+ MSM_BACKEND_DAI_SEC_TDM_TX_5,
+ MSM_BACKEND_DAI_SEC_TDM_RX_6,
+ MSM_BACKEND_DAI_SEC_TDM_TX_6,
+ MSM_BACKEND_DAI_SEC_TDM_RX_7,
+ MSM_BACKEND_DAI_SEC_TDM_TX_7,
+ MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_BACKEND_DAI_TERT_TDM_TX_4,
+ MSM_BACKEND_DAI_TERT_TDM_RX_5,
+ MSM_BACKEND_DAI_TERT_TDM_TX_5,
+ MSM_BACKEND_DAI_TERT_TDM_RX_6,
+ MSM_BACKEND_DAI_TERT_TDM_TX_6,
+ MSM_BACKEND_DAI_TERT_TDM_RX_7,
+ MSM_BACKEND_DAI_TERT_TDM_TX_7,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_4,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_4,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_5,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_5,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_6,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_6,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_7,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_7,
+ MSM_BACKEND_DAI_INT_BT_A2DP_RX,
+ MSM_BACKEND_DAI_USB_RX,
+ MSM_BACKEND_DAI_USB_TX,
+ MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_BACKEND_DAI_INT0_MI2S_TX,
+ MSM_BACKEND_DAI_INT1_MI2S_RX,
+ MSM_BACKEND_DAI_INT1_MI2S_TX,
+ MSM_BACKEND_DAI_INT2_MI2S_RX,
+ MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_BACKEND_DAI_INT3_MI2S_RX,
+ MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_BACKEND_DAI_INT4_MI2S_TX,
+ MSM_BACKEND_DAI_INT5_MI2S_RX,
+ MSM_BACKEND_DAI_INT5_MI2S_TX,
+ MSM_BACKEND_DAI_INT6_MI2S_RX,
+ MSM_BACKEND_DAI_INT6_MI2S_TX,
+ MSM_BACKEND_DAI_MAX,
+};
+
+enum msm_pcm_routing_event {
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ MSM_PCM_RT_EVT_MAX,
+};
+
+enum {
+ EXT_EC_REF_NONE = 0,
+ EXT_EC_REF_PRI_MI2S_TX,
+ EXT_EC_REF_SEC_MI2S_TX,
+ EXT_EC_REF_TERT_MI2S_TX,
+ EXT_EC_REF_QUAT_MI2S_TX,
+ EXT_EC_REF_QUIN_MI2S_TX,
+ EXT_EC_REF_SLIM_1_TX,
+};
+
+#define INVALID_SESSION -1
+#define SESSION_TYPE_RX 0
+#define SESSION_TYPE_TX 1
+#define INT_RX_VOL_MAX_STEPS 0x2000
+#define INT_RX_VOL_GAIN 0x2000
+
+#define RELEASE_LOCK 0
+#define ACQUIRE_LOCK 1
+
+#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX 2
+#define HDMI_RX_ID 0x8001
+#define ADM_PP_PARAM_MUTE_ID 0
+#define ADM_PP_PARAM_MUTE_BIT 1
+#define ADM_PP_PARAM_LATENCY_ID 1
+#define ADM_PP_PARAM_LATENCY_BIT 2
+#define BE_DAI_PORT_SESSIONS_IDX_MAX 4
+
+struct msm_pcm_routing_evt {
+ void (*event_func)(enum msm_pcm_routing_event, void *);
+ void *priv_data;
+};
+
+struct msm_pcm_routing_bdai_data {
+ u16 port_id; /* AFE port ID */
+ u8 active; /* track if this backend is enabled */
+ unsigned long fe_sessions; /* Front-end sessions */
+ /*
+ * Track Tx BE ports -> Rx BE ports.
+ * port_sessions[0] used to track BE 0 to BE 63.
+ * port_sessions[1] used to track BE 64 to BE 127.
+ * port_sessions[2] used to track BE 128 to BE 191.
+ * port_sessions[3] used to track BE 192 to BE 255.
+ */
+ u64 port_sessions[BE_DAI_PORT_SESSIONS_IDX_MAX];
+
+ unsigned int sample_rate;
+ unsigned int channel;
+ unsigned int format;
+ unsigned int adm_override_ch;
+ u32 compr_passthr_mode;
+ char *name;
+};
+
+struct msm_pcm_routing_fdai_data {
+ u16 be_srate; /* track prior backend sample rate for flushing purpose */
+ int strm_id; /* ASM stream ID */
+ int perf_mode;
+ struct msm_pcm_routing_evt event_info;
+};
+
+#define MAX_APP_TYPES 16
+struct msm_pcm_routing_app_type_data {
+ int app_type;
+ u32 sample_rate;
+ int bit_width;
+};
+
+struct msm_pcm_stream_app_type_cfg {
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+};
+
+/* dai_id: front-end ID,
+ * dspst_id: DSP audio stream ID
+ * stream_type: playback or capture
+ */
+int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id,
+ int stream_type);
+void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
+ int stream_type);
+int msm_pcm_routing_reg_phy_compr_stream(int fedai_id, int perf_mode,
+ int dspst_id, int stream_type,
+ uint32_t compr_passthr);
+
+int msm_pcm_routing_reg_phy_stream_v2(int fedai_id, int perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info);
+
+void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
+
+int msm_routing_check_backend_enabled(int fedai_id);
+
+
+void msm_pcm_routing_get_bedai_info(int be_idx,
+ struct msm_pcm_routing_bdai_data *bedai);
+void msm_pcm_routing_get_fedai_info(int fe_idx, int sess_type,
+ struct msm_pcm_routing_fdai_data *fe_dai);
+void msm_pcm_routing_acquire_lock(void);
+void msm_pcm_routing_release_lock(void);
+
+void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
+ int acdb_dev_id, int sample_rate, int session_type);
+int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
+ int *app_type, int *acdb_dev_id, int *sample_rate);
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
new file mode 100644
index 0000000..f4acdeb
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -0,0 +1,758 @@
+/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/of_device.h>
+
+#include "msm-pcm-voice-v2.h"
+#include "q6voice.h"
+
+static struct msm_voice voice_info[VOICE_SESSION_INDEX_MAX];
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ .channels_min = 1,
+ .channels_max = 1,
+
+ .buffer_bytes_max = 4096 * 2,
+ .period_bytes_min = 2048,
+ .period_bytes_max = 4096,
+ .periods_min = 2,
+ .periods_max = 4,
+
+ .fifo_size = 0,
+};
+static bool is_volte(struct msm_voice *pvolte)
+{
+ if (pvolte == &voice_info[VOLTE_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
+static bool is_voice2(struct msm_voice *pvoice2)
+{
+ if (pvoice2 == &voice_info[VOICE2_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
+static bool is_qchat(struct msm_voice *pqchat)
+{
+ if (pqchat == &voice_info[QCHAT_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
+static bool is_vowlan(struct msm_voice *pvowlan)
+{
+ if (pvowlan == &voice_info[VOWLAN_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
+static bool is_voicemmode1(struct msm_voice *pvoicemmode1)
+{
+ if (pvoicemmode1 == &voice_info[VOICEMMODE1_INDEX])
+ return true;
+ else
+ return false;
+}
+
+static bool is_voicemmode2(struct msm_voice *pvoicemmode2)
+{
+ if (pvoicemmode2 == &voice_info[VOICEMMODE2_INDEX])
+ return true;
+ else
+ return false;
+}
+
+static uint32_t get_session_id(struct msm_voice *pvoc)
+{
+ uint32_t session_id = 0;
+
+ if (is_volte(pvoc))
+ session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (is_voice2(pvoc))
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+ else if (is_qchat(pvoc))
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ else if (is_vowlan(pvoc))
+ session_id = voc_get_session_id(VOWLAN_SESSION_NAME);
+ else if (is_voicemmode1(pvoc))
+ session_id = voc_get_session_id(VOICEMMODE1_NAME);
+ else if (is_voicemmode2(pvoc))
+ session_id = voc_get_session_id(VOICEMMODE2_NAME);
+ else
+ session_id = voc_get_session_id(VOICE_SESSION_NAME);
+
+ return session_id;
+}
+
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+
+ pr_debug("%s\n", __func__);
+
+ if (!prtd->playback_start)
+ prtd->playback_start = 1;
+
+ return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+
+ pr_debug("%s\n", __func__);
+
+ if (!prtd->capture_start)
+ prtd->capture_start = 1;
+
+ return 0;
+}
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *voice;
+
+ if (!strcmp("VoLTE", substream->pcm->id)) {
+ voice = &voice_info[VOLTE_SESSION_INDEX];
+ pr_debug("%s: Open VoLTE Substream Id=%s\n",
+ __func__, substream->pcm->id);
+ } else if (!strcmp("Voice2", substream->pcm->id)) {
+ voice = &voice_info[VOICE2_SESSION_INDEX];
+ pr_debug("%s: Open Voice2 Substream Id=%s\n",
+ __func__, substream->pcm->id);
+ } else if (!strcmp("QCHAT", substream->pcm->id)) {
+ voice = &voice_info[QCHAT_SESSION_INDEX];
+ pr_debug("%s: Open QCHAT Substream Id=%s\n",
+ __func__, substream->pcm->id);
+ } else if (!strcmp("VoWLAN", substream->pcm->id)) {
+ voice = &voice_info[VOWLAN_SESSION_INDEX];
+ pr_debug("%s: Open VoWLAN Substream Id=%s\n",
+ __func__, substream->pcm->id);
+ } else if (!strcmp("VoiceMMode1", substream->pcm->id)) {
+ voice = &voice_info[VOICEMMODE1_INDEX];
+ pr_debug("%s: Open VoiceMMode1 Substream Id=%s\n",
+ __func__, substream->pcm->id);
+ } else if (!strcmp("VoiceMMode2", substream->pcm->id)) {
+ voice = &voice_info[VOICEMMODE2_INDEX];
+ pr_debug("%s: Open VoiceMMode2 Substream Id=%s\n",
+ __func__, substream->pcm->id);
+ } else {
+ voice = &voice_info[VOICE_SESSION_INDEX];
+ pr_debug("%s: Open VOICE Substream Id=%s\n",
+ __func__, substream->pcm->id);
+ }
+ mutex_lock(&voice->lock);
+
+ runtime->hw = msm_pcm_hardware;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ voice->playback_substream = substream;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ voice->capture_substream = substream;
+
+ voice->instance++;
+ pr_debug("%s: Instance = %d, Stream ID = %s\n",
+ __func__, voice->instance, substream->pcm->id);
+ runtime->private_data = voice;
+
+ mutex_unlock(&voice->lock);
+
+ return 0;
+}
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+
+ pr_debug("%s\n", __func__);
+
+ if (prtd->playback_start)
+ prtd->playback_start = 0;
+
+ prtd->playback_substream = NULL;
+
+ return 0;
+}
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+
+ pr_debug("%s\n", __func__);
+
+ if (prtd->capture_start)
+ prtd->capture_start = 0;
+ prtd->capture_substream = NULL;
+
+ return 0;
+}
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+ uint32_t session_id = 0;
+ int ret = 0;
+
+ mutex_lock(&prtd->lock);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_close(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_close(substream);
+
+ prtd->instance--;
+ if (!prtd->playback_start && !prtd->capture_start) {
+ pr_debug("end voice call\n");
+
+ session_id = get_session_id(prtd);
+ if (session_id)
+ voc_end_voice_call(session_id);
+ }
+ mutex_unlock(&prtd->lock);
+
+ return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+ uint32_t session_id = 0;
+
+ mutex_lock(&prtd->lock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_prepare(substream);
+
+ if (prtd->playback_start && prtd->capture_start) {
+ session_id = get_session_id(prtd);
+ if (session_id)
+ voc_start_voice_call(session_id);
+ }
+ mutex_unlock(&prtd->lock);
+
+ return ret;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+
+ pr_debug("%s: Voice\n", __func__);
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+ uint32_t session_id = 0;
+
+ pr_debug("%s: cmd = %d\n", __func__, cmd);
+
+ session_id = get_session_id(prtd);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("Start & Stop Voice call not handled in Trigger.\n");
+ break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: resume call session_id = %d\n", __func__,
+ session_id);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_prepare(substream);
+ if (prtd->playback_start && prtd->capture_start) {
+ if (session_id)
+ voc_resume_voice_call(session_id);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("%s: pause call session_id=%d\n",
+ __func__, session_id);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (prtd->playback_start)
+ prtd->playback_start = 0;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (prtd->capture_start)
+ prtd->capture_start = 0;
+ }
+ if (session_id)
+ voc_standby_voice_call(session_id);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+ uint32_t session_id = get_session_id(prtd);
+ enum voice_lch_mode lch_mode;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_VOICE_IOCTL_LCH:
+ if (copy_from_user(&lch_mode, (void *)arg,
+ sizeof(enum voice_lch_mode))) {
+ pr_err("%s: Copy from user failed, size %zd\n",
+ __func__, sizeof(enum voice_lch_mode));
+
+ ret = -EFAULT;
+ break;
+ }
+
+ pr_debug("%s: %s lch_mode:%d\n",
+ __func__, substream->pcm->id, lch_mode);
+
+ switch (lch_mode) {
+ case VOICE_LCH_START:
+ case VOICE_LCH_STOP:
+ ret = voc_set_lch(session_id, lch_mode);
+ break;
+
+ default:
+ pr_err("%s: Invalid LCH MODE %d\n", __func__, lch_mode);
+
+ ret = -EFAULT;
+ }
+
+ break;
+ default:
+ pr_debug("%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
+ __func__, cmd);
+
+ ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+ break;
+ }
+
+ if (!ret)
+ pr_debug("%s: ret %d\n", __func__, ret);
+ else
+ pr_err("%s: cmd 0x%x failed %d\n", __func__, cmd, ret);
+
+ return ret;
+}
+
+static int msm_voice_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int volume = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ int ramp_duration = ucontrol->value.integer.value[2];
+
+ if ((volume < 0) || (ramp_duration < 0)
+ || (ramp_duration > MAX_RAMP_DURATION)) {
+ pr_err(" %s Invalid arguments", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: volume: %d session_id: %#x ramp_duration: %d\n", __func__,
+ volume, session_id, ramp_duration);
+
+ voc_set_rx_vol_step(session_id, RX_PATH, volume, ramp_duration);
+
+done:
+ return ret;
+}
+
+static int msm_voice_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int mute = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ int ramp_duration = ucontrol->value.integer.value[2];
+
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0)
+ || (ramp_duration > MAX_RAMP_DURATION)) {
+ pr_err(" %s Invalid arguments", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
+ mute, session_id, ramp_duration);
+
+ ret = voc_set_tx_mute(session_id, TX_PATH, mute, ramp_duration);
+
+done:
+ return ret;
+}
+
+static int msm_voice_tx_device_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int mute = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ int ramp_duration = ucontrol->value.integer.value[2];
+
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0) ||
+ (ramp_duration > MAX_RAMP_DURATION)) {
+ pr_err(" %s Invalid arguments", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
+ mute, session_id, ramp_duration);
+
+ ret = voc_set_device_mute(session_id, VSS_IVOLUME_DIRECTION_TX,
+ mute, ramp_duration);
+
+done:
+ return ret;
+}
+
+static int msm_voice_rx_device_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int mute = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ int ramp_duration = ucontrol->value.integer.value[2];
+
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0) ||
+ (ramp_duration > MAX_RAMP_DURATION)) {
+ pr_err(" %s Invalid arguments", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
+ mute, session_id, ramp_duration);
+
+ voc_set_device_mute(session_id, VSS_IVOLUME_DIRECTION_RX,
+ mute, ramp_duration);
+
+done:
+ return ret;
+}
+
+
+
+static const char * const tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
+static const struct soc_enum msm_tty_mode_enum[] = {
+ SOC_ENUM_SINGLE_EXT(4, tty_mode),
+};
+
+static int msm_voice_tty_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ voc_get_tty_mode(voc_get_session_id(VOICE_SESSION_NAME));
+ return 0;
+}
+
+static int msm_voice_tty_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int tty_mode = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: tty_mode=%d\n", __func__, tty_mode);
+
+ voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOLTE_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOWLAN_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOICEMMODE1_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOICEMMODE2_NAME), tty_mode);
+
+ return 0;
+}
+
+static int msm_voice_slowtalk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int st_enable = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+
+ pr_debug("%s: st enable=%d session_id=%#x\n", __func__, st_enable,
+ session_id);
+
+ voc_set_pp_enable(session_id,
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
+
+ return 0;
+}
+
+static int msm_voice_hd_voice_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ uint32_t hd_enable = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+
+ pr_debug("%s: HD Voice enable=%d session_id=%#x\n", __func__, hd_enable,
+ session_id);
+
+ ret = voc_set_hd_enable(session_id, hd_enable);
+
+ return ret;
+}
+
+static int msm_voice_topology_disable_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int disable = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+
+ if ((disable < 0) || (disable > 1)) {
+ pr_err(" %s Invalid arguments: %d\n", __func__, disable);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ pr_debug("%s: disable = %d, session_id = %d\n", __func__, disable,
+ session_id);
+
+ ret = voc_disable_topology(session_id, disable);
+
+done:
+ return ret;
+}
+
+static int msm_voice_cvd_version_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int ret = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = CVD_VERSION_STRING_MAX_SIZE;
+
+ return ret;
+}
+
+static int msm_voice_cvd_version_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ char cvd_version[CVD_VERSION_STRING_MAX_SIZE] = CVD_VERSION_DEFAULT;
+ int ret;
+
+ pr_debug("%s:\n", __func__);
+
+ ret = voc_get_cvd_version(cvd_version);
+
+ if (ret)
+ pr_err("%s: Error retrieving CVD version, error:%d\n",
+ __func__, ret);
+
+ memcpy(ucontrol->value.bytes.data, cvd_version, sizeof(cvd_version));
+
+ return 0;
+}
+static struct snd_kcontrol_new msm_voice_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, VSID_MAX,
+ 0, 3, NULL, msm_voice_rx_device_mute_put),
+ SOC_SINGLE_MULTI_EXT("Voice Tx Device Mute", SND_SOC_NOPM, 0, VSID_MAX,
+ 0, 3, NULL, msm_voice_tx_device_mute_put),
+ SOC_SINGLE_MULTI_EXT("Voice Tx Mute", SND_SOC_NOPM, 0, VSID_MAX,
+ 0, 3, NULL, msm_voice_mute_put),
+ SOC_SINGLE_MULTI_EXT("Voice Rx Gain", SND_SOC_NOPM, 0, VSID_MAX, 0, 3,
+ NULL, msm_voice_gain_put),
+ SOC_ENUM_EXT("TTY Mode", msm_tty_mode_enum[0], msm_voice_tty_mode_get,
+ msm_voice_tty_mode_put),
+ SOC_SINGLE_MULTI_EXT("Slowtalk Enable", SND_SOC_NOPM, 0, VSID_MAX, 0, 2,
+ NULL, msm_voice_slowtalk_put),
+ SOC_SINGLE_MULTI_EXT("Voice Topology Disable", SND_SOC_NOPM, 0,
+ VSID_MAX, 0, 2, NULL,
+ msm_voice_topology_disable_put),
+ SOC_SINGLE_MULTI_EXT("HD Voice Enable", SND_SOC_NOPM, 0, VSID_MAX, 0, 2,
+ NULL, msm_voice_hd_voice_put),
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "CVD Version",
+ .info = msm_voice_cvd_version_info,
+ .get = msm_voice_cvd_version_get,
+ },
+};
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+ .ioctl = msm_pcm_ioctl,
+ .compat_ioctl = msm_pcm_ioctl,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static int msm_pcm_voice_probe(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, msm_voice_controls,
+ ARRAY_SIZE(msm_voice_controls));
+
+ return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+ .probe = msm_pcm_voice_probe,
+};
+
+static int msm_pcm_probe(struct platform_device *pdev)
+{
+ int rc;
+ bool destroy_cvd = false;
+ bool vote_bms = false;
+ const char *is_destroy_cvd = "qcom,destroy-cvd";
+ const char *is_vote_bms = "qcom,vote-bms";
+
+ if (!is_voc_initialized()) {
+ pr_debug("%s: voice module not initialized yet, deferring probe()\n",
+ __func__);
+
+ rc = -EPROBE_DEFER;
+ goto done;
+ }
+
+ rc = voc_alloc_cal_shared_memory();
+ if (rc == -EPROBE_DEFER) {
+ pr_debug("%s: memory allocation for calibration deferred %d\n",
+ __func__, rc);
+
+ goto done;
+ } else if (rc < 0) {
+ pr_err("%s: memory allocation for calibration failed %d\n",
+ __func__, rc);
+ }
+
+ pr_debug("%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+ destroy_cvd = of_property_read_bool(pdev->dev.of_node,
+ is_destroy_cvd);
+ voc_set_destroy_cvd_flag(destroy_cvd);
+
+ vote_bms = of_property_read_bool(pdev->dev.of_node,
+ is_vote_bms);
+ voc_set_vote_bms_flag(vote_bms);
+
+ rc = snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+
+done:
+ return rc;
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_voice_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-voice"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_voice_dt_match);
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-voice",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_voice_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = msm_pcm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ int i = 0;
+
+ memset(&voice_info, 0, sizeof(voice_info));
+
+ for (i = 0; i < VOICE_SESSION_INDEX_MAX; i++)
+ mutex_init(&voice_info[i].lock);
+
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Voice PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
new file mode 100644
index 0000000..e00cebc
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_PCM_VOICE_H
+#define _MSM_PCM_VOICE_H
+#include <sound/apr_audio-v2.h>
+
+enum {
+ VOICE_SESSION_INDEX,
+ VOLTE_SESSION_INDEX,
+ VOICE2_SESSION_INDEX,
+ QCHAT_SESSION_INDEX,
+ VOWLAN_SESSION_INDEX,
+ VOICEMMODE1_INDEX,
+ VOICEMMODE2_INDEX,
+ VOICE_SESSION_INDEX_MAX,
+};
+
+struct msm_voice {
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ int instance;
+
+ struct mutex lock;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+
+ int playback_start;
+ int capture_start;
+};
+
+#endif /*_MSM_PCM_VOICE_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
new file mode 100644
index 0000000..65fd947
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -0,0 +1,1705 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+
+#include "msm-pcm-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+#include "q6voice.h"
+
+#define SHARED_MEM_BUF 2
+#define VOIP_MAX_Q_LEN 10
+#define VOIP_MAX_VOC_PKT_SIZE 4096
+#define VOIP_MIN_VOC_PKT_SIZE 320
+
+/* Length of the DSP frame info header added to the voc packet. */
+#define DSP_FRAME_HDR_LEN 1
+
+#define MODE_IS127 0x2
+#define MODE_4GV_NB 0x3
+#define MODE_4GV_WB 0x4
+#define MODE_AMR 0x5
+#define MODE_AMR_WB 0xD
+#define MODE_PCM 0xC
+#define MODE_4GV_NW 0xE
+#define MODE_G711 0xA
+#define MODE_G711A 0xF
+
+enum msm_audio_g711a_frame_type {
+ MVS_G711A_SPEECH_GOOD,
+ MVS_G711A_SID,
+ MVS_G711A_NO_DATA,
+ MVS_G711A_ERASURE
+};
+
+enum msm_audio_g711a_mode {
+ MVS_G711A_MODE_MULAW,
+ MVS_G711A_MODE_ALAW
+};
+
+enum msm_audio_g711_mode {
+ MVS_G711_MODE_MULAW,
+ MVS_G711_MODE_ALAW
+};
+
+#define VOIP_MODE_MAX MODE_G711A
+#define VOIP_RATE_MAX 23850
+
+enum format {
+ FORMAT_S16_LE = 2,
+ FORMAT_SPECIAL = 31,
+};
+
+
+enum amr_rate_type {
+ AMR_RATE_4750, /* AMR 4.75 kbps */
+ AMR_RATE_5150, /* AMR 5.15 kbps */
+ AMR_RATE_5900, /* AMR 5.90 kbps */
+ AMR_RATE_6700, /* AMR 6.70 kbps */
+ AMR_RATE_7400, /* AMR 7.40 kbps */
+ AMR_RATE_7950, /* AMR 7.95 kbps */
+ AMR_RATE_10200, /* AMR 10.20 kbps */
+ AMR_RATE_12200, /* AMR 12.20 kbps */
+ AMR_RATE_6600, /* AMR-WB 6.60 kbps */
+ AMR_RATE_8850, /* AMR-WB 8.85 kbps */
+ AMR_RATE_12650, /* AMR-WB 12.65 kbps */
+ AMR_RATE_14250, /* AMR-WB 14.25 kbps */
+ AMR_RATE_15850, /* AMR-WB 15.85 kbps */
+ AMR_RATE_18250, /* AMR-WB 18.25 kbps */
+ AMR_RATE_19850, /* AMR-WB 19.85 kbps */
+ AMR_RATE_23050, /* AMR-WB 23.05 kbps */
+ AMR_RATE_23850, /* AMR-WB 23.85 kbps */
+ AMR_RATE_UNDEF
+};
+
+enum voip_state {
+ VOIP_STOPPED,
+ VOIP_STARTED,
+};
+
+struct voip_frame_hdr {
+ uint32_t timestamp;
+ union {
+ /*
+ * Bits 0-3: Frame type
+ * [optional] Bits 16-19: Frame rate
+ */
+ uint32_t frame_type;
+ uint32_t packet_rate;
+ };
+};
+struct voip_frame {
+ struct voip_frame_hdr frm_hdr;
+ uint32_t pktlen;
+ uint8_t voc_pkt[VOIP_MAX_VOC_PKT_SIZE];
+};
+
+struct voip_buf_node {
+ struct list_head list;
+ struct voip_frame frame;
+};
+
+struct voip_drv_info {
+ enum voip_state state;
+
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ struct list_head in_queue;
+ struct list_head free_in_queue;
+
+ struct list_head out_queue;
+ struct list_head free_out_queue;
+
+ wait_queue_head_t out_wait;
+ wait_queue_head_t in_wait;
+
+ struct mutex lock;
+
+ spinlock_t dsp_lock;
+ spinlock_t dsp_ul_lock;
+
+ bool voip_reset;
+ uint32_t mode;
+ uint32_t rate_type;
+ uint32_t rate;
+ uint32_t dtx_mode;
+
+ uint8_t capture_start;
+ uint8_t playback_start;
+
+ uint8_t playback_prepare;
+ uint8_t capture_prepare;
+
+ unsigned int play_samp_rate;
+ unsigned int cap_samp_rate;
+
+ unsigned int pcm_size;
+ unsigned int pcm_count;
+ unsigned int pcm_playback_irq_pos; /* IRQ position */
+ unsigned int pcm_playback_buf_pos; /* position in buffer */
+
+ unsigned int pcm_capture_size;
+ unsigned int pcm_capture_count;
+ unsigned int pcm_capture_irq_pos; /* IRQ position */
+ unsigned int pcm_capture_buf_pos; /* position in buffer */
+
+ uint32_t evrc_min_rate;
+ uint32_t evrc_max_rate;
+};
+
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
+ unsigned int samp_rate,
+ unsigned int *media_type);
+static int voip_get_rate_type(uint32_t mode,
+ uint32_t rate,
+ uint32_t *rate_type);
+static int voip_config_vocoder(struct snd_pcm_substream *substream);
+static int msm_voip_mode_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+static struct voip_drv_info voip_info;
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_SPECIAL,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = sizeof(struct voip_buf_node) * VOIP_MAX_Q_LEN,
+ .period_bytes_min = VOIP_MIN_VOC_PKT_SIZE,
+ .period_bytes_max = VOIP_MAX_VOC_PKT_SIZE,
+ .periods_min = VOIP_MAX_Q_LEN,
+ .periods_max = VOIP_MAX_Q_LEN,
+ .fifo_size = 0,
+};
+
+
+static int msm_voip_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int mute = ucontrol->value.integer.value[0];
+ int ramp_duration = ucontrol->value.integer.value[1];
+
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0)) {
+ pr_err(" %s Invalid arguments", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: mute=%d ramp_duration=%d\n", __func__, mute,
+ ramp_duration);
+
+ voc_set_tx_mute(voc_get_session_id(VOIP_SESSION_NAME), TX_PATH, mute,
+ ramp_duration);
+
+done:
+ return ret;
+}
+
+static int msm_voip_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int volume = ucontrol->value.integer.value[0];
+ int ramp_duration = ucontrol->value.integer.value[1];
+
+ if ((volume < 0) || (ramp_duration < 0)) {
+ pr_err(" %s Invalid arguments", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: volume: %d ramp_duration: %d\n", __func__, volume,
+ ramp_duration);
+
+ voc_set_rx_vol_step(voc_get_session_id(VOIP_SESSION_NAME),
+ RX_PATH,
+ volume,
+ ramp_duration);
+
+done:
+ return ret;
+}
+
+static int msm_voip_dtx_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ voip_info.dtx_mode = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: dtx: %d\n", __func__, voip_info.dtx_mode);
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+static int msm_voip_dtx_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ ucontrol->value.integer.value[0] = voip_info.dtx_mode;
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new msm_voip_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Voip Tx Mute", SND_SOC_NOPM, 0,
+ MAX_RAMP_DURATION,
+ 0, 2, NULL, msm_voip_mute_put),
+ SOC_SINGLE_MULTI_EXT("Voip Rx Gain", SND_SOC_NOPM, 0,
+ MAX_RAMP_DURATION,
+ 0, 2, NULL, msm_voip_gain_put),
+ SOC_SINGLE_EXT("Voip Mode Config", SND_SOC_NOPM, 0, VOIP_MODE_MAX, 0,
+ msm_voip_mode_config_get, msm_voip_mode_config_put),
+ SOC_SINGLE_EXT("Voip Rate Config", SND_SOC_NOPM, 0, VOIP_RATE_MAX, 0,
+ NULL, msm_voip_rate_config_put),
+ SOC_SINGLE_MULTI_EXT("Voip Evrc Min Max Rate Config", SND_SOC_NOPM,
+ 0, VOC_1_RATE, 0, 2,
+ msm_voip_evrc_min_max_rate_config_get,
+ msm_voip_evrc_min_max_rate_config_put),
+ SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
+ msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
+};
+
+static int msm_pcm_voip_probe(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, msm_voip_controls,
+ ARRAY_SIZE(msm_voip_controls));
+
+ return 0;
+}
+
+/* sample rate supported */
+static unsigned int supported_sample_rates[] = {8000, 16000, 32000, 48000};
+
+static void voip_ssr_cb_fn(uint32_t opcode, void *private_data)
+{
+
+ /* Notify ASoC to send next playback/Capture to unblock write/read */
+ struct voip_drv_info *prtd = private_data;
+
+ if (opcode == 0xFFFFFFFF) {
+
+ prtd->voip_reset = true;
+ pr_debug("%s: Notify ASoC to send next playback/Capture\n",
+ __func__);
+
+ prtd->pcm_playback_irq_pos += prtd->pcm_count;
+ if (prtd->state == VOIP_STARTED)
+ snd_pcm_period_elapsed(prtd->playback_substream);
+ wake_up(&prtd->out_wait);
+
+ prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+ if (prtd->state == VOIP_STARTED)
+ snd_pcm_period_elapsed(prtd->capture_substream);
+ wake_up(&prtd->in_wait);
+
+ } else {
+ pr_err("%s: Invalid opcode during reset : %d\n",
+ __func__, opcode);
+ }
+}
+
+/* capture path */
+static void voip_process_ul_pkt(uint8_t *voc_pkt,
+ uint32_t pkt_len,
+ uint32_t timestamp,
+ void *private_data)
+{
+ struct voip_buf_node *buf_node = NULL;
+ struct voip_drv_info *prtd = private_data;
+ unsigned long dsp_flags;
+
+ if (prtd->capture_substream == NULL)
+ return;
+
+ /* Copy up-link packet into out_queue. */
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
+
+ /* discarding UL packets till start is received */
+ if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
+ buf_node = list_first_entry(&prtd->free_out_queue,
+ struct voip_buf_node, list);
+ list_del(&buf_node->list);
+ switch (prtd->mode) {
+ case MODE_AMR_WB:
+ case MODE_AMR: {
+ /* Remove the DSP frame info header. Header format:
+ * Bits 0-3: Frame rate
+ * Bits 4-7: Frame type
+ */
+ buf_node->frame.frm_hdr.timestamp = timestamp;
+ buf_node->frame.frm_hdr.frame_type =
+ ((*voc_pkt) & 0xF0) >> 4;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+ buf_node->frame.pktlen = pkt_len - DSP_FRAME_HDR_LEN;
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.pktlen);
+
+ list_add_tail(&buf_node->list, &prtd->out_queue);
+ break;
+ }
+ case MODE_IS127:
+ case MODE_4GV_NB:
+ case MODE_4GV_WB:
+ case MODE_4GV_NW: {
+ /* Remove the DSP frame info header.
+ * Header format:
+ * Bits 0-3: frame rate
+ */
+ buf_node->frame.frm_hdr.timestamp = timestamp;
+ buf_node->frame.frm_hdr.packet_rate = (*voc_pkt) & 0x0F;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+ buf_node->frame.pktlen = pkt_len - DSP_FRAME_HDR_LEN;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.pktlen);
+
+ list_add_tail(&buf_node->list, &prtd->out_queue);
+ break;
+ }
+ case MODE_G711:
+ case MODE_G711A:{
+ /* G711 frames are 10ms each, but the DSP works with
+ * 20ms frames and sends two 10ms frames per buffer.
+ * Extract the two frames and put them in separate
+ * buffers.
+ */
+ /* Remove the first DSP frame info header.
+ * Header format: G711A
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ *
+ * Header format: G711
+ * Bits 2-3: Frame rate
+ */
+ if (prtd->mode == MODE_G711A)
+ buf_node->frame.frm_hdr.frame_type =
+ (*voc_pkt) & 0x03;
+ buf_node->frame.frm_hdr.timestamp = timestamp;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ /* There are two frames in the buffer. Length of the
+ * first frame:
+ */
+ buf_node->frame.pktlen = (pkt_len -
+ 2 * DSP_FRAME_HDR_LEN) / 2;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.pktlen);
+ voc_pkt = voc_pkt + buf_node->frame.pktlen;
+
+ list_add_tail(&buf_node->list, &prtd->out_queue);
+
+ /* Get another buffer from the free Q and fill in the
+ * second frame.
+ */
+ if (!list_empty(&prtd->free_out_queue)) {
+ buf_node =
+ list_first_entry(&prtd->free_out_queue,
+ struct voip_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ /* Remove the second DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+
+ if (prtd->mode == MODE_G711A)
+ buf_node->frame.frm_hdr.frame_type =
+ (*voc_pkt) & 0x03;
+ buf_node->frame.frm_hdr.timestamp = timestamp;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ /* There are two frames in the buffer. Length
+ * of the second frame:
+ */
+ buf_node->frame.pktlen = (pkt_len -
+ 2 * DSP_FRAME_HDR_LEN) / 2;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.pktlen);
+
+ list_add_tail(&buf_node->list,
+ &prtd->out_queue);
+ } else {
+ /* Drop the second frame */
+ pr_err("%s: UL data dropped, read is slow\n",
+ __func__);
+ }
+ break;
+ }
+ default: {
+ buf_node->frame.frm_hdr.timestamp = timestamp;
+ buf_node->frame.pktlen = pkt_len;
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.pktlen);
+ list_add_tail(&buf_node->list, &prtd->out_queue);
+ }
+ }
+ pr_debug("%s: pkt_len =%d, frame.pktlen=%d, timestamp=%d\n",
+ __func__, pkt_len, buf_node->frame.pktlen, timestamp);
+
+ if (prtd->mode == MODE_PCM)
+ prtd->pcm_capture_irq_pos += buf_node->frame.pktlen;
+ else
+ prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
+ snd_pcm_period_elapsed(prtd->capture_substream);
+ } else {
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
+ pr_err("UL data dropped\n");
+ }
+
+ wake_up(&prtd->out_wait);
+}
+
+/* playback path */
+static void voip_process_dl_pkt(uint8_t *voc_pkt, void *private_data)
+{
+ struct voip_buf_node *buf_node = NULL;
+ struct voip_drv_info *prtd = private_data;
+ unsigned long dsp_flags;
+ uint32_t rate_type;
+ uint32_t frame_rate;
+ u32 pkt_len;
+ u8 *voc_addr = NULL;
+
+ if (prtd->playback_substream == NULL)
+ return;
+
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+
+ if (!list_empty(&prtd->in_queue) && prtd->playback_start) {
+ buf_node = list_first_entry(&prtd->in_queue,
+ struct voip_buf_node, list);
+ list_del(&buf_node->list);
+ switch (prtd->mode) {
+ case MODE_AMR:
+ case MODE_AMR_WB: {
+ *((uint32_t *)voc_pkt) = buf_node->frame.pktlen +
+ DSP_FRAME_HDR_LEN;
+ /* Advance to the header of voip packet */
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+ /*
+ * Add the DSP frame info header. Header format:
+ * Bits 0-3: Frame rate
+ * Bits 4-7: Frame type
+ */
+ *voc_pkt = ((buf_node->frame.frm_hdr.frame_type &
+ 0x0F) << 4);
+ frame_rate = (buf_node->frame.frm_hdr.frame_type &
+ 0xFFFF0000) >> 16;
+ if (frame_rate) {
+ if (voip_get_rate_type(prtd->mode, frame_rate,
+ &rate_type)) {
+ pr_err("%s(): fail at getting rate_type\n",
+ __func__);
+ } else
+ prtd->rate_type = rate_type;
+ }
+ *voc_pkt |= prtd->rate_type & 0x0F;
+
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.pktlen);
+ list_add_tail(&buf_node->list, &prtd->free_in_queue);
+ break;
+ }
+ case MODE_IS127:
+ case MODE_4GV_NB:
+ case MODE_4GV_WB:
+ case MODE_4GV_NW: {
+ *((uint32_t *)voc_pkt) = buf_node->frame.pktlen +
+ DSP_FRAME_HDR_LEN;
+ /* Advance to the header of voip packet */
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+ /*
+ * Add the DSP frame info header. Header format:
+ * Bits 0-3 : Frame rate
+ */
+ *voc_pkt = buf_node->frame.frm_hdr.packet_rate & 0x0F;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.pktlen);
+
+ list_add_tail(&buf_node->list, &prtd->free_in_queue);
+ break;
+ }
+ case MODE_G711:
+ case MODE_G711A:{
+ /* G711 frames are 10ms each but the DSP expects 20ms
+ * worth of data, so send two 10ms frames per buffer.
+ */
+ /* Add the first DSP frame info header. Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+ voc_addr = voc_pkt;
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+
+ *voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+ (buf_node->frame.frm_hdr.frame_type & 0x03);
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ pkt_len = buf_node->frame.pktlen + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.pktlen);
+ voc_pkt = voc_pkt + buf_node->frame.pktlen;
+
+ list_add_tail(&buf_node->list, &prtd->free_in_queue);
+
+ if (!list_empty(&prtd->in_queue)) {
+ /* Get the second buffer. */
+ buf_node = list_first_entry(&prtd->in_queue,
+ struct voip_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ /* Add the second DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+ *voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+ (buf_node->frame.frm_hdr.frame_type & 0x03);
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ pkt_len = pkt_len + buf_node->frame.pktlen +
+ DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.pktlen);
+
+ list_add_tail(&buf_node->list,
+ &prtd->free_in_queue);
+ } else {
+ /* Only 10ms worth of data is available, signal
+ * erasure frame.
+ */
+ *voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+ (MVS_G711A_ERASURE & 0x03);
+
+ pkt_len = pkt_len + DSP_FRAME_HDR_LEN;
+ pr_debug("%s, Only 10ms read, erase 2nd frame\n",
+ __func__);
+ }
+ *((uint32_t *)voc_addr) = pkt_len;
+ break;
+ }
+ default: {
+ *((uint32_t *)voc_pkt) = buf_node->frame.pktlen;
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.pktlen);
+ list_add_tail(&buf_node->list, &prtd->free_in_queue);
+ }
+ }
+ pr_debug("%s: frame.pktlen=%d\n", __func__,
+ buf_node->frame.pktlen);
+
+ if (prtd->mode == MODE_PCM)
+ prtd->pcm_playback_irq_pos += buf_node->frame.pktlen;
+ else
+ prtd->pcm_playback_irq_pos += prtd->pcm_count;
+
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ snd_pcm_period_elapsed(prtd->playback_substream);
+ } else {
+ *((uint32_t *)voc_pkt) = 0;
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ pr_err_ratelimited("DL data not available\n");
+ }
+ wake_up(&prtd->in_wait);
+}
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+
+ prtd->play_samp_rate = runtime->rate;
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_playback_irq_pos = 0;
+ prtd->pcm_playback_buf_pos = 0;
+ prtd->playback_prepare = 1;
+
+ return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+ int ret = 0;
+
+ prtd->cap_samp_rate = runtime->rate;
+ prtd->pcm_capture_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_capture_irq_pos = 0;
+ prtd->pcm_capture_buf_pos = 0;
+ prtd->capture_prepare = 1;
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ pr_debug("%s: Trigger start\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->capture_start = 1;
+ else
+ prtd->playback_start = 1;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd->playback_start = 0;
+ else
+ prtd->capture_start = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = &voip_info;
+ int ret = 0;
+
+ pr_debug("%s, VoIP\n", __func__);
+ mutex_lock(&prtd->lock);
+
+ runtime->hw = msm_pcm_hardware;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret < 0)
+ pr_debug("snd_pcm_hw_constraint_list failed\n");
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ pr_debug("snd_pcm_hw_constraint_integer failed\n");
+ goto err;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd->playback_substream = substream;
+ else
+ prtd->capture_substream = substream;
+
+ runtime->private_data = prtd;
+err:
+ mutex_unlock(&prtd->lock);
+
+ return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ struct voip_buf_node *buf_node = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+ unsigned long dsp_flags;
+
+ int count = frames_to_bytes(runtime, frames);
+
+ pr_debug("%s: count = %d, frames=%d\n", __func__, count, (int)frames);
+
+ if (prtd->voip_reset) {
+ pr_debug("%s: RESET event happened during VoIP\n", __func__);
+ return -ENETRESET;
+ }
+
+ ret = wait_event_interruptible_timeout(prtd->in_wait,
+ (!list_empty(&prtd->free_in_queue) ||
+ prtd->state == VOIP_STOPPED),
+ 1 * HZ);
+ if (prtd->voip_reset) {
+ pr_debug("%s: RESET event happened during VoIP\n", __func__);
+ return -ENETRESET;
+ }
+
+ if (ret > 0) {
+ if (count <= VOIP_MAX_VOC_PKT_SIZE) {
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ buf_node =
+ list_first_entry(&prtd->free_in_queue,
+ struct voip_buf_node, list);
+ list_del(&buf_node->list);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ if (prtd->mode == MODE_PCM) {
+ ret = copy_from_user(&buf_node->frame.voc_pkt,
+ buf, count);
+ buf_node->frame.pktlen = count;
+ } else {
+ ret = copy_from_user(&buf_node->frame,
+ buf, count);
+ if (buf_node->frame.pktlen >= count)
+ buf_node->frame.pktlen = count -
+ (sizeof(buf_node->frame.frm_hdr) +
+ sizeof(buf_node->frame.pktlen));
+ }
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ list_add_tail(&buf_node->list, &prtd->in_queue);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ } else {
+ pr_err("%s: Write cnt %d is > VOIP_MAX_VOC_PKT_SIZE\n",
+ __func__, count);
+ ret = -ENOMEM;
+ }
+
+ } else if (ret == 0) {
+ pr_err("%s: No free DL buffs\n", __func__);
+ ret = -ETIMEDOUT;
+ } else {
+ pr_err("%s: playback copy was interrupted %d\n", __func__, ret);
+ }
+
+ return ret;
+}
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+ snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ int count = 0;
+ struct voip_buf_node *buf_node = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+ unsigned long dsp_flags;
+ int size;
+
+ count = frames_to_bytes(runtime, frames);
+
+ pr_debug("%s: count = %d\n", __func__, count);
+
+ if (prtd->voip_reset) {
+ pr_debug("%s: RESET event happened during VoIP\n", __func__);
+ return -ENETRESET;
+ }
+
+ ret = wait_event_interruptible_timeout(prtd->out_wait,
+ (!list_empty(&prtd->out_queue) ||
+ prtd->state == VOIP_STOPPED),
+ 1 * HZ);
+
+ if (prtd->voip_reset) {
+ pr_debug("%s: RESET event happened during VoIP\n", __func__);
+ return -ENETRESET;
+ }
+
+ if (ret > 0) {
+
+ if (count <= VOIP_MAX_VOC_PKT_SIZE) {
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
+ buf_node = list_first_entry(&prtd->out_queue,
+ struct voip_buf_node, list);
+ list_del(&buf_node->list);
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
+ if (prtd->mode == MODE_PCM) {
+ ret = copy_to_user(buf,
+ &buf_node->frame.voc_pkt,
+ buf_node->frame.pktlen);
+ } else {
+ size = sizeof(buf_node->frame.frm_hdr) +
+ sizeof(buf_node->frame.pktlen) +
+ buf_node->frame.pktlen;
+
+ ret = copy_to_user(buf,
+ &buf_node->frame,
+ size);
+ }
+ if (ret) {
+ pr_err("%s: Copy to user returned %d\n",
+ __func__, ret);
+ ret = -EFAULT;
+ }
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
+ list_add_tail(&buf_node->list,
+ &prtd->free_out_queue);
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
+ } else {
+ pr_err("%s: Read count %d > VOIP_MAX_VOC_PKT_SIZE\n",
+ __func__, count);
+ ret = -ENOMEM;
+ }
+
+
+ } else if (ret == 0) {
+ pr_err_ratelimited("%s: No UL data available\n", __func__);
+ ret = -ETIMEDOUT;
+ } else {
+ pr_err("%s: Read was interrupted\n", __func__);
+ ret = -ERESTARTSYS;
+ }
+ return ret;
+}
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+
+ return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct list_head *ptr = NULL;
+ struct list_head *next = NULL;
+ struct voip_buf_node *buf_node = NULL;
+ struct snd_dma_buffer *p_dma_buf, *c_dma_buf;
+ struct snd_pcm_substream *p_substream, *c_substream;
+ struct snd_pcm_runtime *runtime;
+ struct voip_drv_info *prtd;
+ unsigned long dsp_flags;
+
+ if (substream == NULL) {
+ pr_err("substream is NULL\n");
+ return -EINVAL;
+ }
+ runtime = substream->runtime;
+ prtd = runtime->private_data;
+
+ wake_up(&prtd->out_wait);
+
+ mutex_lock(&prtd->lock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd->playback_prepare = 0;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->capture_prepare = 0;
+
+ if (!prtd->playback_prepare && !prtd->capture_prepare) {
+ if (prtd->state == VOIP_STARTED) {
+ prtd->voip_reset = false;
+ prtd->state = VOIP_STOPPED;
+ voc_end_voice_call(
+ voc_get_session_id(VOIP_SESSION_NAME));
+ voc_register_mvs_cb(NULL, NULL, NULL, prtd);
+ }
+ /* release all buffer */
+ /* release in_queue and free_in_queue */
+ pr_debug("release all buffer\n");
+ p_substream = prtd->playback_substream;
+ if (p_substream == NULL) {
+ pr_debug("p_substream is NULL\n");
+ goto capt;
+ }
+ p_dma_buf = &p_substream->dma_buffer;
+ if (p_dma_buf == NULL) {
+ pr_debug("p_dma_buf is NULL\n");
+ goto capt;
+ }
+ if (p_dma_buf->area != NULL) {
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ list_for_each_safe(ptr, next, &prtd->in_queue) {
+ buf_node = list_entry(ptr,
+ struct voip_buf_node, list);
+ list_del(&buf_node->list);
+ }
+ list_for_each_safe(ptr, next, &prtd->free_in_queue) {
+ buf_node = list_entry(ptr,
+ struct voip_buf_node, list);
+ list_del(&buf_node->list);
+ }
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ dma_free_coherent(p_substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max, p_dma_buf->area,
+ p_dma_buf->addr);
+ p_dma_buf->area = NULL;
+ }
+ /* release out_queue and free_out_queue */
+capt: c_substream = prtd->capture_substream;
+ if (c_substream == NULL) {
+ pr_debug("c_substream is NULL\n");
+ goto done;
+ }
+ c_dma_buf = &c_substream->dma_buffer;
+ if (c_substream == NULL) {
+ pr_debug("c_dma_buf is NULL.\n");
+ goto done;
+ }
+ if (c_dma_buf->area != NULL) {
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
+ list_for_each_safe(ptr, next, &prtd->out_queue) {
+ buf_node = list_entry(ptr,
+ struct voip_buf_node, list);
+ list_del(&buf_node->list);
+ }
+ list_for_each_safe(ptr, next, &prtd->free_out_queue) {
+ buf_node = list_entry(ptr,
+ struct voip_buf_node, list);
+ list_del(&buf_node->list);
+ }
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
+ dma_free_coherent(c_substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max, c_dma_buf->area,
+ c_dma_buf->addr);
+ c_dma_buf->area = NULL;
+ }
+done:
+ prtd->capture_substream = NULL;
+ prtd->playback_substream = NULL;
+ }
+ mutex_unlock(&prtd->lock);
+
+ return ret;
+}
+
+static int voip_config_vocoder(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+ uint32_t media_type = 0;
+ uint32_t rate_type = 0;
+ uint32_t evrc_min_rate_type = 0;
+ uint32_t evrc_max_rate_type = 0;
+
+ pr_debug("%s(): mode=%d, playback rate=%d, capture rate=%d\n",
+ __func__, prtd->mode, prtd->play_samp_rate,
+ prtd->cap_samp_rate);
+
+ if ((runtime->format != FORMAT_S16_LE &&
+ runtime->format != FORMAT_SPECIAL) &&
+ ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
+ (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
+ (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW) ||
+ (prtd->mode == MODE_G711) || (prtd->mode == MODE_G711A))) {
+ pr_err("%s(): mode:%d and format:%u are not matched\n",
+ __func__, prtd->mode, (uint32_t)runtime->format);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (runtime->format != FORMAT_S16_LE && (prtd->mode == MODE_PCM)) {
+ pr_err("%s(): mode:%d and format:%u are not matched\n",
+ __func__, prtd->mode, runtime->format);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((prtd->mode == MODE_PCM) ||
+ (prtd->mode == MODE_AMR) ||
+ (prtd->mode == MODE_AMR_WB) ||
+ (prtd->mode == MODE_G711) ||
+ (prtd->mode == MODE_G711A)) {
+ ret = voip_get_rate_type(prtd->mode,
+ prtd->rate,
+ &rate_type);
+ if (ret < 0) {
+ pr_err("%s(): fail at getting rate_type, ret=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ prtd->rate_type = rate_type;
+ pr_debug("rate_type=%d\n", rate_type);
+
+ } else if ((prtd->mode == MODE_IS127) ||
+ (prtd->mode == MODE_4GV_NB) ||
+ (prtd->mode == MODE_4GV_WB) ||
+ (prtd->mode == MODE_4GV_NW)) {
+ ret = voip_get_rate_type(prtd->mode,
+ prtd->evrc_min_rate,
+ &evrc_min_rate_type);
+ if (ret < 0) {
+ pr_err("%s(): fail at getting min rate, ret=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ if (evrc_min_rate_type == VOC_0_RATE)
+ evrc_min_rate_type = VOC_8_RATE;
+
+ ret = voip_get_rate_type(prtd->mode,
+ prtd->evrc_max_rate,
+ &evrc_max_rate_type);
+ if (ret < 0) {
+ pr_err("%s(): fail at getting max rate, ret=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ if (evrc_max_rate_type == VOC_0_RATE)
+ evrc_max_rate_type = VOC_1_RATE;
+
+ if (evrc_max_rate_type < evrc_min_rate_type) {
+ pr_err("%s(): Invalid EVRC min max rates: %d, %d\n",
+ __func__, evrc_min_rate_type,
+ evrc_max_rate_type);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ pr_debug("%s(): min rate=%d, max rate=%d\n",
+ __func__, evrc_min_rate_type, evrc_max_rate_type);
+ }
+ ret = voip_get_media_type(prtd->mode,
+ prtd->rate_type,
+ prtd->play_samp_rate,
+ &media_type);
+ if (ret < 0) {
+ pr_err("%s(): fail at getting media_type, ret=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ pr_debug("%s(): media_type=%d\n", __func__, media_type);
+
+ if ((prtd->play_samp_rate == 8000 && prtd->cap_samp_rate == 8000) ||
+ (prtd->play_samp_rate == 16000 && prtd->cap_samp_rate == 16000) ||
+ (prtd->play_samp_rate == 32000 && prtd->cap_samp_rate == 32000) ||
+ (prtd->play_samp_rate == 48000 && prtd->cap_samp_rate == 48000)) {
+ voc_config_vocoder(media_type, rate_type,
+ VSS_NETWORK_ID_VOIP,
+ voip_info.dtx_mode,
+ evrc_min_rate_type,
+ evrc_max_rate_type);
+ } else {
+ pr_debug("%s: Invalid rate playback %d, capture %d\n",
+ __func__, prtd->play_samp_rate,
+ prtd->cap_samp_rate);
+
+ ret = -EINVAL;
+ }
+done:
+
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+
+ mutex_lock(&prtd->lock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_prepare(substream);
+
+ if (prtd->playback_prepare && prtd->capture_prepare
+ && (prtd->state != VOIP_STARTED)) {
+ ret = voip_config_vocoder(substream);
+ if (ret < 0) {
+ pr_err("%s(): fail at configuring vocoder for voip, ret=%d\n",
+ __func__, ret);
+
+ goto done;
+ }
+
+ /* Initialaizing cb variables */
+ voc_register_mvs_cb(voip_process_ul_pkt,
+ voip_process_dl_pkt,
+ voip_ssr_cb_fn, prtd);
+
+ ret = voc_start_voice_call(
+ voc_get_session_id(VOIP_SESSION_NAME));
+
+ if (ret < 0) {
+ pr_err("%s: voc_start_voice_call() failed err %d",
+ __func__, ret);
+
+ goto done;
+ }
+ prtd->state = VOIP_STARTED;
+ }
+done:
+ mutex_unlock(&prtd->lock);
+
+ return ret;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+
+ pr_debug("%s\n", __func__);
+ if (prtd->pcm_playback_irq_pos >= prtd->pcm_size)
+ prtd->pcm_playback_irq_pos = 0;
+ return bytes_to_frames(runtime, (prtd->pcm_playback_irq_pos));
+}
+
+static snd_pcm_uframes_t
+msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct voip_drv_info *prtd = runtime->private_data;
+
+ if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
+ prtd->pcm_capture_irq_pos = 0;
+ return bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ snd_pcm_uframes_t ret = 0;
+
+ pr_debug("%s\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_pointer(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_pointer(substream);
+ return ret;
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ pr_debug("%s\n", __func__);
+ dma_mmap_coherent(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+ return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct voip_buf_node *buf_node = NULL;
+ int i = 0, offset = 0;
+
+ pr_debug("%s: voip\n", __func__);
+
+ mutex_lock(&voip_info.lock);
+
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+
+ dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max,
+ &dma_buf->addr, GFP_KERNEL);
+ if (!dma_buf->area) {
+ pr_err("%s:MSM VOIP dma_alloc failed\n", __func__);
+ mutex_unlock(&voip_info.lock);
+ return -ENOMEM;
+ }
+
+ dma_buf->bytes = runtime->hw.buffer_bytes_max;
+ memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
+ buf_node = (void *)dma_buf->area + offset;
+
+ list_add_tail(&buf_node->list,
+ &voip_info.free_in_queue);
+ offset = offset + sizeof(struct voip_buf_node);
+ }
+ } else {
+ for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
+ buf_node = (void *) dma_buf->area + offset;
+ list_add_tail(&buf_node->list,
+ &voip_info.free_out_queue);
+ offset = offset + sizeof(struct voip_buf_node);
+ }
+ }
+
+ mutex_unlock(&voip_info.lock);
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ return 0;
+}
+
+static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ ucontrol->value.integer.value[0] = voip_info.mode;
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static int msm_voip_mode_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ voip_info.mode = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: mode=%d\n", __func__, voip_info.mode);
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int rate = ucontrol->value.integer.value[0];
+
+ mutex_lock(&voip_info.lock);
+
+ if (voip_info.rate != rate) {
+ voip_info.rate = rate;
+ pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
+
+ if (voip_info.state == VOIP_STARTED &&
+ (voip_info.mode == MODE_AMR ||
+ voip_info.mode == MODE_AMR_WB)) {
+ ret = voip_config_vocoder(
+ voip_info.capture_substream);
+ if (ret) {
+ pr_err("%s:Failed to configure vocoder, ret=%d\n",
+ __func__, ret);
+
+ goto done;
+ }
+
+ ret = voc_update_amr_vocoder_rate(
+ voc_get_session_id(VOIP_SESSION_NAME));
+ if (ret) {
+ pr_err("%s:Failed to update AMR rate, ret=%d\n",
+ __func__, ret);
+ }
+ }
+ }
+
+done:
+ mutex_unlock(&voip_info.lock);
+
+ return ret;
+}
+
+static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ ucontrol->value.integer.value[0] = voip_info.evrc_min_rate;
+ ucontrol->value.integer.value[1] = voip_info.evrc_max_rate;
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ voip_info.evrc_min_rate = ucontrol->value.integer.value[0];
+ voip_info.evrc_max_rate = ucontrol->value.integer.value[1];
+
+ pr_debug("%s(): evrc_min_rate=%d,evrc_max_rate=%d\n", __func__,
+ voip_info.evrc_min_rate, voip_info.evrc_max_rate);
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static int voip_get_rate_type(uint32_t mode, uint32_t rate,
+ uint32_t *rate_type)
+{
+ int ret = 0;
+
+ switch (mode) {
+ case MODE_AMR: {
+ switch (rate) {
+ case 4750:
+ *rate_type = AMR_RATE_4750;
+ break;
+ case 5150:
+ *rate_type = AMR_RATE_5150;
+ break;
+ case 5900:
+ *rate_type = AMR_RATE_5900;
+ break;
+ case 6700:
+ *rate_type = AMR_RATE_6700;
+ break;
+ case 7400:
+ *rate_type = AMR_RATE_7400;
+ break;
+ case 7950:
+ *rate_type = AMR_RATE_7950;
+ break;
+ case 10200:
+ *rate_type = AMR_RATE_10200;
+ break;
+ case 12200:
+ *rate_type = AMR_RATE_12200;
+ break;
+ default:
+ pr_err("wrong rate for AMR NB.\n");
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ }
+ case MODE_AMR_WB: {
+ switch (rate) {
+ case 6600:
+ *rate_type = AMR_RATE_6600 - AMR_RATE_6600;
+ break;
+ case 8850:
+ *rate_type = AMR_RATE_8850 - AMR_RATE_6600;
+ break;
+ case 12650:
+ *rate_type = AMR_RATE_12650 - AMR_RATE_6600;
+ break;
+ case 14250:
+ *rate_type = AMR_RATE_14250 - AMR_RATE_6600;
+ break;
+ case 15850:
+ *rate_type = AMR_RATE_15850 - AMR_RATE_6600;
+ break;
+ case 18250:
+ *rate_type = AMR_RATE_18250 - AMR_RATE_6600;
+ break;
+ case 19850:
+ *rate_type = AMR_RATE_19850 - AMR_RATE_6600;
+ break;
+ case 23050:
+ *rate_type = AMR_RATE_23050 - AMR_RATE_6600;
+ break;
+ case 23850:
+ *rate_type = AMR_RATE_23850 - AMR_RATE_6600;
+ break;
+ default:
+ pr_err("wrong rate for AMR_WB.\n");
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ }
+ case MODE_PCM: {
+ *rate_type = 0;
+ break;
+ }
+ case MODE_IS127:
+ case MODE_4GV_NB:
+ case MODE_4GV_WB: {
+ switch (rate) {
+ case VOC_0_RATE:
+ case VOC_8_RATE:
+ case VOC_4_RATE:
+ case VOC_2_RATE:
+ case VOC_1_RATE:
+ *rate_type = rate;
+ break;
+ default:
+ pr_err("wrong rate for IS127/4GV_NB/WB.\n");
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ }
+ case MODE_4GV_NW: {
+ switch (rate) {
+ case VOC_0_RATE:
+ case VOC_8_RATE:
+ case VOC_4_RATE:
+ case VOC_2_RATE:
+ case VOC_1_RATE:
+ case VOC_8_RATE_NC:
+ *rate_type = rate;
+ break;
+ default:
+ pr_err("wrong rate for 4GV_NW.\n");
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ }
+ case MODE_G711:
+ case MODE_G711A:
+ *rate_type = rate;
+ break;
+ default:
+ pr_err("wrong mode type.\n");
+ ret = -EINVAL;
+ }
+ pr_debug("%s, mode=%d, rate=%u, rate_type=%d\n",
+ __func__, mode, rate, *rate_type);
+ return ret;
+}
+
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
+ unsigned int samp_rate,
+ unsigned int *media_type)
+{
+ int ret = 0;
+
+ pr_debug("%s: mode=%d, samp_rate=%d\n", __func__,
+ mode, samp_rate);
+ switch (mode) {
+ case MODE_AMR:
+ *media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
+ break;
+ case MODE_AMR_WB:
+ *media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
+ break;
+ case MODE_PCM:
+ if (samp_rate == 8000)
+ *media_type = VSS_MEDIA_ID_PCM_8_KHZ;
+ else if (samp_rate == 16000)
+ *media_type = VSS_MEDIA_ID_PCM_16_KHZ;
+ else if (samp_rate == 32000)
+ *media_type = VSS_MEDIA_ID_PCM_32_KHZ;
+ else
+ *media_type = VSS_MEDIA_ID_PCM_48_KHZ;
+ break;
+ case MODE_IS127: /* EVRC-A */
+ *media_type = VSS_MEDIA_ID_EVRC_MODEM;
+ break;
+ case MODE_4GV_NB: /* EVRC-B */
+ *media_type = VSS_MEDIA_ID_4GV_NB_MODEM;
+ break;
+ case MODE_4GV_WB: /* EVRC-WB */
+ *media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
+ break;
+ case MODE_4GV_NW: /* EVRC-NW */
+ *media_type = VSS_MEDIA_ID_4GV_NW_MODEM;
+ break;
+ case MODE_G711:
+ case MODE_G711A:
+ if (rate_type == MVS_G711A_MODE_MULAW)
+ *media_type = VSS_MEDIA_ID_G711_MULAW;
+ else
+ *media_type = VSS_MEDIA_ID_G711_ALAW;
+ break;
+ default:
+ pr_debug(" input mode is not supported\n");
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: media_type is 0x%x\n", __func__, *media_type);
+
+ return ret;
+}
+
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .copy = msm_pcm_copy,
+ .hw_params = msm_pcm_hw_params,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+ .pointer = msm_pcm_pointer,
+ .mmap = msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ pr_debug("msm_asoc_pcm_new\n");
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+ .probe = msm_pcm_voip_probe,
+};
+
+static int msm_pcm_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ if (!is_voc_initialized()) {
+ pr_debug("%s: voice module not initialized yet, deferring probe()\n",
+ __func__);
+
+ rc = -EPROBE_DEFER;
+ goto done;
+ }
+
+ rc = voc_alloc_cal_shared_memory();
+ if (rc == -EPROBE_DEFER) {
+ pr_debug("%s: memory allocation for calibration deferred %d\n",
+ __func__, rc);
+
+ goto done;
+ } else if (rc < 0) {
+ pr_err("%s: memory allocation for calibration failed %d\n",
+ __func__, rc);
+ }
+
+ rc = voc_alloc_voip_shared_memory();
+ if (rc < 0) {
+ pr_err("%s: error allocating shared mem err %d\n",
+ __func__, rc);
+ }
+
+
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ rc = snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+
+done:
+ return rc;
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_voip_dt_match[] = {
+ {.compatible = "qcom,msm-voip-dsp"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_voip_dt_match);
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-voip-dsp",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_voip_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = msm_pcm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ memset(&voip_info, 0, sizeof(voip_info));
+ voip_info.mode = MODE_PCM;
+ mutex_init(&voip_info.lock);
+
+ spin_lock_init(&voip_info.dsp_lock);
+ spin_lock_init(&voip_info.dsp_ul_lock);
+
+ init_waitqueue_head(&voip_info.out_wait);
+ init_waitqueue_head(&voip_info.in_wait);
+
+ INIT_LIST_HEAD(&voip_info.in_queue);
+ INIT_LIST_HEAD(&voip_info.free_in_queue);
+ INIT_LIST_HEAD(&voip_info.out_queue);
+ INIT_LIST_HEAD(&voip_info.free_out_queue);
+
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
new file mode 100644
index 0000000..9276231
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -0,0 +1,1035 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <sound/control.h>
+#include <sound/q6adm-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/asound.h>
+#include <sound/q6audio-v2.h>
+#include <sound/tlv.h>
+
+#include "msm-qti-pp-config.h"
+#include "msm-pcm-routing-v2.h"
+
+/* EQUALIZER */
+/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
+#define MAX_EQ_SESSIONS MSM_FRONTEND_DAI_CS_VOICE
+
+enum {
+ EQ_BAND1 = 0,
+ EQ_BAND2,
+ EQ_BAND3,
+ EQ_BAND4,
+ EQ_BAND5,
+ EQ_BAND6,
+ EQ_BAND7,
+ EQ_BAND8,
+ EQ_BAND9,
+ EQ_BAND10,
+ EQ_BAND11,
+ EQ_BAND12,
+ EQ_BAND_MAX,
+};
+
+struct msm_audio_eq_band {
+ uint16_t band_idx; /* The band index, 0 .. 11 */
+ uint32_t filter_type; /* Filter band type */
+ uint32_t center_freq_hz; /* Filter band center frequency */
+ uint32_t filter_gain; /* Filter band initial gain (dB) */
+ /* Range is +12 dB to -12 dB with 1dB increments. */
+ uint32_t q_factor;
+} __packed;
+
+struct msm_audio_eq_stream_config {
+ uint32_t enable; /* Number of consequtive bands specified */
+ uint32_t num_bands;
+ struct msm_audio_eq_band eq_bands[EQ_BAND_MAX];
+} __packed;
+
+/* Audio Sphere data structures */
+struct msm_audio_pp_asphere_state_s {
+ uint32_t enabled;
+ uint32_t strength;
+ uint32_t mode;
+ uint32_t version;
+ int port_id[AFE_MAX_PORTS];
+ int copp_idx[AFE_MAX_PORTS];
+ bool initialized;
+ uint32_t enabled_prev;
+ uint32_t strength_prev;
+};
+
+static struct msm_audio_pp_asphere_state_s asphere_state;
+
+struct msm_audio_eq_stream_config eq_data[MAX_EQ_SESSIONS];
+
+static int msm_route_hfp_vol_control;
+static const DECLARE_TLV_DB_LINEAR(hfp_rx_vol_gain, 0,
+ INT_RX_VOL_MAX_STEPS);
+
+static int msm_route_pri_auxpcm_lb_vol_ctrl;
+static const DECLARE_TLV_DB_LINEAR(pri_auxpcm_lb_vol_gain, 0,
+ INT_RX_VOL_MAX_STEPS);
+
+static int msm_route_sec_auxpcm_lb_vol_ctrl;
+static const DECLARE_TLV_DB_LINEAR(sec_auxpcm_lb_vol_gain, 0,
+ INT_RX_VOL_MAX_STEPS);
+
+static void msm_qti_pp_send_eq_values_(int eq_idx)
+{
+ int result;
+ struct msm_pcm_routing_fdai_data fe_dai;
+ struct audio_client *ac = NULL;
+
+ msm_pcm_routing_get_fedai_info(eq_idx, SESSION_TYPE_RX, &fe_dai);
+ ac = q6asm_get_audio_client(fe_dai.strm_id);
+
+ if (ac == NULL) {
+ pr_err("%s: Could not get audio client for session: %d\n",
+ __func__, fe_dai.strm_id);
+ goto done;
+ }
+
+ result = q6asm_equalizer(ac, &eq_data[eq_idx]);
+
+ if (result < 0)
+ pr_err("%s: Call to ASM equalizer failed, returned = %d\n",
+ __func__, result);
+done:
+ return;
+}
+
+static int msm_qti_pp_get_eq_enable_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int eq_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+
+ if ((eq_idx < 0) || (eq_idx >= MAX_EQ_SESSIONS))
+ return -EINVAL;
+
+ ucontrol->value.integer.value[0] = eq_data[eq_idx].enable;
+
+ pr_debug("%s: EQ #%d enable %d\n", __func__,
+ eq_idx, eq_data[eq_idx].enable);
+ return 0;
+}
+
+static int msm_qti_pp_put_eq_enable_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int eq_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int value = ucontrol->value.integer.value[0];
+
+ if ((eq_idx < 0) || (eq_idx >= MAX_EQ_SESSIONS))
+ return -EINVAL;
+ pr_debug("%s: EQ #%d enable %d\n", __func__,
+ eq_idx, value);
+ eq_data[eq_idx].enable = value;
+ msm_pcm_routing_acquire_lock();
+ msm_qti_pp_send_eq_values_(eq_idx);
+ msm_pcm_routing_release_lock();
+ return 0;
+}
+
+static int msm_qti_pp_get_eq_band_count_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int eq_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+
+ if ((eq_idx < 0) || (eq_idx >= MAX_EQ_SESSIONS))
+ return -EINVAL;
+ ucontrol->value.integer.value[0] = eq_data[eq_idx].num_bands;
+
+ pr_debug("%s: EQ #%d bands %d\n", __func__,
+ eq_idx, eq_data[eq_idx].num_bands);
+ return eq_data[eq_idx].num_bands;
+}
+
+static int msm_qti_pp_put_eq_band_count_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int eq_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int value = ucontrol->value.integer.value[0];
+
+ if ((eq_idx < 0) || (eq_idx >= MAX_EQ_SESSIONS))
+ return -EINVAL;
+
+ pr_debug("%s: EQ #%d bands %d\n", __func__,
+ eq_idx, value);
+ eq_data[eq_idx].num_bands = value;
+ return 0;
+}
+
+static int msm_qti_pp_get_eq_band_audio_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int eq_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ if ((eq_idx < 0) || (eq_idx >= MAX_EQ_SESSIONS) ||
+ (band_idx < EQ_BAND1) || (band_idx >= EQ_BAND_MAX))
+ return -EINVAL;
+
+ ucontrol->value.integer.value[0] =
+ eq_data[eq_idx].eq_bands[band_idx].band_idx;
+ ucontrol->value.integer.value[1] =
+ eq_data[eq_idx].eq_bands[band_idx].filter_type;
+ ucontrol->value.integer.value[2] =
+ eq_data[eq_idx].eq_bands[band_idx].center_freq_hz;
+ ucontrol->value.integer.value[3] =
+ eq_data[eq_idx].eq_bands[band_idx].filter_gain;
+ ucontrol->value.integer.value[4] =
+ eq_data[eq_idx].eq_bands[band_idx].q_factor;
+
+ pr_debug("%s: band_idx = %d\n", __func__,
+ eq_data[eq_idx].eq_bands[band_idx].band_idx);
+ pr_debug("%s: filter_type = %d\n", __func__,
+ eq_data[eq_idx].eq_bands[band_idx].filter_type);
+ pr_debug("%s: center_freq_hz = %d\n", __func__,
+ eq_data[eq_idx].eq_bands[band_idx].center_freq_hz);
+ pr_debug("%s: filter_gain = %d\n", __func__,
+ eq_data[eq_idx].eq_bands[band_idx].filter_gain);
+ pr_debug("%s: q_factor = %d\n", __func__,
+ eq_data[eq_idx].eq_bands[band_idx].q_factor);
+ return 0;
+}
+
+static int msm_qti_pp_put_eq_band_audio_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int eq_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ if ((eq_idx < 0) || (eq_idx >= MAX_EQ_SESSIONS) ||
+ (band_idx < EQ_BAND1) || (band_idx >= EQ_BAND_MAX))
+ return -EINVAL;
+
+ eq_data[eq_idx].eq_bands[band_idx].band_idx =
+ ucontrol->value.integer.value[0];
+ eq_data[eq_idx].eq_bands[band_idx].filter_type =
+ ucontrol->value.integer.value[1];
+ eq_data[eq_idx].eq_bands[band_idx].center_freq_hz =
+ ucontrol->value.integer.value[2];
+ eq_data[eq_idx].eq_bands[band_idx].filter_gain =
+ ucontrol->value.integer.value[3];
+ eq_data[eq_idx].eq_bands[band_idx].q_factor =
+ ucontrol->value.integer.value[4];
+ return 0;
+}
+
+#ifdef CONFIG_QTI_PP
+void msm_qti_pp_send_eq_values(int fedai_id)
+{
+ if (eq_data[fedai_id].enable)
+ msm_qti_pp_send_eq_values_(fedai_id);
+}
+
+/* CUSTOM MIXING */
+int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx,
+ unsigned int session_id,
+ uint16_t op_FL_ip_FL_weight,
+ uint16_t op_FL_ip_FR_weight,
+ uint16_t op_FR_ip_FL_weight,
+ uint16_t op_FR_ip_FR_weight)
+{
+ char *params_value;
+ int *update_params_value32, rc = 0;
+ int16_t *update_params_value16 = 0;
+ uint32_t params_length = CUSTOM_STEREO_PAYLOAD_SIZE * sizeof(uint32_t);
+ uint32_t avail_length = params_length;
+
+ pr_debug("%s: port_id - %d, session id - %d\n", __func__, port_id,
+ session_id);
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value) {
+ pr_err("%s, params memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ update_params_value32 = (int *)params_value;
+ if (avail_length < 2 * sizeof(uint32_t))
+ goto skip_send_cmd;
+ *update_params_value32++ = MTMX_MODULE_ID_DEFAULT_CHMIXER;
+ *update_params_value32++ = DEFAULT_CHMIXER_PARAM_ID_COEFF;
+ avail_length = avail_length - (2 * sizeof(uint32_t));
+
+ update_params_value16 = (int16_t *)update_params_value32;
+ if (avail_length < 10 * sizeof(uint16_t))
+ goto skip_send_cmd;
+ *update_params_value16++ = CUSTOM_STEREO_CMD_PARAM_SIZE;
+ /*for alignment only*/
+ *update_params_value16++ = 0;
+ /*index is 32-bit param in little endian*/
+ *update_params_value16++ = CUSTOM_STEREO_INDEX_PARAM;
+ *update_params_value16++ = 0;
+ /*for stereo mixing num out ch*/
+ *update_params_value16++ = CUSTOM_STEREO_NUM_OUT_CH;
+ /*for stereo mixing num in ch*/
+ *update_params_value16++ = CUSTOM_STEREO_NUM_IN_CH;
+
+ /* Out ch map FL/FR*/
+ *update_params_value16++ = PCM_CHANNEL_FL;
+ *update_params_value16++ = PCM_CHANNEL_FR;
+
+ /* In ch map FL/FR*/
+ *update_params_value16++ = PCM_CHANNEL_FL;
+ *update_params_value16++ = PCM_CHANNEL_FR;
+ avail_length = avail_length - (10 * sizeof(uint16_t));
+ /* weighting coefficients as name suggests,
+ * mixing will be done according to these coefficients
+ */
+ if (avail_length < 4 * sizeof(uint16_t))
+ goto skip_send_cmd;
+ *update_params_value16++ = op_FL_ip_FL_weight;
+ *update_params_value16++ = op_FL_ip_FR_weight;
+ *update_params_value16++ = op_FR_ip_FL_weight;
+ *update_params_value16++ = op_FR_ip_FR_weight;
+ avail_length = avail_length - (4 * sizeof(uint16_t));
+ if (params_length) {
+ rc = adm_set_stereo_to_custom_stereo(port_id,
+ copp_idx,
+ session_id,
+ params_value,
+ params_length);
+ if (rc) {
+ pr_err("%s: send params failed rc=%d\n", __func__, rc);
+ kfree(params_value);
+ return -EINVAL;
+ }
+ }
+ kfree(params_value);
+ return 0;
+skip_send_cmd:
+ pr_err("%s: insufficient memory, send cmd failed\n",
+ __func__);
+ kfree(params_value);
+ return -ENOMEM;
+}
+#endif /* CONFIG_QTI_PP */
+
+/* RMS */
+static int msm_qti_pp_get_rms_value_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ int be_idx = 0, copp_idx;
+ char *param_value;
+ int *update_param_value;
+ uint32_t param_length = sizeof(uint32_t);
+ uint32_t param_payload_len = RMS_PAYLOAD_LEN * sizeof(uint32_t);
+ struct msm_pcm_routing_bdai_data msm_bedai;
+
+ param_value = kzalloc(param_length, GFP_KERNEL);
+ if (!param_value)
+ return -ENOMEM;
+
+ msm_pcm_routing_acquire_lock();
+ for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) {
+ msm_pcm_routing_get_bedai_info(be_idx, &msm_bedai);
+ if (msm_bedai.port_id == SLIMBUS_0_TX)
+ break;
+ }
+ if ((be_idx >= MSM_BACKEND_DAI_MAX) || !msm_bedai.active) {
+ pr_err("%s, back not active to query rms be_idx:%d\n",
+ __func__, be_idx);
+ rc = -EINVAL;
+ goto get_rms_value_err;
+ }
+ copp_idx = adm_get_default_copp_idx(SLIMBUS_0_TX);
+ if ((copp_idx < 0) || (copp_idx > MAX_COPPS_PER_PORT)) {
+ pr_err("%s, no active copp to query rms copp_idx:%d\n",
+ __func__, copp_idx);
+ rc = -EINVAL;
+ goto get_rms_value_err;
+ }
+ rc = adm_get_params(SLIMBUS_0_TX, copp_idx,
+ RMS_MODULEID_APPI_PASSTHRU,
+ RMS_PARAM_FIRST_SAMPLE,
+ param_length + param_payload_len,
+ param_value);
+ if (rc) {
+ pr_err("%s: get parameters failed rc=%d\n", __func__, rc);
+ rc = -EINVAL;
+ goto get_rms_value_err;
+ }
+ update_param_value = (int *)param_value;
+ ucontrol->value.integer.value[0] = update_param_value[0];
+
+ pr_debug("%s: FROM DSP value[0] 0x%x\n",
+ __func__, update_param_value[0]);
+get_rms_value_err:
+ msm_pcm_routing_release_lock();
+ kfree(param_value);
+ return rc;
+}
+
+static int msm_qti_pp_put_rms_value_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* not used */
+ return 0;
+}
+
+/* VOLUME */
+static int msm_route_fm_vol_control;
+static int msm_afe_lb_vol_ctrl;
+static int msm_afe_sec_mi2s_lb_vol_ctrl;
+static int msm_afe_tert_mi2s_lb_vol_ctrl;
+static int msm_afe_quat_mi2s_lb_vol_ctrl;
+static int msm_afe_slimbus_8_lb_vol_ctrl;
+static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
+static const DECLARE_TLV_DB_LINEAR(afe_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
+
+static int msm_qti_pp_get_fm_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_route_fm_vol_control;
+ return 0;
+}
+
+static int msm_qti_pp_set_fm_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ afe_loopback_gain(INT_FM_TX, ucontrol->value.integer.value[0]);
+
+ msm_route_fm_vol_control = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int msm_qti_pp_get_pri_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_afe_lb_vol_ctrl;
+ return 0;
+}
+
+static int msm_qti_pp_set_pri_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ afe_loopback_gain(AFE_PORT_ID_PRIMARY_MI2S_TX,
+ ucontrol->value.integer.value[0]);
+
+ msm_afe_lb_vol_ctrl = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int msm_qti_pp_get_sec_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_afe_sec_mi2s_lb_vol_ctrl;
+ return 0;
+}
+
+static int msm_qti_pp_set_sec_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ afe_loopback_gain(AFE_PORT_ID_SECONDARY_MI2S_TX,
+ ucontrol->value.integer.value[0]);
+ msm_afe_sec_mi2s_lb_vol_ctrl = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int msm_qti_pp_get_tert_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_afe_tert_mi2s_lb_vol_ctrl;
+ return 0;
+}
+
+static int msm_qti_pp_set_tert_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ afe_loopback_gain(AFE_PORT_ID_TERTIARY_MI2S_TX,
+ ucontrol->value.integer.value[0]);
+ msm_afe_tert_mi2s_lb_vol_ctrl = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int msm_qti_pp_get_slimbus_8_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_afe_slimbus_8_lb_vol_ctrl;
+ return 0;
+}
+
+static int msm_qti_pp_set_slimbus_8_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+
+ ret = afe_loopback_gain(SLIMBUS_8_TX,
+ ucontrol->value.integer.value[0]);
+
+ if (ret)
+ pr_err("%s: failed to set LB vol for SLIMBUS_8_TX", __func__);
+ else
+ msm_afe_slimbus_8_lb_vol_ctrl =
+ ucontrol->value.integer.value[0];
+
+ return ret;
+}
+
+static int msm_qti_pp_get_quat_mi2s_fm_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_afe_quat_mi2s_lb_vol_ctrl;
+ return 0;
+}
+
+static int msm_qti_pp_set_quat_mi2s_fm_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ afe_loopback_gain(AFE_PORT_ID_QUATERNARY_MI2S_TX,
+ ucontrol->value.integer.value[0]);
+
+ msm_afe_quat_mi2s_lb_vol_ctrl = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int msm_qti_pp_get_hfp_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_route_hfp_vol_control;
+ return 0;
+}
+
+static int msm_qti_pp_set_hfp_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ afe_loopback_gain(INT_BT_SCO_TX, ucontrol->value.integer.value[0]);
+
+ msm_route_hfp_vol_control = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int msm_qti_pp_get_pri_auxpcm_lb_vol_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_route_pri_auxpcm_lb_vol_ctrl;
+ pr_debug("%s: Volume = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_qti_pp_set_pri_auxpcm_lb_vol_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ afe_loopback_gain(mc->reg, ucontrol->value.integer.value[0]);
+
+ msm_route_pri_auxpcm_lb_vol_ctrl = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int msm_qti_pp_get_sec_auxpcm_lb_vol_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_route_sec_auxpcm_lb_vol_ctrl;
+ pr_debug("%s: Volume = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_qti_pp_set_sec_auxpcm_lb_vol_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ afe_loopback_gain(mc->reg, ucontrol->value.integer.value[0]);
+
+ msm_route_sec_auxpcm_lb_vol_ctrl = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int msm_qti_pp_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
+ int i;
+
+ adm_get_multi_ch_map(channel_map, ADM_PATH_PLAYBACK);
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] =
+ (unsigned int) channel_map[i];
+ return 0;
+}
+
+static int msm_qti_pp_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
+ int i;
+
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ channel_map[i] = (char)(ucontrol->value.integer.value[i]);
+ adm_set_multi_ch_map(channel_map, ADM_PATH_PLAYBACK);
+
+ return 0;
+}
+
+/* Audio Sphere functions */
+
+static void msm_qti_pp_asphere_init_state(void)
+{
+ int i;
+
+ if (asphere_state.initialized)
+ return;
+ asphere_state.initialized = true;
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ asphere_state.port_id[i] = -1;
+ asphere_state.copp_idx[i] = -1;
+ }
+ asphere_state.enabled = 0;
+ asphere_state.strength = 0;
+ asphere_state.mode = 0;
+ asphere_state.version = 0;
+ asphere_state.enabled_prev = 0;
+ asphere_state.strength_prev = 0;
+}
+
+static int msm_qti_pp_asphere_send_params(int port_id, int copp_idx, bool force)
+{
+ char *params_value = NULL;
+ uint32_t *update_params_value = NULL;
+ uint32_t param_size = sizeof(uint32_t) +
+ sizeof(struct adm_param_data_v5);
+ int params_length = 0, param_count = 0, ret = 0;
+ bool set_enable = force ||
+ (asphere_state.enabled != asphere_state.enabled_prev);
+ bool set_strength = asphere_state.enabled == 1 && (set_enable ||
+ (asphere_state.strength != asphere_state.strength_prev));
+
+ if (set_enable)
+ param_count++;
+ if (set_strength)
+ param_count++;
+ params_length = param_count * param_size;
+
+ pr_debug("%s: port_id %d, copp_id %d, forced %d, param_count %d\n",
+ __func__, port_id, copp_idx, force, param_count);
+ pr_debug("%s: enable prev:%u cur:%u, strength prev:%u cur:%u\n",
+ __func__, asphere_state.enabled_prev, asphere_state.enabled,
+ asphere_state.strength_prev, asphere_state.strength);
+
+ if (params_length > 0)
+ params_value = kzalloc(params_length, GFP_KERNEL);
+ if (!params_value) {
+ pr_err("%s, params memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ update_params_value = (uint32_t *)params_value;
+ params_length = 0;
+ if (set_strength) {
+ /* add strength command */
+ *update_params_value++ = AUDPROC_MODULE_ID_AUDIOSPHERE;
+ *update_params_value++ = AUDPROC_PARAM_ID_AUDIOSPHERE_STRENGTH;
+ *update_params_value++ = sizeof(uint32_t);
+ *update_params_value++ = asphere_state.strength;
+ params_length += param_size;
+ }
+ if (set_enable) {
+ /* add enable command */
+ *update_params_value++ = AUDPROC_MODULE_ID_AUDIOSPHERE;
+ *update_params_value++ = AUDPROC_PARAM_ID_AUDIOSPHERE_ENABLE;
+ *update_params_value++ = sizeof(uint32_t);
+ *update_params_value++ = asphere_state.enabled;
+ params_length += param_size;
+ }
+ pr_debug("%s, param length: %d\n", __func__, params_length);
+ if (params_length) {
+ ret = adm_send_params_v5(port_id, copp_idx,
+ params_value, params_length);
+ if (ret) {
+ pr_err("%s: setting param failed with err=%d\n",
+ __func__, ret);
+ kfree(params_value);
+ return -EINVAL;
+ }
+ }
+ kfree(params_value);
+ return 0;
+}
+
+#if defined(CONFIG_QTI_PP) && defined(CONFIG_QTI_PP_AUDIOSPHERE)
+int msm_qti_pp_asphere_init(int port_id, int copp_idx)
+{
+ int index = adm_validate_and_get_port_index(port_id);
+
+ pr_debug("%s, port_id %d, copp_id %d\n", __func__, port_id, copp_idx);
+ if (index < 0) {
+ pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
+ port_id);
+ return -EINVAL;
+ }
+ msm_qti_pp_asphere_init_state();
+
+ asphere_state.port_id[index] = port_id;
+ asphere_state.copp_idx[index] = copp_idx;
+
+ if (asphere_state.enabled)
+ msm_qti_pp_asphere_send_params(port_id, copp_idx, true);
+
+ return 0;
+}
+
+void msm_qti_pp_asphere_deinit(int port_id)
+{
+ int index = adm_validate_and_get_port_index(port_id);
+
+ pr_debug("%s, port_id %d\n", __func__, port_id);
+ if (index < 0) {
+ pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
+ port_id);
+ return;
+ }
+
+ if (asphere_state.port_id[index] == port_id) {
+ asphere_state.port_id[index] = -1;
+ asphere_state.copp_idx[index] = -1;
+ }
+}
+#endif
+
+static int msm_qti_pp_asphere_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ if (!asphere_state.initialized)
+ return -EAGAIN;
+ ucontrol->value.integer.value[0] = asphere_state.enabled;
+ ucontrol->value.integer.value[1] = asphere_state.strength;
+ pr_debug("%s, enable %u, strength %u\n", __func__,
+ asphere_state.enabled, asphere_state.strength);
+ return 0;
+}
+
+static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int32_t enable = ucontrol->value.integer.value[0];
+ int32_t strength = ucontrol->value.integer.value[1];
+ int i;
+
+ pr_debug("%s, enable %u, strength %u\n", __func__, enable, strength);
+
+ msm_qti_pp_asphere_init_state();
+
+ if (enable == 0 || enable == 1) {
+ asphere_state.enabled_prev = asphere_state.enabled;
+ asphere_state.enabled = enable;
+ }
+
+ if (strength >= 0 && strength <= 1000) {
+ asphere_state.strength_prev = asphere_state.strength;
+ asphere_state.strength = strength;
+ }
+
+ if (asphere_state.strength != asphere_state.strength_prev ||
+ asphere_state.enabled != asphere_state.enabled_prev) {
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ if (asphere_state.port_id[i] >= 0)
+ msm_qti_pp_asphere_send_params(
+ asphere_state.port_id[i],
+ asphere_state.copp_idx[i],
+ false);
+ }
+ }
+ return 0;
+}
+
+static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_qti_pp_get_fm_vol_mixer,
+ msm_qti_pp_set_fm_vol_mixer, fm_rx_vol_gain),
+ SOC_SINGLE_EXT_TLV("Quat MI2S FM RX Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_qti_pp_get_quat_mi2s_fm_vol_mixer,
+ msm_qti_pp_set_quat_mi2s_fm_vol_mixer, fm_rx_vol_gain),
+};
+
+static const struct snd_kcontrol_new pri_mi2s_lb_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("PRI MI2S LOOPBACK Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_qti_pp_get_pri_mi2s_lb_vol_mixer,
+ msm_qti_pp_set_pri_mi2s_lb_vol_mixer, afe_lb_vol_gain),
+};
+
+static const struct snd_kcontrol_new sec_mi2s_lb_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("SEC MI2S LOOPBACK Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_qti_pp_get_sec_mi2s_lb_vol_mixer,
+ msm_qti_pp_set_sec_mi2s_lb_vol_mixer, afe_lb_vol_gain),
+};
+
+static const struct snd_kcontrol_new tert_mi2s_lb_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("Tert MI2S LOOPBACK Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_qti_pp_get_tert_mi2s_lb_vol_mixer,
+ msm_qti_pp_set_tert_mi2s_lb_vol_mixer, afe_lb_vol_gain),
+};
+
+static const struct snd_kcontrol_new slimbus_8_lb_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("SLIMBUS_8 LOOPBACK Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_qti_pp_get_slimbus_8_lb_vol_mixer,
+ msm_qti_pp_set_slimbus_8_lb_vol_mixer, afe_lb_vol_gain),
+};
+
+static const struct snd_kcontrol_new int_hfp_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("Internal HFP RX Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_qti_pp_get_hfp_vol_mixer,
+ msm_qti_pp_set_hfp_vol_mixer, hfp_rx_vol_gain),
+};
+
+static const struct snd_kcontrol_new pri_auxpcm_lb_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("PRI AUXPCM LOOPBACK Volume",
+ AFE_PORT_ID_PRIMARY_PCM_TX, 0, INT_RX_VOL_GAIN, 0,
+ msm_qti_pp_get_pri_auxpcm_lb_vol_mixer,
+ msm_qti_pp_set_pri_auxpcm_lb_vol_mixer,
+ pri_auxpcm_lb_vol_gain),
+};
+
+static const struct snd_kcontrol_new sec_auxpcm_lb_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("SEC AUXPCM LOOPBACK Volume",
+ AFE_PORT_ID_SECONDARY_PCM_TX, 0, INT_RX_VOL_GAIN, 0,
+ msm_qti_pp_get_sec_auxpcm_lb_vol_mixer,
+ msm_qti_pp_set_sec_auxpcm_lb_vol_mixer,
+ sec_auxpcm_lb_vol_gain),
+};
+
+static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Playback Device Channel Map", SND_SOC_NOPM, 0, 16,
+ 0, 8, msm_qti_pp_get_channel_map_mixer,
+ msm_qti_pp_put_channel_map_mixer),
+};
+
+
+static const struct snd_kcontrol_new get_rms_controls[] = {
+ SOC_SINGLE_EXT("Get RMS", SND_SOC_NOPM, 0, 0xFFFFFFFF,
+ 0, msm_qti_pp_get_rms_value_control, msm_qti_pp_put_rms_value_control),
+};
+
+static const struct snd_kcontrol_new eq_enable_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1 EQ Enable", SND_SOC_NOPM,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_qti_pp_get_eq_enable_mixer,
+ msm_qti_pp_put_eq_enable_mixer),
+ SOC_SINGLE_EXT("MultiMedia2 EQ Enable", SND_SOC_NOPM,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_qti_pp_get_eq_enable_mixer,
+ msm_qti_pp_put_eq_enable_mixer),
+ SOC_SINGLE_EXT("MultiMedia3 EQ Enable", SND_SOC_NOPM,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_qti_pp_get_eq_enable_mixer,
+ msm_qti_pp_put_eq_enable_mixer),
+};
+
+static const struct snd_kcontrol_new eq_band_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1 EQ Band Count", SND_SOC_NOPM,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 11, 0,
+ msm_qti_pp_get_eq_band_count_audio_mixer,
+ msm_qti_pp_put_eq_band_count_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2 EQ Band Count", SND_SOC_NOPM,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 11, 0,
+ msm_qti_pp_get_eq_band_count_audio_mixer,
+ msm_qti_pp_put_eq_band_count_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3 EQ Band Count", SND_SOC_NOPM,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 11, 0,
+ msm_qti_pp_get_eq_band_count_audio_mixer,
+ msm_qti_pp_put_eq_band_count_audio_mixer),
+};
+
+static const struct snd_kcontrol_new eq_coeff_mixer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band1", EQ_BAND1,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band2", EQ_BAND2,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band3", EQ_BAND3,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band4", EQ_BAND4,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band5", EQ_BAND5,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band6", EQ_BAND6,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band7", EQ_BAND7,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band8", EQ_BAND8,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band9", EQ_BAND9,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band10", EQ_BAND10,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band11", EQ_BAND11,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band12", EQ_BAND12,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band1", EQ_BAND1,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band2", EQ_BAND2,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band3", EQ_BAND3,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band4", EQ_BAND4,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band5", EQ_BAND5,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band6", EQ_BAND6,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band7", EQ_BAND7,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band8", EQ_BAND8,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band9", EQ_BAND9,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band10", EQ_BAND10,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band11", EQ_BAND11,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band12", EQ_BAND12,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band1", EQ_BAND1,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band2", EQ_BAND2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band3", EQ_BAND3,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band4", EQ_BAND4,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band5", EQ_BAND5,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band6", EQ_BAND6,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band7", EQ_BAND7,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band8", EQ_BAND8,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band9", EQ_BAND9,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band10", EQ_BAND10,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band11", EQ_BAND11,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band12", EQ_BAND12,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+ msm_qti_pp_get_eq_band_audio_mixer, msm_qti_pp_put_eq_band_audio_mixer),
+};
+
+static const struct snd_kcontrol_new asphere_mixer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("MSM ASphere Set Param", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, 2, msm_qti_pp_asphere_get, msm_qti_pp_asphere_set),
+};
+
+#ifdef CONFIG_QTI_PP
+void msm_qti_pp_add_controls(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, int_fm_vol_mixer_controls,
+ ARRAY_SIZE(int_fm_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, pri_mi2s_lb_vol_mixer_controls,
+ ARRAY_SIZE(pri_mi2s_lb_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, sec_mi2s_lb_vol_mixer_controls,
+ ARRAY_SIZE(sec_mi2s_lb_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, tert_mi2s_lb_vol_mixer_controls,
+ ARRAY_SIZE(tert_mi2s_lb_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, slimbus_8_lb_vol_mixer_controls,
+ ARRAY_SIZE(slimbus_8_lb_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, int_hfp_vol_mixer_controls,
+ ARRAY_SIZE(int_hfp_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ pri_auxpcm_lb_vol_mixer_controls,
+ ARRAY_SIZE(pri_auxpcm_lb_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ sec_auxpcm_lb_vol_mixer_controls,
+ ARRAY_SIZE(sec_auxpcm_lb_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ multi_ch_channel_map_mixer_controls,
+ ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, get_rms_controls,
+ ARRAY_SIZE(get_rms_controls));
+
+ snd_soc_add_platform_controls(platform, eq_enable_mixer_controls,
+ ARRAY_SIZE(eq_enable_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, eq_band_mixer_controls,
+ ARRAY_SIZE(eq_band_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, eq_coeff_mixer_controls,
+ ARRAY_SIZE(eq_coeff_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, asphere_mixer_controls,
+ ARRAY_SIZE(asphere_mixer_controls));
+}
+#endif /* CONFIG_QTI_PP */
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
new file mode 100644
index 0000000..805fb3e
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_QTI_PP_H_
+#define _MSM_QTI_PP_H_
+
+#include <sound/soc.h>
+
+#ifdef CONFIG_QTI_PP
+void msm_qti_pp_send_eq_values(int fedai_id);
+int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx,
+ unsigned int session_id,
+ uint16_t op_FL_ip_FL_weight,
+ uint16_t op_FL_ip_FR_weight,
+ uint16_t op_FR_ip_FL_weight,
+ uint16_t op_FR_ip_FR_weight);
+void msm_qti_pp_add_controls(struct snd_soc_platform *platform);
+#else /* CONFIG_QTI_PP */
+#define msm_qti_pp_send_eq_values(fedai_id) do {} while (0)
+#define msm_qti_pp_send_stereo_to_custom_stereo_cmd(port_id, copp_idx, \
+ session_id, op_FL_ip_FL_weight, op_FL_ip_FR_weight, \
+ op_FR_ip_FL_weight, op_FR_ip_FR_weight) (0)
+#define msm_qti_pp_add_controls(platform) do {} while (0)
+#endif /* CONFIG_QTI_PP */
+
+
+#if defined(CONFIG_QTI_PP) && defined(CONFIG_QTI_PP_AUDIOSPHERE)
+int msm_qti_pp_asphere_init(int port_id, int copp_idx);
+void msm_qti_pp_asphere_deinit(int port_id);
+#else
+#define msm_qti_pp_asphere_init(port_id, copp_idx) (0)
+#define msm_qti_pp_asphere_deinit(port_id) do {} while (0)
+#endif
+
+#endif /* _MSM_QTI_PP_H_ */
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
new file mode 100644
index 0000000..26d2b80
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -0,0 +1,4407 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/wait.h>
+#include <linux/qdsp6v2/apr.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6adm-v2.h>
+#include <sound/q6audio-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/audio_cal_utils.h>
+#include <sound/asound.h>
+#include <sound/msm-dts-eagle.h>
+#include "msm-dts-srs-tm-config.h"
+#include <sound/adsp_err.h>
+
+#define TIMEOUT_MS 1000
+
+#define RESET_COPP_ID 99
+#define INVALID_COPP_ID 0xFF
+/* Used for inband payload copy, max size is 4k */
+/* 2 is to account for module & param ID in payload */
+#define ADM_GET_PARAMETER_LENGTH (4096 - APR_HDR_SIZE - 2 * sizeof(uint32_t))
+
+#define ULL_SUPPORTED_BITS_PER_SAMPLE 16
+#define ULL_SUPPORTED_SAMPLE_RATE 48000
+
+/* ENUM for adm_status */
+enum adm_cal_status {
+ ADM_STATUS_CALIBRATION_REQUIRED = 0,
+ ADM_STATUS_MAX,
+};
+
+struct adm_copp {
+
+ atomic_t id[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t cnt[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t topology[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t mode[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t stat[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t rate[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t bit_width[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t channels[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t app_type[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t acdb_id[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ wait_queue_head_t wait[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ wait_queue_head_t adm_delay_wait[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ atomic_t adm_delay_stat[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ uint32_t adm_delay[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+ unsigned long adm_status[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
+};
+
+struct source_tracking_data {
+ struct ion_client *ion_client;
+ struct ion_handle *ion_handle;
+ struct param_outband memmap;
+ int apr_cmd_status;
+};
+
+struct adm_ctl {
+ void *apr;
+
+ struct adm_copp copp;
+
+ atomic_t matrix_map_stat;
+ wait_queue_head_t matrix_map_wait;
+
+ atomic_t adm_stat;
+ wait_queue_head_t adm_wait;
+
+ struct cal_type_data *cal_data[ADM_MAX_CAL_TYPES];
+
+ atomic_t mem_map_handles[ADM_MEM_MAP_INDEX_MAX];
+ atomic_t mem_map_index;
+
+ struct param_outband outband_memmap;
+ struct source_tracking_data sourceTrackingData;
+
+ int set_custom_topology;
+ int ec_ref_rx;
+};
+
+static struct adm_ctl this_adm;
+
+struct adm_multi_ch_map {
+ bool set_channel_map;
+ char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+};
+
+#define ADM_MCH_MAP_IDX_PLAYBACK 0
+#define ADM_MCH_MAP_IDX_REC 1
+static struct adm_multi_ch_map multi_ch_maps[2] = {
+ { false,
+ {0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ { false,
+ {0, 0, 0, 0, 0, 0, 0, 0}
+ }
+};
+
+static int adm_get_parameters[MAX_COPPS_PER_PORT * ADM_GET_PARAMETER_LENGTH];
+static int adm_module_topo_list[
+ MAX_COPPS_PER_PORT * ADM_GET_TOPO_MODULE_LIST_LENGTH];
+
+int adm_validate_and_get_port_index(int port_id)
+{
+ int index;
+ int ret;
+
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port validation failed id 0x%x ret %d\n",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ index = afe_get_port_index(port_id);
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: Invalid port idx %d port_id 0x%x\n",
+ __func__, index,
+ port_id);
+ return -EINVAL;
+ }
+ pr_debug("%s: port_idx- %d\n", __func__, index);
+ return index;
+}
+
+int adm_get_default_copp_idx(int port_id)
+{
+ int port_idx = adm_validate_and_get_port_index(port_id), idx;
+
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port id: 0x%x", __func__, port_id);
+ return -EINVAL;
+ }
+ pr_debug("%s: port_idx:%d\n", __func__, port_idx);
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
+ if (atomic_read(&this_adm.copp.id[port_idx][idx]) !=
+ RESET_COPP_ID)
+ return idx;
+ }
+ return -EINVAL;
+}
+
+int adm_get_topology_for_port_from_copp_id(int port_id, int copp_id)
+{
+ int port_idx = adm_validate_and_get_port_index(port_id), idx;
+
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port id: 0x%x", __func__, port_id);
+ return 0;
+ }
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++)
+ if (atomic_read(&this_adm.copp.id[port_idx][idx]) == copp_id)
+ return atomic_read(&this_adm.copp.topology[port_idx]
+ [idx]);
+ pr_err("%s: Invalid copp_id %d port_id 0x%x\n",
+ __func__, copp_id, port_id);
+ return 0;
+}
+
+int adm_get_topology_for_port_copp_idx(int port_id, int copp_idx)
+{
+ int port_idx = adm_validate_and_get_port_index(port_id);
+
+ if (port_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid port: 0x%x copp id: 0x%x",
+ __func__, port_id, copp_idx);
+ return 0;
+ }
+ return atomic_read(&this_adm.copp.topology[port_idx][copp_idx]);
+}
+
+int adm_get_indexes_from_copp_id(int copp_id, int *copp_idx, int *port_idx)
+{
+ int p_idx, c_idx;
+
+ for (p_idx = 0; p_idx < AFE_MAX_PORTS; p_idx++) {
+ for (c_idx = 0; c_idx < MAX_COPPS_PER_PORT; c_idx++) {
+ if (atomic_read(&this_adm.copp.id[p_idx][c_idx])
+ == copp_id) {
+ if (copp_idx != NULL)
+ *copp_idx = c_idx;
+ if (port_idx != NULL)
+ *port_idx = p_idx;
+ return 0;
+ }
+ }
+ }
+ return -EINVAL;
+}
+
+static int adm_get_copp_id(int port_idx, int copp_idx)
+{
+ pr_debug("%s: port_idx:%d copp_idx:%d\n", __func__, port_idx, copp_idx);
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+ return atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+}
+
+static int adm_get_idx_if_copp_exists(int port_idx, int topology, int mode,
+ int rate, int bit_width, int app_type)
+{
+ int idx;
+
+ pr_debug("%s: port_idx-%d, topology-0x%x, mode-%d, rate-%d, bit_width-%d\n",
+ __func__, port_idx, topology, mode, rate, bit_width);
+
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++)
+ if ((topology ==
+ atomic_read(&this_adm.copp.topology[port_idx][idx])) &&
+ (mode == atomic_read(&this_adm.copp.mode[port_idx][idx])) &&
+ (rate == atomic_read(&this_adm.copp.rate[port_idx][idx])) &&
+ (bit_width ==
+ atomic_read(&this_adm.copp.bit_width[port_idx][idx])) &&
+ (app_type ==
+ atomic_read(&this_adm.copp.app_type[port_idx][idx])))
+ return idx;
+ return -EINVAL;
+}
+
+static int adm_get_next_available_copp(int port_idx)
+{
+ int idx;
+
+ pr_debug("%s:\n", __func__);
+ for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
+ pr_debug("%s: copp_id:0x%x port_idx:%d idx:%d\n", __func__,
+ atomic_read(&this_adm.copp.id[port_idx][idx]),
+ port_idx, idx);
+ if (atomic_read(&this_adm.copp.id[port_idx][idx]) ==
+ RESET_COPP_ID)
+ break;
+ }
+ return idx;
+}
+
+int adm_dts_eagle_set(int port_id, int copp_idx, int param_id,
+ void *data, uint32_t size)
+{
+ struct adm_cmd_set_pp_params_v5 admp;
+ int p_idx, ret = 0, *ob_params;
+
+ pr_debug("DTS_EAGLE_ADM: %s - port id %i, copp idx %i, param id 0x%X size %u\n",
+ __func__, port_id, copp_idx, param_id, size);
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ p_idx = adm_validate_and_get_port_index(port_id);
+ pr_debug("DTS_EAGLE_ADM: %s - after lookup, port id %i, port idx %i\n",
+ __func__, port_id, p_idx);
+
+ if (p_idx < 0) {
+ pr_err("DTS_EAGLE_ADM: %s: invalid port index 0x%x, port id 0x%x\n",
+ __func__, p_idx, port_id);
+ return -EINVAL;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("DTS_EAGLE_ADM: %s: Invalid copp_idx: %d\n", __func__,
+ copp_idx);
+ return -EINVAL;
+ }
+
+ ob_params = (int *)this_adm.outband_memmap.kvaddr;
+ if (ob_params == NULL) {
+ pr_err("DTS_EAGLE_ADM: %s - NULL memmap. Non Eagle topology selected?\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* check for integer overflow */
+ if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
+ ret = -EINVAL;
+ if ((ret < 0) ||
+ (size + APR_CMD_OB_HDR_SZ > this_adm.outband_memmap.size)) {
+ pr_err("DTS_EAGLE_ADM - %s: ion alloc of size %zu too small for size requested %u\n",
+ __func__, this_adm.outband_memmap.size,
+ size + APR_CMD_OB_HDR_SZ);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ *ob_params++ = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
+ *ob_params++ = param_id;
+ *ob_params++ = size;
+ memcpy(ob_params, data, size);
+
+ admp.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ admp.hdr.pkt_size = sizeof(admp);
+ admp.hdr.src_svc = APR_SVC_ADM;
+ admp.hdr.src_domain = APR_DOMAIN_APPS;
+ admp.hdr.src_port = port_id;
+ admp.hdr.dest_svc = APR_SVC_ADM;
+ admp.hdr.dest_domain = APR_DOMAIN_ADSP;
+ admp.hdr.dest_port = atomic_read(&this_adm.copp.id[p_idx][copp_idx]);
+ admp.hdr.token = p_idx << 16 | copp_idx;
+ admp.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ admp.payload_addr_lsw = lower_32_bits(this_adm.outband_memmap.paddr);
+ admp.payload_addr_msw = msm_audio_populate_upper_32_bits(
+ this_adm.outband_memmap.paddr);
+ admp.mem_map_handle = atomic_read(&this_adm.mem_map_handles[
+ ADM_DTS_EAGLE]);
+ admp.payload_size = size + sizeof(struct adm_param_data_v5);
+
+ pr_debug("DTS_EAGLE_ADM: %s - Command was sent now check Q6 - port id = %d, size %d, module id %x, param id %x.\n",
+ __func__, admp.hdr.dest_port,
+ admp.payload_size, AUDPROC_MODULE_ID_DTS_HPX_POSTMIX,
+ param_id);
+ atomic_set(&this_adm.copp.stat[p_idx][copp_idx], -1);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&admp);
+ if (ret < 0) {
+ pr_err("DTS_EAGLE_ADM: %s - ADM enable for port %d failed\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_adm.copp.wait[p_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("DTS_EAGLE_ADM: %s - set params timed out port = %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ } else if (atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx])));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx]));
+ } else {
+ ret = 0;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+int adm_dts_eagle_get(int port_id, int copp_idx, int param_id,
+ void *data, uint32_t size)
+{
+ struct adm_cmd_get_pp_params_v5 admp;
+ int p_idx, ret = 0, *ob_params;
+ uint32_t orig_size = size;
+
+ pr_debug("DTS_EAGLE_ADM: %s - port id %i, copp idx %i, param id 0x%X\n",
+ __func__, port_id, copp_idx, param_id);
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ p_idx = adm_validate_and_get_port_index(port_id);
+ if (p_idx < 0) {
+ pr_err("DTS_EAGLE_ADM: %s - invalid port index %i, port id %i, copp idx %i\n",
+ __func__, p_idx, port_id, copp_idx);
+ return -EINVAL;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("DTS_EAGLE_ADM: %s: Invalid copp_idx: %d\n", __func__,
+ copp_idx);
+ return -EINVAL;
+ }
+
+ if ((size == 0) || !data) {
+ pr_err("DTS_EAGLE_ADM: %s - invalid size %u or pointer %pK.\n",
+ __func__, size, data);
+ return -EINVAL;
+ }
+
+ size = (size+3) & 0xFFFFFFFC;
+
+ ob_params = (int *)(this_adm.outband_memmap.kvaddr);
+ if (ob_params == NULL) {
+ pr_err("DTS_EAGLE_ADM: %s - NULL memmap. Non Eagle topology selected?",
+ __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* check for integer overflow */
+ if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
+ ret = -EINVAL;
+ if ((ret < 0) ||
+ (size + APR_CMD_OB_HDR_SZ > this_adm.outband_memmap.size)) {
+ pr_err("DTS_EAGLE_ADM - %s: ion alloc of size %zu too small for size requested %u\n",
+ __func__, this_adm.outband_memmap.size,
+ size + APR_CMD_OB_HDR_SZ);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ *ob_params++ = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
+ *ob_params++ = param_id;
+ *ob_params++ = size;
+
+ admp.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ admp.hdr.pkt_size = sizeof(admp);
+ admp.hdr.src_svc = APR_SVC_ADM;
+ admp.hdr.src_domain = APR_DOMAIN_APPS;
+ admp.hdr.src_port = port_id;
+ admp.hdr.dest_svc = APR_SVC_ADM;
+ admp.hdr.dest_domain = APR_DOMAIN_ADSP;
+ admp.hdr.dest_port = atomic_read(&this_adm.copp.id[p_idx][copp_idx]);
+ admp.hdr.token = p_idx << 16 | copp_idx;
+ admp.hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5;
+ admp.data_payload_addr_lsw =
+ lower_32_bits(this_adm.outband_memmap.paddr);
+ admp.data_payload_addr_msw =
+ msm_audio_populate_upper_32_bits(
+ this_adm.outband_memmap.paddr);
+ admp.mem_map_handle = atomic_read(&this_adm.mem_map_handles[
+ ADM_DTS_EAGLE]);
+ admp.module_id = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
+ admp.param_id = param_id;
+ admp.param_max_size = size + sizeof(struct adm_param_data_v5);
+ admp.reserved = 0;
+
+ atomic_set(&this_adm.copp.stat[p_idx][copp_idx], -1);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&admp);
+ if (ret < 0) {
+ pr_err("DTS_EAGLE_ADM: %s - Failed to get EAGLE Params on port %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_adm.copp.wait[p_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("DTS_EAGLE_ADM: %s - EAGLE get params timed out port = %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx])));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx]));
+ goto fail_cmd;
+ }
+
+ memcpy(data, ob_params, orig_size);
+ ret = 0;
+fail_cmd:
+ return ret;
+}
+
+int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
+ void *srs_params)
+{
+ struct adm_cmd_set_pp_params_inband_v5 *adm_params = NULL;
+ struct adm_cmd_set_pp_params_v5 *adm_params_ = NULL;
+ __s32 sz = 0, param_id, module_id = SRS_TRUMEDIA_MODULE_ID, outband = 0;
+ int ret = 0, port_idx;
+
+ pr_debug("SRS - %s", __func__);
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ return -EINVAL;
+ }
+ switch (srs_tech_id) {
+ case SRS_ID_GLOBAL: {
+ struct srs_trumedia_params_GLOBAL *glb_params = NULL;
+
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_GLOBAL);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_GLOBAL) +
+ sizeof(struct adm_param_data_v5);
+ param_id = SRS_TRUMEDIA_PARAMS;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_GLOBAL);
+ glb_params = (struct srs_trumedia_params_GLOBAL *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(glb_params, srs_params,
+ sizeof(struct srs_trumedia_params_GLOBAL));
+ break;
+ }
+ case SRS_ID_WOWHD: {
+ struct srs_trumedia_params_WOWHD *whd_params = NULL;
+
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_WOWHD);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_WOWHD) +
+ sizeof(struct adm_param_data_v5);
+ param_id = SRS_TRUMEDIA_PARAMS_WOWHD;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_WOWHD);
+ whd_params = (struct srs_trumedia_params_WOWHD *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(whd_params, srs_params,
+ sizeof(struct srs_trumedia_params_WOWHD));
+ break;
+ }
+ case SRS_ID_CSHP: {
+ struct srs_trumedia_params_CSHP *chp_params = NULL;
+
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_CSHP);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_CSHP) +
+ sizeof(struct adm_param_data_v5);
+ param_id = SRS_TRUMEDIA_PARAMS_CSHP;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_CSHP);
+ chp_params = (struct srs_trumedia_params_CSHP *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(chp_params, srs_params,
+ sizeof(struct srs_trumedia_params_CSHP));
+ break;
+ }
+ case SRS_ID_HPF: {
+ struct srs_trumedia_params_HPF *hpf_params = NULL;
+
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_HPF);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_HPF) +
+ sizeof(struct adm_param_data_v5);
+ param_id = SRS_TRUMEDIA_PARAMS_HPF;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_HPF);
+ hpf_params = (struct srs_trumedia_params_HPF *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(hpf_params, srs_params,
+ sizeof(struct srs_trumedia_params_HPF));
+ break;
+ }
+ case SRS_ID_AEQ: {
+ int *update_params_ptr = (int *)this_adm.outband_memmap.kvaddr;
+
+ outband = 1;
+ adm_params = kzalloc(sizeof(struct adm_cmd_set_pp_params_v5),
+ GFP_KERNEL);
+ adm_params_ = (struct adm_cmd_set_pp_params_v5 *)adm_params;
+ if (!adm_params_) {
+ pr_err("%s, adm params memory alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ sz = sizeof(struct srs_trumedia_params_AEQ);
+ if (update_params_ptr == NULL) {
+ pr_err("ADM_SRS_TRUMEDIA - %s: null memmap for AEQ params\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ param_id = SRS_TRUMEDIA_PARAMS_AEQ;
+ *update_params_ptr++ = module_id;
+ *update_params_ptr++ = param_id;
+ *update_params_ptr++ = sz;
+ memcpy(update_params_ptr, srs_params, sz);
+
+ adm_params_->payload_size = sz + 12;
+
+ break;
+ }
+ case SRS_ID_HL: {
+ struct srs_trumedia_params_HL *hl_params = NULL;
+
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_HL);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_HL) +
+ sizeof(struct adm_param_data_v5);
+ param_id = SRS_TRUMEDIA_PARAMS_HL;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_HL);
+ hl_params = (struct srs_trumedia_params_HL *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(hl_params, srs_params,
+ sizeof(struct srs_trumedia_params_HL));
+ break;
+ }
+ case SRS_ID_GEQ: {
+ struct srs_trumedia_params_GEQ *geq_params = NULL;
+
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_GEQ);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_GEQ) +
+ sizeof(struct adm_param_data_v5);
+ param_id = SRS_TRUMEDIA_PARAMS_GEQ;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_GEQ);
+ geq_params = (struct srs_trumedia_params_GEQ *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(geq_params, srs_params,
+ sizeof(struct srs_trumedia_params_GEQ));
+ pr_debug("SRS - %s: GEQ params prepared\n", __func__);
+ break;
+ }
+ default:
+ goto fail_cmd;
+ }
+
+ adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_params->hdr.src_svc = APR_SVC_ADM;
+ adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params->hdr.src_port = port_id;
+ adm_params->hdr.dest_svc = APR_SVC_ADM;
+ adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params->hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_params->hdr.token = port_idx << 16 | copp_idx;
+ adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ if (outband && this_adm.outband_memmap.paddr) {
+ adm_params->hdr.pkt_size =
+ sizeof(struct adm_cmd_set_pp_params_v5);
+ adm_params->payload_addr_lsw = lower_32_bits(
+ this_adm.outband_memmap.paddr);
+ adm_params->payload_addr_msw = msm_audio_populate_upper_32_bits(
+ this_adm.outband_memmap.paddr);
+ adm_params->mem_map_handle = atomic_read(&this_adm.
+ mem_map_handles[ADM_SRS_TRUMEDIA]);
+ } else {
+ adm_params->hdr.pkt_size = sz;
+ adm_params->payload_addr_lsw = 0;
+ adm_params->payload_addr_msw = 0;
+ adm_params->mem_map_handle = 0;
+
+ adm_params->params.module_id = module_id;
+ adm_params->params.param_id = param_id;
+ adm_params->params.reserved = 0;
+ }
+
+ pr_debug("SRS - %s: Command was sent now check Q6 - port id = %d, size %d, module id %x, param id %x.\n",
+ __func__, adm_params->hdr.dest_port,
+ adm_params->payload_size, module_id, param_id);
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+ if (ret < 0) {
+ pr_err("SRS - %s: ADM enable for port %d failed\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback with copp id */
+ ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: SRS set params timed out port = %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ kfree(adm_params);
+ return ret;
+}
+
+int adm_set_stereo_to_custom_stereo(int port_id, int copp_idx,
+ unsigned int session_id, char *params,
+ uint32_t params_length)
+{
+ struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL;
+ int sz, rc = 0, port_idx;
+
+ pr_debug("%s:\n", __func__);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) +
+ params_length;
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5)),
+ params, params_length);
+ adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_params->hdr.pkt_size = sz;
+ adm_params->hdr.src_svc = APR_SVC_ADM;
+ adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params->hdr.src_port = port_id;
+ adm_params->hdr.dest_svc = APR_SVC_ADM;
+ adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params->hdr.dest_port = 0; /* Ignored */;
+ adm_params->hdr.token = port_idx << 16 | copp_idx;
+ adm_params->hdr.opcode = ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5;
+ adm_params->payload_addr_lsw = 0;
+ adm_params->payload_addr_msw = 0;
+ adm_params->mem_map_handle = 0;
+ adm_params->payload_size = params_length;
+ /* direction RX as 0 */
+ adm_params->direction = ADM_MATRIX_ID_AUDIO_RX;
+ /* session id for this cmd to be applied on */
+ adm_params->sessionid = session_id;
+ adm_params->deviceid =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_params->reserved = 0;
+ pr_debug("%s: deviceid %d, session_id %d, src_port %d, dest_port %d\n",
+ __func__, adm_params->deviceid, adm_params->sessionid,
+ adm_params->hdr.src_port, adm_params->hdr.dest_port);
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+ if (rc < 0) {
+ pr_err("%s: Set params failed port = 0x%x rc %d\n",
+ __func__, port_id, rc);
+ rc = -EINVAL;
+ goto set_stereo_to_custom_stereo_return;
+ }
+ /* Wait for the callback */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: Set params timed out port = 0x%x\n", __func__,
+ port_id);
+ rc = -EINVAL;
+ goto set_stereo_to_custom_stereo_return;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n", __func__,
+ adsp_err_get_err_str(atomic_read(
+ &this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto set_stereo_to_custom_stereo_return;
+ }
+ rc = 0;
+set_stereo_to_custom_stereo_return:
+ kfree(adm_params);
+ return rc;
+}
+
+int adm_dolby_dap_send_params(int port_id, int copp_idx, char *params,
+ uint32_t params_length)
+{
+ struct adm_cmd_set_pp_params_v5 *adm_params = NULL;
+ int sz, rc = 0;
+ int port_idx;
+
+ pr_debug("%s:\n", __func__);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct adm_cmd_set_pp_params_v5) + params_length;
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(((u8 *)adm_params + sizeof(struct adm_cmd_set_pp_params_v5)),
+ params, params_length);
+ adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_params->hdr.pkt_size = sz;
+ adm_params->hdr.src_svc = APR_SVC_ADM;
+ adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params->hdr.src_port = port_id;
+ adm_params->hdr.dest_svc = APR_SVC_ADM;
+ adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params->hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_params->hdr.token = port_idx << 16 | copp_idx;
+ adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ adm_params->payload_addr_lsw = 0;
+ adm_params->payload_addr_msw = 0;
+ adm_params->mem_map_handle = 0;
+ adm_params->payload_size = params_length;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+ if (rc < 0) {
+ pr_err("%s: Set params failed port = 0x%x rc %d\n",
+ __func__, port_id, rc);
+ rc = -EINVAL;
+ goto dolby_dap_send_param_return;
+ }
+ /* Wait for the callback */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: Set params timed out port = 0x%x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto dolby_dap_send_param_return;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto dolby_dap_send_param_return;
+ }
+ rc = 0;
+dolby_dap_send_param_return:
+ kfree(adm_params);
+ return rc;
+}
+
+int adm_send_params_v5(int port_id, int copp_idx, char *params,
+ uint32_t params_length)
+{
+ struct adm_cmd_set_pp_params_v5 *adm_params = NULL;
+ int rc = 0;
+ int sz, port_idx;
+
+ pr_debug("%s:\n", __func__);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct adm_cmd_set_pp_params_v5) + params_length;
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(((u8 *)adm_params + sizeof(struct adm_cmd_set_pp_params_v5)),
+ params, params_length);
+ adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_params->hdr.pkt_size = sz;
+ adm_params->hdr.src_svc = APR_SVC_ADM;
+ adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params->hdr.src_port = port_id;
+ adm_params->hdr.dest_svc = APR_SVC_ADM;
+ adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params->hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_params->hdr.token = port_idx << 16 | copp_idx;
+ adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ adm_params->payload_addr_lsw = 0;
+ adm_params->payload_addr_msw = 0;
+ adm_params->mem_map_handle = 0;
+ adm_params->payload_size = params_length;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+ if (rc < 0) {
+ pr_err("%s: Set params failed port = 0x%x rc %d\n",
+ __func__, port_id, rc);
+ rc = -EINVAL;
+ goto send_param_return;
+ }
+ /* Wait for the callback */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: Set params timed out port = 0x%x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto send_param_return;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto send_param_return;
+ }
+ rc = 0;
+send_param_return:
+ kfree(adm_params);
+ return rc;
+}
+
+int adm_get_params_v2(int port_id, int copp_idx, uint32_t module_id,
+ uint32_t param_id, uint32_t params_length,
+ char *params, uint32_t client_id)
+{
+ struct adm_cmd_get_pp_params_v5 *adm_params = NULL;
+ int sz, rc = 0, i = 0;
+ int port_idx, idx;
+ int *params_data = (int *)params;
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct adm_cmd_get_pp_params_v5) + params_length;
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s: adm params memory alloc failed", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(((u8 *)adm_params + sizeof(struct adm_cmd_get_pp_params_v5)),
+ params, params_length);
+ adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_params->hdr.pkt_size = sz;
+ adm_params->hdr.src_svc = APR_SVC_ADM;
+ adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params->hdr.src_port = port_id;
+ adm_params->hdr.dest_svc = APR_SVC_ADM;
+ adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params->hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_params->hdr.token = port_idx << 16 | client_id << 8 | copp_idx;
+ adm_params->hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5;
+ adm_params->data_payload_addr_lsw = 0;
+ adm_params->data_payload_addr_msw = 0;
+ adm_params->mem_map_handle = 0;
+ adm_params->module_id = module_id;
+ adm_params->param_id = param_id;
+ adm_params->param_max_size = params_length;
+ adm_params->reserved = 0;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+ if (rc < 0) {
+ pr_err("%s: Failed to Get Params on port_id 0x%x %d\n",
+ __func__, port_id, rc);
+ rc = -EINVAL;
+ goto adm_get_param_return;
+ }
+ /* Wait for the callback with copp id */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: get params timed out port_id = 0x%x\n", __func__,
+ port_id);
+ rc = -EINVAL;
+ goto adm_get_param_return;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto adm_get_param_return;
+ }
+ idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
+
+ if (adm_get_parameters[idx] < 0) {
+ pr_err("%s: Size is invalid %d\n", __func__,
+ adm_get_parameters[idx]);
+ rc = -EINVAL;
+ goto adm_get_param_return;
+ }
+ if ((params_data) &&
+ (ARRAY_SIZE(adm_get_parameters) >
+ idx) &&
+ (ARRAY_SIZE(adm_get_parameters) >=
+ 1+adm_get_parameters[idx]+idx) &&
+ (params_length/sizeof(uint32_t) >=
+ adm_get_parameters[idx])) {
+ for (i = 0; i < adm_get_parameters[idx]; i++)
+ params_data[i] = adm_get_parameters[1+i+idx];
+
+ } else {
+ pr_err("%s: Get param data not copied! get_param array size %zd, index %d, params array size %zd, index %d\n",
+ __func__, ARRAY_SIZE(adm_get_parameters),
+ (1+adm_get_parameters[idx]+idx),
+ params_length/sizeof(int),
+ adm_get_parameters[idx]);
+ }
+ rc = 0;
+adm_get_param_return:
+ kfree(adm_params);
+
+ return rc;
+}
+
+int adm_get_params(int port_id, int copp_idx, uint32_t module_id,
+ uint32_t param_id, uint32_t params_length, char *params)
+{
+ return adm_get_params_v2(port_id, copp_idx, module_id, param_id,
+ params_length, params, 0);
+}
+
+int adm_get_pp_topo_module_list(int port_id, int copp_idx, int32_t param_length,
+ char *params)
+{
+ struct adm_cmd_get_pp_topo_module_list_t *adm_pp_module_list = NULL;
+ int sz, rc = 0, i = 0;
+ int port_idx, idx;
+ int32_t *params_data = (int32_t *)params;
+ int *topo_list;
+
+ pr_debug("%s : port_id %x", __func__, port_id);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct adm_cmd_get_pp_topo_module_list_t) + param_length;
+ adm_pp_module_list = kzalloc(sz, GFP_KERNEL);
+ if (!adm_pp_module_list) {
+ pr_err("%s, adm params memory alloc failed", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(((u8 *)adm_pp_module_list +
+ sizeof(struct adm_cmd_get_pp_topo_module_list_t)),
+ params, param_length);
+ adm_pp_module_list->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_pp_module_list->hdr.pkt_size = sz;
+ adm_pp_module_list->hdr.src_svc = APR_SVC_ADM;
+ adm_pp_module_list->hdr.src_domain = APR_DOMAIN_APPS;
+ adm_pp_module_list->hdr.src_port = port_id;
+ adm_pp_module_list->hdr.dest_svc = APR_SVC_ADM;
+ adm_pp_module_list->hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_pp_module_list->hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_pp_module_list->hdr.token = port_idx << 16 | copp_idx;
+ adm_pp_module_list->hdr.opcode = ADM_CMD_GET_PP_TOPO_MODULE_LIST;
+ adm_pp_module_list->param_max_size = param_length;
+ /* Payload address and mmap handle set to zero by kzalloc */
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_pp_module_list);
+ if (rc < 0) {
+ pr_err("%s: Failed to Get Params on port %d\n", __func__,
+ port_id);
+ rc = -EINVAL;
+ goto adm_pp_module_list_l;
+ }
+ /* Wait for the callback with copp id */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: get params timed out port = %d\n", __func__,
+ port_id);
+ rc = -EINVAL;
+ goto adm_pp_module_list_l;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto adm_pp_module_list_l;
+ }
+ if (params_data) {
+ idx = ADM_GET_TOPO_MODULE_LIST_LENGTH * copp_idx;
+ topo_list = (int *)(adm_module_topo_list + idx);
+ if (param_length <= ADM_GET_TOPO_MODULE_LIST_LENGTH &&
+ idx <
+ (MAX_COPPS_PER_PORT * ADM_GET_TOPO_MODULE_LIST_LENGTH))
+ memcpy(params_data, topo_list, param_length);
+ else
+ pr_debug("%s: i/p size:%d > MAX param size:%d\n",
+ __func__, param_length,
+ (int)ADM_GET_TOPO_MODULE_LIST_LENGTH);
+ for (i = 1; i <= params_data[0]; i++)
+ pr_debug("module = 0x%x\n", params_data[i]);
+ }
+ rc = 0;
+adm_pp_module_list_l:
+ kfree(adm_pp_module_list);
+ pr_debug("%s : rc = %d ", __func__, rc);
+ return rc;
+}
+static void adm_callback_debug_print(struct apr_client_data *data)
+{
+ uint32_t *payload;
+
+ payload = data->payload;
+
+ if (data->payload_size >= 8)
+ pr_debug("%s: code = 0x%x PL#0[0x%x], PL#1[0x%x], size = %d\n",
+ __func__, data->opcode, payload[0], payload[1],
+ data->payload_size);
+ else if (data->payload_size >= 4)
+ pr_debug("%s: code = 0x%x PL#0[0x%x], size = %d\n",
+ __func__, data->opcode, payload[0],
+ data->payload_size);
+ else
+ pr_debug("%s: code = 0x%x, size = %d\n",
+ __func__, data->opcode, data->payload_size);
+}
+
+int adm_set_multi_ch_map(char *channel_map, int path)
+{
+ int idx;
+
+ if (path == ADM_PATH_PLAYBACK) {
+ idx = ADM_MCH_MAP_IDX_PLAYBACK;
+ } else if (path == ADM_PATH_LIVE_REC) {
+ idx = ADM_MCH_MAP_IDX_REC;
+ } else {
+ pr_err("%s: invalid attempt to set path %d\n", __func__, path);
+ return -EINVAL;
+ }
+
+ memcpy(multi_ch_maps[idx].channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ multi_ch_maps[idx].set_channel_map = true;
+
+ return 0;
+}
+
+int adm_get_multi_ch_map(char *channel_map, int path)
+{
+ int idx;
+
+ if (path == ADM_PATH_PLAYBACK) {
+ idx = ADM_MCH_MAP_IDX_PLAYBACK;
+ } else if (path == ADM_PATH_LIVE_REC) {
+ idx = ADM_MCH_MAP_IDX_REC;
+ } else {
+ pr_err("%s: invalid attempt to get path %d\n", __func__, path);
+ return -EINVAL;
+ }
+
+ if (multi_ch_maps[idx].set_channel_map) {
+ memcpy(channel_map, multi_ch_maps[idx].channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ return 0;
+}
+
+static int32_t adm_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t *payload;
+ int i, j, port_idx, copp_idx, idx, client_id;
+
+ if (data == NULL) {
+ pr_err("%s: data parameter is null\n", __func__);
+ return -EINVAL;
+ }
+
+ payload = data->payload;
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
+ __func__,
+ data->reset_event, data->reset_proc, this_adm.apr);
+ if (this_adm.apr) {
+ apr_reset(this_adm.apr);
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+ atomic_set(&this_adm.copp.id[i][j],
+ RESET_COPP_ID);
+ atomic_set(&this_adm.copp.cnt[i][j], 0);
+ atomic_set(
+ &this_adm.copp.topology[i][j], 0);
+ atomic_set(&this_adm.copp.mode[i][j],
+ 0);
+ atomic_set(&this_adm.copp.stat[i][j],
+ 0);
+ atomic_set(&this_adm.copp.rate[i][j],
+ 0);
+ atomic_set(
+ &this_adm.copp.channels[i][j],
+ 0);
+ atomic_set(
+ &this_adm.copp.bit_width[i][j], 0);
+ atomic_set(
+ &this_adm.copp.app_type[i][j], 0);
+ atomic_set(
+ &this_adm.copp.acdb_id[i][j], 0);
+ this_adm.copp.adm_status[i][j] =
+ ADM_STATUS_CALIBRATION_REQUIRED;
+ }
+ }
+ this_adm.apr = NULL;
+ cal_utils_clear_cal_block_q6maps(ADM_MAX_CAL_TYPES,
+ this_adm.cal_data);
+ mutex_lock(&this_adm.cal_data
+ [ADM_CUSTOM_TOP_CAL]->lock);
+ this_adm.set_custom_topology = 1;
+ mutex_unlock(&this_adm.cal_data[
+ ADM_CUSTOM_TOP_CAL]->lock);
+ rtac_clear_mapping(ADM_RTAC_CAL);
+ /*
+ * Free the ION memory and clear the map handles
+ * for Source Tracking
+ */
+ if (this_adm.sourceTrackingData.memmap.paddr != 0) {
+ msm_audio_ion_free(
+ this_adm.sourceTrackingData.ion_client,
+ this_adm.sourceTrackingData.ion_handle);
+ this_adm.sourceTrackingData.ion_client = NULL;
+ this_adm.sourceTrackingData.ion_handle = NULL;
+ this_adm.sourceTrackingData.memmap.size = 0;
+ this_adm.sourceTrackingData.memmap.kvaddr =
+ NULL;
+ this_adm.sourceTrackingData.memmap.paddr = 0;
+ this_adm.sourceTrackingData.apr_cmd_status = -1;
+ atomic_set(&this_adm.mem_map_handles[
+ ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
+ }
+ }
+ return 0;
+ }
+
+ adm_callback_debug_print(data);
+ if (data->payload_size) {
+ copp_idx = (data->token) & 0XFF;
+ port_idx = ((data->token) >> 16) & 0xFF;
+ client_id = ((data->token) >> 8) & 0xFF;
+ if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
+ pr_err("%s: Invalid port idx %d token %d\n",
+ __func__, port_idx, data->token);
+ return 0;
+ }
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp idx %d token %d\n",
+ __func__, copp_idx, data->token);
+ return 0;
+ }
+ if (client_id < 0 || client_id >= ADM_CLIENT_ID_MAX) {
+ pr_err("%s: Invalid client id %d\n", __func__,
+ client_id);
+ return 0;
+ }
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ pr_debug("%s: APR_BASIC_RSP_RESULT id 0x%x\n",
+ __func__, payload[0]);
+ if (payload[1] != 0) {
+ pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+ __func__, payload[0], payload[1]);
+ }
+ switch (payload[0]) {
+ case ADM_CMD_SET_PP_PARAMS_V5:
+ pr_debug("%s: ADM_CMD_SET_PP_PARAMS_V5\n",
+ __func__);
+ if (client_id == ADM_CLIENT_ID_SOURCE_TRACKING)
+ this_adm.sourceTrackingData.
+ apr_cmd_status = payload[1];
+ else if (rtac_make_adm_callback(payload,
+ data->payload_size))
+ break;
+ /*
+ * if soft volume is called and already
+ * interrupted break out of the sequence here
+ */
+ case ADM_CMD_DEVICE_OPEN_V5:
+ case ADM_CMD_DEVICE_CLOSE_V5:
+ pr_debug("%s: Basic callback received, wake up.\n",
+ __func__);
+ atomic_set(&this_adm.copp.stat[port_idx]
+ [copp_idx], payload[1]);
+ wake_up(
+ &this_adm.copp.wait[port_idx][copp_idx]);
+ break;
+ case ADM_CMD_ADD_TOPOLOGIES:
+ pr_debug("%s: callback received, ADM_CMD_ADD_TOPOLOGIES.\n",
+ __func__);
+ atomic_set(&this_adm.adm_stat, payload[1]);
+ wake_up(&this_adm.adm_wait);
+ break;
+ case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
+ case ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5:
+ pr_debug("%s: Basic callback received, wake up.\n",
+ __func__);
+ atomic_set(&this_adm.matrix_map_stat,
+ payload[1]);
+ wake_up(&this_adm.matrix_map_wait);
+ break;
+ case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
+ pr_debug("%s: ADM_CMD_SHARED_MEM_UNMAP_REGIONS\n",
+ __func__);
+ atomic_set(&this_adm.adm_stat, payload[1]);
+ wake_up(&this_adm.adm_wait);
+ break;
+ case ADM_CMD_SHARED_MEM_MAP_REGIONS:
+ pr_debug("%s: ADM_CMD_SHARED_MEM_MAP_REGIONS\n",
+ __func__);
+ /* Should only come here if there is an APR */
+ /* error or malformed APR packet. Otherwise */
+ /* response will be returned as */
+ if (payload[1] != 0) {
+ pr_err("%s: ADM map error, resuming\n",
+ __func__);
+ atomic_set(&this_adm.adm_stat,
+ payload[1]);
+ wake_up(&this_adm.adm_wait);
+ }
+ break;
+ case ADM_CMD_GET_PP_PARAMS_V5:
+ pr_debug("%s: ADM_CMD_GET_PP_PARAMS_V5\n",
+ __func__);
+ /* Should only come here if there is an APR */
+ /* error or malformed APR packet. Otherwise */
+ /* response will be returned as */
+ /* ADM_CMDRSP_GET_PP_PARAMS_V5 */
+ if (client_id ==
+ ADM_CLIENT_ID_SOURCE_TRACKING) {
+ this_adm.sourceTrackingData.
+ apr_cmd_status = payload[1];
+ if (payload[1] != 0)
+ pr_err("%s: ADM get param error = %d\n",
+ __func__, payload[1]);
+
+ atomic_set(&this_adm.copp.stat
+ [port_idx][copp_idx],
+ payload[1]);
+ wake_up(&this_adm.copp.wait
+ [port_idx][copp_idx]);
+ } else {
+ if (payload[1] != 0) {
+ pr_err("%s: ADM get param error = %d, resuming\n",
+ __func__, payload[1]);
+
+ rtac_make_adm_callback(payload,
+ data->payload_size);
+ }
+ }
+ break;
+ case ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5:
+ pr_debug("%s: ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5\n",
+ __func__);
+ atomic_set(&this_adm.copp.stat[port_idx]
+ [copp_idx], payload[1]);
+ wake_up(
+ &this_adm.copp.wait[port_idx][copp_idx]);
+ break;
+ case ADM_CMD_GET_PP_TOPO_MODULE_LIST:
+ pr_debug("%s:ADM_CMD_GET_PP_TOPO_MODULE_LIST\n",
+ __func__);
+ if (payload[1] != 0)
+ pr_err("%s: ADM get topo list error = %d,\n",
+ __func__, payload[1]);
+ break;
+ default:
+ pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
+ payload[0]);
+ break;
+ }
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case ADM_CMDRSP_DEVICE_OPEN_V5: {
+ struct adm_cmd_rsp_device_open_v5 *open =
+ (struct adm_cmd_rsp_device_open_v5 *)data->payload;
+
+ if (open->copp_id == INVALID_COPP_ID) {
+ pr_err("%s: invalid coppid rxed %d\n",
+ __func__, open->copp_id);
+ atomic_set(&this_adm.copp.stat[port_idx]
+ [copp_idx], ADSP_EBADPARAM);
+ wake_up(
+ &this_adm.copp.wait[port_idx][copp_idx]);
+ break;
+ }
+ atomic_set(&this_adm.copp.stat
+ [port_idx][copp_idx], payload[0]);
+ atomic_set(&this_adm.copp.id[port_idx][copp_idx],
+ open->copp_id);
+ pr_debug("%s: coppid rxed=%d\n", __func__,
+ open->copp_id);
+ wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
+ }
+ break;
+ case ADM_CMDRSP_GET_PP_PARAMS_V5:
+ pr_debug("%s: ADM_CMDRSP_GET_PP_PARAMS_V5\n", __func__);
+ if (payload[0] != 0)
+ pr_err("%s: ADM_CMDRSP_GET_PP_PARAMS_V5 returned error = 0x%x\n",
+ __func__, payload[0]);
+ if (client_id == ADM_CLIENT_ID_SOURCE_TRACKING)
+ this_adm.sourceTrackingData.apr_cmd_status =
+ payload[0];
+ else if (rtac_make_adm_callback(payload,
+ data->payload_size))
+ break;
+
+ idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
+ if ((payload[0] == 0) && (data->payload_size >
+ (4 * sizeof(*payload))) &&
+ (data->payload_size - 4 >=
+ payload[3]) &&
+ (ARRAY_SIZE(adm_get_parameters) >
+ idx) &&
+ (ARRAY_SIZE(adm_get_parameters)-idx-1 >=
+ payload[3])) {
+ adm_get_parameters[idx] = payload[3] /
+ sizeof(uint32_t);
+ /*
+ * payload[3] is param_size which is
+ * expressed in number of bytes
+ */
+ pr_debug("%s: GET_PP PARAM:received parameter length: 0x%x\n",
+ __func__, adm_get_parameters[idx]);
+ /* storing param size then params */
+ for (i = 0; i < payload[3] /
+ sizeof(uint32_t); i++)
+ adm_get_parameters[idx+1+i] =
+ payload[4+i];
+ } else if (payload[0] == 0) {
+ adm_get_parameters[idx] = -1;
+ pr_err("%s: Out of band case, setting size to %d\n",
+ __func__, adm_get_parameters[idx]);
+ } else {
+ adm_get_parameters[idx] = -1;
+ pr_err("%s: GET_PP_PARAMS failed, setting size to %d\n",
+ __func__, adm_get_parameters[idx]);
+ }
+ atomic_set(&this_adm.copp.stat
+ [port_idx][copp_idx], payload[0]);
+ wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
+ break;
+ case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST:
+ pr_debug("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST\n",
+ __func__);
+ if (payload[0] != 0) {
+ pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST",
+ __func__);
+ pr_err(":err = 0x%x\n", payload[0]);
+ } else if (payload[1] >
+ ((ADM_GET_TOPO_MODULE_LIST_LENGTH /
+ sizeof(uint32_t)) - 1)) {
+ pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST",
+ __func__);
+ pr_err(":size = %d\n", payload[1]);
+ } else {
+ idx = ADM_GET_TOPO_MODULE_LIST_LENGTH *
+ copp_idx;
+ pr_debug("%s:Num modules payload[1] %d\n",
+ __func__, payload[1]);
+ adm_module_topo_list[idx] = payload[1];
+ for (i = 1; i <= payload[1]; i++) {
+ adm_module_topo_list[idx+i] =
+ payload[1+i];
+ pr_debug("%s:payload[%d] = %x\n",
+ __func__, (i+1), payload[1+i]);
+ }
+ }
+ atomic_set(&this_adm.copp.stat
+ [port_idx][copp_idx], payload[0]);
+ wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
+ break;
+ case ADM_CMDRSP_SHARED_MEM_MAP_REGIONS:
+ pr_debug("%s: ADM_CMDRSP_SHARED_MEM_MAP_REGIONS\n",
+ __func__);
+ atomic_set(&this_adm.mem_map_handles[
+ atomic_read(&this_adm.mem_map_index)],
+ *payload);
+ atomic_set(&this_adm.adm_stat, 0);
+ wake_up(&this_adm.adm_wait);
+ break;
+ default:
+ pr_err("%s: Unknown cmd:0x%x\n", __func__,
+ data->opcode);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int adm_memory_map_regions(phys_addr_t *buf_add, uint32_t mempool_id,
+ uint32_t *bufsz, uint32_t bufcnt)
+{
+ struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+ struct avs_shared_map_region_payload *mregions = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ int ret = 0;
+ int i = 0;
+ int cmd_size = 0;
+
+ pr_debug("%s:\n", __func__);
+ if (this_adm.apr == NULL) {
+ this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+ 0xFFFFFFFF, &this_adm);
+ if (this_adm.apr == NULL) {
+ pr_err("%s: Unable to register ADM\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_adm_handle(this_adm.apr);
+ }
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
+ + sizeof(struct avs_shared_map_region_payload)
+ * bufcnt;
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (!mmap_region_cmd)
+ return -ENOMEM;
+
+ mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
+ mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mmap_regions->hdr.pkt_size = cmd_size;
+ mmap_regions->hdr.src_port = 0;
+
+ mmap_regions->hdr.dest_port = 0;
+ mmap_regions->hdr.token = 0;
+ mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
+ mmap_regions->num_regions = bufcnt & 0x00ff;
+ mmap_regions->property_flag = 0x00;
+
+ pr_debug("%s: map_regions->num_regions = %d\n", __func__,
+ mmap_regions->num_regions);
+ payload = ((u8 *) mmap_region_cmd +
+ sizeof(struct avs_cmd_shared_mem_map_regions));
+ mregions = (struct avs_shared_map_region_payload *)payload;
+
+ for (i = 0; i < bufcnt; i++) {
+ mregions->shm_addr_lsw = lower_32_bits(buf_add[i]);
+ mregions->shm_addr_msw =
+ msm_audio_populate_upper_32_bits(buf_add[i]);
+ mregions->mem_size_bytes = bufsz[i];
+ ++mregions;
+ }
+
+ atomic_set(&this_adm.adm_stat, -1);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
+ if (ret < 0) {
+ pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+ mmap_regions->hdr.opcode, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_adm.adm_wait,
+ atomic_read(&this_adm.adm_stat) >= 0,
+ 5 * HZ);
+ if (!ret) {
+ pr_err("%s: timeout. waited for memory_map\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.adm_stat) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.adm_stat)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.adm_stat));
+ goto fail_cmd;
+ }
+fail_cmd:
+ kfree(mmap_region_cmd);
+ return ret;
+}
+
+static int adm_memory_unmap_regions(void)
+{
+ struct avs_cmd_shared_mem_unmap_regions unmap_regions;
+ int ret = 0;
+
+ pr_debug("%s:\n", __func__);
+ if (this_adm.apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ unmap_regions.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ unmap_regions.hdr.pkt_size = sizeof(unmap_regions);
+ unmap_regions.hdr.src_port = 0;
+ unmap_regions.hdr.dest_port = 0;
+ unmap_regions.hdr.token = 0;
+ unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
+ unmap_regions.mem_map_handle = atomic_read(&this_adm.
+ mem_map_handles[atomic_read(&this_adm.mem_map_index)]);
+ atomic_set(&this_adm.adm_stat, -1);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
+ if (ret < 0) {
+ pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+ unmap_regions.hdr.opcode, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_adm.adm_wait,
+ atomic_read(&this_adm.adm_stat) >= 0,
+ 5 * HZ);
+ if (!ret) {
+ pr_err("%s: timeout. waited for memory_unmap\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.adm_stat) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.adm_stat)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.adm_stat));
+ goto fail_cmd;
+ } else {
+ pr_debug("%s: Unmap handle 0x%x succeeded\n", __func__,
+ unmap_regions.mem_map_handle);
+ }
+fail_cmd:
+ return ret;
+}
+
+static int remap_cal_data(struct cal_block_data *cal_block, int cal_index)
+{
+ int ret = 0;
+
+ if (cal_block->map_data.ion_client == NULL) {
+ pr_err("%s: No ION allocation for cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((cal_block->map_data.map_size > 0) &&
+ (cal_block->map_data.q6map_handle == 0)) {
+ atomic_set(&this_adm.mem_map_index, cal_index);
+ ret = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
+ (uint32_t *)&cal_block->map_data.map_size, 1);
+ if (ret < 0) {
+ pr_err("%s: ADM mmap did not work! size = %zd ret %d\n",
+ __func__,
+ cal_block->map_data.map_size, ret);
+ pr_debug("%s: ADM mmap did not work! addr = 0x%pK, size = %zd ret %d\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size, ret);
+ goto done;
+ }
+ cal_block->map_data.q6map_handle = atomic_read(&this_adm.
+ mem_map_handles[cal_index]);
+ }
+done:
+ return ret;
+}
+
+static void send_adm_custom_topology(void)
+{
+ struct cal_block_data *cal_block = NULL;
+ struct cmd_set_topologies adm_top;
+ int cal_index = ADM_CUSTOM_TOP_CAL;
+ int result;
+
+ if (this_adm.cal_data[cal_index] == NULL)
+ goto done;
+
+ mutex_lock(&this_adm.cal_data[cal_index]->lock);
+ if (!this_adm.set_custom_topology)
+ goto unlock;
+ this_adm.set_custom_topology = 0;
+
+ cal_block = cal_utils_get_only_cal_block(this_adm.cal_data[cal_index]);
+ if (cal_block == NULL)
+ goto unlock;
+
+ pr_debug("%s: Sending cal_index %d\n", __func__, cal_index);
+
+ result = remap_cal_data(cal_block, cal_index);
+ if (result) {
+ pr_err("%s: Remap_cal_data failed for cal %d!\n",
+ __func__, cal_index);
+ goto unlock;
+ }
+ atomic_set(&this_adm.mem_map_index, cal_index);
+ atomic_set(&this_adm.mem_map_handles[cal_index],
+ cal_block->map_data.q6map_handle);
+
+ if (cal_block->cal_data.size == 0) {
+ pr_debug("%s: No ADM cal to send\n", __func__);
+ goto unlock;
+ }
+
+ adm_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_top.hdr.pkt_size = sizeof(adm_top);
+ adm_top.hdr.src_svc = APR_SVC_ADM;
+ adm_top.hdr.src_domain = APR_DOMAIN_APPS;
+ adm_top.hdr.src_port = 0;
+ adm_top.hdr.dest_svc = APR_SVC_ADM;
+ adm_top.hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_top.hdr.dest_port = 0;
+ adm_top.hdr.token = 0;
+ adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
+ adm_top.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
+ adm_top.payload_addr_msw = msm_audio_populate_upper_32_bits(
+ cal_block->cal_data.paddr);
+ adm_top.mem_map_handle = cal_block->map_data.q6map_handle;
+ adm_top.payload_size = cal_block->cal_data.size;
+
+ atomic_set(&this_adm.adm_stat, -1);
+ pr_debug("%s: Sending ADM_CMD_ADD_TOPOLOGIES payload = 0x%pK, size = %d\n",
+ __func__, &cal_block->cal_data.paddr,
+ adm_top.payload_size);
+ result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_top);
+ if (result < 0) {
+ pr_err("%s: Set topologies failed payload size = %zd result %d\n",
+ __func__, cal_block->cal_data.size, result);
+ goto unlock;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(this_adm.adm_wait,
+ atomic_read(&this_adm.adm_stat) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: Set topologies timed out payload size = %zd\n",
+ __func__, cal_block->cal_data.size);
+ goto unlock;
+ } else if (atomic_read(&this_adm.adm_stat) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.adm_stat)));
+ result = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.adm_stat));
+ goto unlock;
+ }
+unlock:
+ mutex_unlock(&this_adm.cal_data[cal_index]->lock);
+done:
+ return;
+}
+
+static int send_adm_cal_block(int port_id, int copp_idx,
+ struct cal_block_data *cal_block, int perf_mode,
+ int app_type, int acdb_id, int sample_rate)
+{
+ s32 result = 0;
+ struct adm_cmd_set_pp_params_v5 adm_params;
+ int port_idx;
+
+ pr_debug("%s: Port id 0x%x sample_rate %d ,\n", __func__,
+ port_id, sample_rate);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+ if (!cal_block) {
+ pr_debug("%s: No ADM cal to send for port_id = 0x%x!\n",
+ __func__, port_id);
+ result = -EINVAL;
+ goto done;
+ }
+ if (cal_block->cal_data.size <= 0) {
+ pr_debug("%s: No ADM cal send for port_id = 0x%x!\n",
+ __func__, port_id);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (perf_mode == LEGACY_PCM_MODE &&
+ ((atomic_read(&this_adm.copp.topology[port_idx][copp_idx])) ==
+ DS2_ADM_COPP_TOPOLOGY_ID)) {
+ pr_err("%s: perf_mode %d, topology 0x%x\n", __func__, perf_mode,
+ atomic_read(
+ &this_adm.copp.topology[port_idx][copp_idx]));
+ goto done;
+ }
+
+ adm_params.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_params.hdr.pkt_size = sizeof(adm_params);
+ adm_params.hdr.src_svc = APR_SVC_ADM;
+ adm_params.hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params.hdr.src_port = port_id;
+ adm_params.hdr.dest_svc = APR_SVC_ADM;
+ adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
+
+ adm_params.hdr.token = port_idx << 16 | copp_idx;
+ adm_params.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ adm_params.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
+ adm_params.payload_addr_msw = msm_audio_populate_upper_32_bits(
+ cal_block->cal_data.paddr);
+ adm_params.mem_map_handle = cal_block->map_data.q6map_handle;
+ adm_params.payload_size = cal_block->cal_data.size;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ pr_debug("%s: Sending SET_PARAMS payload = 0x%pK, size = %d\n",
+ __func__, &cal_block->cal_data.paddr,
+ adm_params.payload_size);
+ result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
+ if (result < 0) {
+ pr_err("%s: Set params failed port 0x%x result %d\n",
+ __func__, port_id, result);
+ pr_debug("%s: Set params failed port = 0x%x payload = 0x%pK result %d\n",
+ __func__, port_id, &cal_block->cal_data.paddr, result);
+ result = -EINVAL;
+ goto done;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: Set params timed out port = 0x%x\n",
+ __func__, port_id);
+ pr_debug("%s: Set params timed out port = 0x%x, payload = 0x%pK\n",
+ __func__, port_id, &cal_block->cal_data.paddr);
+ result = -EINVAL;
+ goto done;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ result = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto done;
+ }
+
+done:
+ return result;
+}
+
+static struct cal_block_data *adm_find_cal_by_path(int cal_index, int path)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_audproc *audproc_cal_info = NULL;
+ struct audio_cal_info_audvol *audvol_cal_info = NULL;
+
+ pr_debug("%s:\n", __func__);
+
+ list_for_each_safe(ptr, next,
+ &this_adm.cal_data[cal_index]->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ if (cal_index == ADM_AUDPROC_CAL) {
+ audproc_cal_info = cal_block->cal_info;
+ if ((audproc_cal_info->path == path) &&
+ (cal_block->cal_data.size > 0))
+ return cal_block;
+ } else if (cal_index == ADM_AUDVOL_CAL) {
+ audvol_cal_info = cal_block->cal_info;
+ if ((audvol_cal_info->path == path) &&
+ (cal_block->cal_data.size > 0))
+ return cal_block;
+ }
+ }
+ pr_debug("%s: Can't find ADM cal for cal_index %d, path %d\n",
+ __func__, cal_index, path);
+ return NULL;
+}
+
+static struct cal_block_data *adm_find_cal_by_app_type(int cal_index, int path,
+ int app_type)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_audproc *audproc_cal_info = NULL;
+ struct audio_cal_info_audvol *audvol_cal_info = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ list_for_each_safe(ptr, next,
+ &this_adm.cal_data[cal_index]->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ if (cal_index == ADM_AUDPROC_CAL) {
+ audproc_cal_info = cal_block->cal_info;
+ if ((audproc_cal_info->path == path) &&
+ (audproc_cal_info->app_type == app_type) &&
+ (cal_block->cal_data.size > 0))
+ return cal_block;
+ } else if (cal_index == ADM_AUDVOL_CAL) {
+ audvol_cal_info = cal_block->cal_info;
+ if ((audvol_cal_info->path == path) &&
+ (audvol_cal_info->app_type == app_type) &&
+ (cal_block->cal_data.size > 0))
+ return cal_block;
+ }
+ }
+ pr_debug("%s: Can't find ADM cali for cal_index %d, path %d, app %d, defaulting to search by path\n",
+ __func__, cal_index, path, app_type);
+ return adm_find_cal_by_path(cal_index, path);
+}
+
+
+static struct cal_block_data *adm_find_cal(int cal_index, int path,
+ int app_type, int acdb_id,
+ int sample_rate)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_audproc *audproc_cal_info = NULL;
+ struct audio_cal_info_audvol *audvol_cal_info = NULL;
+
+ pr_debug("%s:\n", __func__);
+
+ list_for_each_safe(ptr, next,
+ &this_adm.cal_data[cal_index]->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ if (cal_index == ADM_AUDPROC_CAL) {
+ audproc_cal_info = cal_block->cal_info;
+ if ((audproc_cal_info->path == path) &&
+ (audproc_cal_info->app_type == app_type) &&
+ (audproc_cal_info->acdb_id == acdb_id) &&
+ (audproc_cal_info->sample_rate == sample_rate) &&
+ (cal_block->cal_data.size > 0))
+ return cal_block;
+ } else if (cal_index == ADM_AUDVOL_CAL) {
+ audvol_cal_info = cal_block->cal_info;
+ if ((audvol_cal_info->path == path) &&
+ (audvol_cal_info->app_type == app_type) &&
+ (audvol_cal_info->acdb_id == acdb_id) &&
+ (cal_block->cal_data.size > 0))
+ return cal_block;
+ }
+ }
+ pr_debug("%s: Can't find ADM cal for cal_index %d, path %d, app %d, acdb_id %d sample_rate %d defaulting to search by app type\n",
+ __func__, cal_index, path, app_type, acdb_id, sample_rate);
+ return adm_find_cal_by_app_type(cal_index, path, app_type);
+}
+
+static int adm_remap_and_send_cal_block(int cal_index, int port_id,
+ int copp_idx, struct cal_block_data *cal_block, int perf_mode,
+ int app_type, int acdb_id, int sample_rate)
+{
+ int ret = 0;
+
+ pr_debug("%s: Sending cal_index cal %d\n", __func__, cal_index);
+ ret = remap_cal_data(cal_block, cal_index);
+ if (ret) {
+ pr_err("%s: Remap_cal_data failed for cal %d!\n",
+ __func__, cal_index);
+ goto done;
+ }
+ ret = send_adm_cal_block(port_id, copp_idx, cal_block, perf_mode,
+ app_type, acdb_id, sample_rate);
+ if (ret < 0)
+ pr_debug("%s: No cal sent for cal_index %d, port_id = 0x%x! ret %d sample_rate %d\n",
+ __func__, cal_index, port_id, ret, sample_rate);
+done:
+ return ret;
+}
+
+static void send_adm_cal_type(int cal_index, int path, int port_id,
+ int copp_idx, int perf_mode, int app_type,
+ int acdb_id, int sample_rate)
+{
+ struct cal_block_data *cal_block = NULL;
+ int ret;
+
+ pr_debug("%s: cal index %d\n", __func__, cal_index);
+
+ if (this_adm.cal_data[cal_index] == NULL) {
+ pr_debug("%s: cal_index %d not allocated!\n",
+ __func__, cal_index);
+ goto done;
+ }
+
+ mutex_lock(&this_adm.cal_data[cal_index]->lock);
+ cal_block = adm_find_cal(cal_index, path, app_type, acdb_id,
+ sample_rate);
+ if (cal_block == NULL)
+ goto unlock;
+
+ ret = adm_remap_and_send_cal_block(cal_index, port_id, copp_idx,
+ cal_block, perf_mode, app_type, acdb_id, sample_rate);
+unlock:
+ mutex_unlock(&this_adm.cal_data[cal_index]->lock);
+done:
+ return;
+}
+
+static int get_cal_path(int path)
+{
+ if (path == 0x1)
+ return RX_DEVICE;
+ else
+ return TX_DEVICE;
+}
+
+static void send_adm_cal(int port_id, int copp_idx, int path, int perf_mode,
+ int app_type, int acdb_id, int sample_rate)
+{
+ pr_debug("%s: port id 0x%x copp_idx %d\n", __func__, port_id, copp_idx);
+
+ send_adm_cal_type(ADM_AUDPROC_CAL, path, port_id, copp_idx, perf_mode,
+ app_type, acdb_id, sample_rate);
+ send_adm_cal_type(ADM_AUDVOL_CAL, path, port_id, copp_idx, perf_mode,
+ app_type, acdb_id, sample_rate);
+}
+
+int adm_connect_afe_port(int mode, int session_id, int port_id)
+{
+ struct adm_cmd_connect_afe_port_v5 cmd;
+ int ret = 0;
+ int port_idx, copp_idx = 0;
+
+ pr_debug("%s: port_id: 0x%x session id:%d mode:%d\n", __func__,
+ port_id, session_id, mode);
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ if (this_adm.apr == NULL) {
+ this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+ 0xFFFFFFFF, &this_adm);
+ if (this_adm.apr == NULL) {
+ pr_err("%s: Unable to register ADM\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_adm_handle(this_adm.apr);
+ }
+ pr_debug("%s: Port ID 0x%x, index %d\n", __func__, port_id, port_idx);
+
+ cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cmd.hdr.pkt_size = sizeof(cmd);
+ cmd.hdr.src_svc = APR_SVC_ADM;
+ cmd.hdr.src_domain = APR_DOMAIN_APPS;
+ cmd.hdr.src_port = port_id;
+ cmd.hdr.dest_svc = APR_SVC_ADM;
+ cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+ cmd.hdr.dest_port = 0; /* Ignored */
+ cmd.hdr.token = port_idx << 16 | copp_idx;
+ cmd.hdr.opcode = ADM_CMD_CONNECT_AFE_PORT_V5;
+
+ cmd.mode = mode;
+ cmd.session_id = session_id;
+ cmd.afe_port_id = port_id;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
+ if (ret < 0) {
+ pr_err("%s: ADM enable for port_id: 0x%x failed ret %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback with copp id */
+ ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: ADM connect timedout for port_id: 0x%x\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto fail_cmd;
+ }
+ atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]);
+ return 0;
+
+fail_cmd:
+
+ return ret;
+}
+
+int adm_arrange_mch_map(struct adm_cmd_device_open_v5 *open, int path,
+ int channel_mode)
+{
+ int rc = 0, idx;
+
+ memset(open->dev_channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ switch (path) {
+ case ADM_PATH_PLAYBACK:
+ idx = ADM_MCH_MAP_IDX_PLAYBACK;
+ break;
+ case ADM_PATH_LIVE_REC:
+ case ADM_PATH_NONLIVE_REC:
+ idx = ADM_MCH_MAP_IDX_REC;
+ break;
+ default:
+ goto non_mch_path;
+ };
+ if ((open->dev_num_channel > 2) && multi_ch_maps[idx].set_channel_map) {
+ memcpy(open->dev_channel_mapping,
+ multi_ch_maps[idx].channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ } else {
+ if (channel_mode == 1) {
+ open->dev_channel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channel_mode == 2) {
+ open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channel_mode == 3) {
+ open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+ } else if (channel_mode == 4) {
+ open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open->dev_channel_mapping[2] = PCM_CHANNEL_LS;
+ open->dev_channel_mapping[3] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 5) {
+ open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+ open->dev_channel_mapping[3] = PCM_CHANNEL_LS;
+ open->dev_channel_mapping[4] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 6) {
+ open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+ open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+ open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+ open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 7) {
+ open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+ open->dev_channel_mapping[3] = PCM_CHANNEL_LFE;
+ open->dev_channel_mapping[4] = PCM_CHANNEL_LB;
+ open->dev_channel_mapping[5] = PCM_CHANNEL_RB;
+ open->dev_channel_mapping[6] = PCM_CHANNEL_CS;
+ } else if (channel_mode == 8) {
+ open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+ open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+ open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+ open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+ open->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+ open->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+ } else {
+ pr_err("%s: invalid num_chan %d\n", __func__,
+ channel_mode);
+ rc = -EINVAL;
+ goto inval_ch_mod;
+ }
+ }
+
+non_mch_path:
+inval_ch_mod:
+ return rc;
+}
+
+int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
+ int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
+{
+ struct adm_cmd_device_open_v5 open;
+ int ret = 0;
+ int port_idx, copp_idx, flags;
+ int tmp_port = q6audio_get_port_id(port_id);
+
+ pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n",
+ __func__, port_id, path, rate, channel_mode, perf_mode,
+ topology);
+
+ /* For DTS EAGLE only, force 24 bit */
+ if ((topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) &&
+ (perf_mode == LEGACY_PCM_MODE)) {
+ bit_width = 24;
+ pr_debug("%s: Force open adm in 24-bit for DTS HPX topology 0x%x\n",
+ __func__, topology);
+ }
+ port_id = q6audio_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ if (this_adm.apr == NULL) {
+ this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+ 0xFFFFFFFF, &this_adm);
+ if (this_adm.apr == NULL) {
+ pr_err("%s: Unable to register ADM\n", __func__);
+ return -ENODEV;
+ }
+ rtac_set_adm_handle(this_adm.apr);
+ }
+
+ if (perf_mode == ULL_POST_PROCESSING_PCM_MODE) {
+ flags = ADM_ULL_POST_PROCESSING_DEVICE_SESSION;
+ if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
+ (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
+ (topology == SRS_TRUMEDIA_TOPOLOGY_ID) ||
+ (topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX))
+ topology = DEFAULT_COPP_TOPOLOGY;
+ } else if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
+ flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
+ topology = NULL_COPP_TOPOLOGY;
+ rate = ULL_SUPPORTED_SAMPLE_RATE;
+ bit_width = ULL_SUPPORTED_BITS_PER_SAMPLE;
+ } else if (perf_mode == LOW_LATENCY_PCM_MODE) {
+ flags = ADM_LOW_LATENCY_DEVICE_SESSION;
+ if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
+ (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
+ (topology == SRS_TRUMEDIA_TOPOLOGY_ID) ||
+ (topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX))
+ topology = DEFAULT_COPP_TOPOLOGY;
+ } else {
+ if (path == ADM_PATH_COMPRESSED_RX)
+ flags = 0;
+ else
+ flags = ADM_LEGACY_DEVICE_SESSION;
+ }
+
+ if ((topology == VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
+ (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
+ (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY))
+ rate = 16000;
+
+ copp_idx = adm_get_idx_if_copp_exists(port_idx, topology, perf_mode,
+ rate, bit_width, app_type);
+ if (copp_idx < 0) {
+ copp_idx = adm_get_next_available_copp(port_idx);
+ if (copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: exceeded copp id %d\n",
+ __func__, copp_idx);
+ return -EINVAL;
+ }
+ atomic_set(&this_adm.copp.cnt[port_idx][copp_idx], 0);
+ atomic_set(&this_adm.copp.topology[port_idx][copp_idx],
+ topology);
+ atomic_set(&this_adm.copp.mode[port_idx][copp_idx],
+ perf_mode);
+ atomic_set(&this_adm.copp.rate[port_idx][copp_idx],
+ rate);
+ atomic_set(&this_adm.copp.channels[port_idx][copp_idx],
+ channel_mode);
+ atomic_set(&this_adm.copp.bit_width[port_idx][copp_idx],
+ bit_width);
+ atomic_set(&this_adm.copp.app_type[port_idx][copp_idx],
+ app_type);
+ atomic_set(&this_adm.copp.acdb_id[port_idx][copp_idx],
+ acdb_id);
+ set_bit(ADM_STATUS_CALIBRATION_REQUIRED,
+ (void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
+ if (path != ADM_PATH_COMPRESSED_RX)
+ send_adm_custom_topology();
+ }
+
+ if (this_adm.copp.adm_delay[port_idx][copp_idx] &&
+ perf_mode == LEGACY_PCM_MODE) {
+ atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx],
+ 1);
+ this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
+ wake_up(&this_adm.copp.adm_delay_wait[port_idx][copp_idx]);
+ }
+
+ /* Create a COPP if port id are not enabled */
+ if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) == 0) {
+ pr_debug("%s: open ADM: port_idx: %d, copp_idx: %d\n", __func__,
+ port_idx, copp_idx);
+ if ((topology == SRS_TRUMEDIA_TOPOLOGY_ID) &&
+ perf_mode == LEGACY_PCM_MODE) {
+ int res;
+
+ atomic_set(&this_adm.mem_map_index, ADM_SRS_TRUMEDIA);
+ msm_dts_srs_tm_ion_memmap(&this_adm.outband_memmap);
+ res = adm_memory_map_regions(&this_adm.outband_memmap.paddr, 0,
+ (uint32_t *)&this_adm.outband_memmap.size, 1);
+ if (res < 0) {
+ pr_err("%s: SRS adm_memory_map_regions failed ! addr = 0x%pK, size = %d\n",
+ __func__, (void *)this_adm.outband_memmap.paddr,
+ (uint32_t)this_adm.outband_memmap.size);
+ }
+ }
+ if ((topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) &&
+ (perf_mode == LEGACY_PCM_MODE)) {
+ int res = 0;
+
+ atomic_set(&this_adm.mem_map_index, ADM_DTS_EAGLE);
+ msm_dts_ion_memmap(&this_adm.outband_memmap);
+ res = adm_memory_map_regions(
+ &this_adm.outband_memmap.paddr,
+ 0,
+ (uint32_t *)&this_adm.outband_memmap.size,
+ 1);
+ if (res < 0)
+ pr_err("%s: DTS_EAGLE mmap did not work!",
+ __func__);
+ }
+ open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ open.hdr.pkt_size = sizeof(open);
+ open.hdr.src_svc = APR_SVC_ADM;
+ open.hdr.src_domain = APR_DOMAIN_APPS;
+ open.hdr.src_port = tmp_port;
+ open.hdr.dest_svc = APR_SVC_ADM;
+ open.hdr.dest_domain = APR_DOMAIN_ADSP;
+ open.hdr.dest_port = tmp_port;
+ open.hdr.token = port_idx << 16 | copp_idx;
+ open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
+ open.flags = flags;
+ open.mode_of_operation = path;
+ open.endpoint_id_1 = tmp_port;
+
+ if (this_adm.ec_ref_rx == -1) {
+ open.endpoint_id_2 = 0xFFFF;
+ } else if (this_adm.ec_ref_rx && (path != 1)) {
+ open.endpoint_id_2 = this_adm.ec_ref_rx;
+ this_adm.ec_ref_rx = -1;
+ }
+
+ open.topology_id = topology;
+
+ open.dev_num_channel = channel_mode & 0x00FF;
+ open.bit_width = bit_width;
+ WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
+ (rate != ULL_SUPPORTED_SAMPLE_RATE));
+ open.sample_rate = rate;
+
+ ret = adm_arrange_mch_map(&open, path, channel_mode);
+
+ if (ret)
+ return ret;
+
+ pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
+ __func__, open.endpoint_id_1, open.sample_rate,
+ open.topology_id);
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+ if (ret < 0) {
+ pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
+ __func__, tmp_port, port_id, ret);
+ return -EINVAL;
+ }
+ /* Wait for the callback with copp id */
+ ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: ADM open timedout for port_id: 0x%x for [0x%x]\n",
+ __func__, tmp_port, port_id);
+ return -EINVAL;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ return adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ }
+ }
+ atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]);
+ return copp_idx;
+}
+
+
+void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate)
+{
+ struct audproc_mfc_output_media_fmt mfc_cfg;
+ struct adm_cmd_device_open_v5 open;
+ int port_idx;
+ int sz = 0;
+ int rc = 0;
+ int i = 0;
+
+ port_id = q6audio_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ goto fail_cmd;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ goto fail_cmd;
+ }
+
+ sz = sizeof(struct audproc_mfc_output_media_fmt);
+
+ mfc_cfg.params.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mfc_cfg.params.hdr.pkt_size = sz;
+ mfc_cfg.params.hdr.src_svc = APR_SVC_ADM;
+ mfc_cfg.params.hdr.src_domain = APR_DOMAIN_APPS;
+ mfc_cfg.params.hdr.src_port = port_id;
+ mfc_cfg.params.hdr.dest_svc = APR_SVC_ADM;
+ mfc_cfg.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ mfc_cfg.params.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ mfc_cfg.params.hdr.token = port_idx << 16 | copp_idx;
+ mfc_cfg.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ mfc_cfg.params.payload_addr_lsw = 0;
+ mfc_cfg.params.payload_addr_msw = 0;
+ mfc_cfg.params.mem_map_handle = 0;
+ mfc_cfg.params.payload_size = sizeof(mfc_cfg) -
+ sizeof(mfc_cfg.params);
+ mfc_cfg.data.module_id = AUDPROC_MODULE_ID_MFC;
+ mfc_cfg.data.param_id =
+ AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
+ mfc_cfg.data.param_size = mfc_cfg.params.payload_size -
+ sizeof(mfc_cfg.data);
+ mfc_cfg.data.reserved = 0;
+ mfc_cfg.sampling_rate = dst_sample_rate;
+ mfc_cfg.bits_per_sample =
+ atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
+ open.dev_num_channel = mfc_cfg.num_channels =
+ atomic_read(&this_adm.copp.channels[port_idx][copp_idx]);
+
+ rc = adm_arrange_mch_map(&open, ADM_PATH_PLAYBACK,
+ mfc_cfg.num_channels);
+ if (rc < 0) {
+ pr_err("%s: unable to get channal map\n", __func__);
+ goto fail_cmd;
+ }
+
+ for (i = 0; i < mfc_cfg.num_channels; i++)
+ mfc_cfg.channel_type[i] =
+ (uint16_t) open.dev_channel_mapping[i];
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+
+ pr_debug("%s: mfc config: port_idx %d copp_idx %d copp SR %d copp BW %d copp chan %d o/p SR %d\n",
+ __func__, port_idx, copp_idx,
+ atomic_read(&this_adm.copp.rate[port_idx][copp_idx]),
+ mfc_cfg.bits_per_sample, mfc_cfg.num_channels,
+ mfc_cfg.sampling_rate);
+
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)&mfc_cfg);
+
+ if (rc < 0) {
+ pr_err("%s: port_id: for[0x%x] failed %d\n",
+ __func__, port_id, rc);
+ goto fail_cmd;
+ }
+ /* Wait for the callback with copp id */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: mfc_cfg Set params timed out for port_id: for [0x%x]\n",
+ __func__, port_id);
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return;
+}
+
+
+int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode)
+{
+ struct adm_cmd_matrix_map_routings_v5 *route;
+ struct adm_session_map_node_v5 *node;
+ uint16_t *copps_list;
+ int cmd_size = 0;
+ int ret = 0, i = 0;
+ void *payload = NULL;
+ void *matrix_map = NULL;
+ int port_idx, copp_idx;
+
+ /* Assumes port_ids have already been validated during adm_open */
+ cmd_size = (sizeof(struct adm_cmd_matrix_map_routings_v5) +
+ sizeof(struct adm_session_map_node_v5) +
+ (sizeof(uint32_t) * payload_map.num_copps));
+ matrix_map = kzalloc(cmd_size, GFP_KERNEL);
+ if (matrix_map == NULL) {
+ pr_err("%s: Mem alloc failed\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+ route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map;
+
+ route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ route->hdr.pkt_size = cmd_size;
+ route->hdr.src_svc = 0;
+ route->hdr.src_domain = APR_DOMAIN_APPS;
+ route->hdr.src_port = 0; /* Ignored */;
+ route->hdr.dest_svc = APR_SVC_ADM;
+ route->hdr.dest_domain = APR_DOMAIN_ADSP;
+ route->hdr.dest_port = 0; /* Ignored */;
+ route->hdr.token = 0;
+ if (path == ADM_PATH_COMPRESSED_RX) {
+ pr_debug("%s: ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5 0x%x\n",
+ __func__, ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5);
+ route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
+ } else {
+ pr_debug("%s: DM_CMD_MATRIX_MAP_ROUTINGS_V5 0x%x\n",
+ __func__, ADM_CMD_MATRIX_MAP_ROUTINGS_V5);
+ route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
+ }
+ route->num_sessions = 1;
+
+ switch (path) {
+ case ADM_PATH_PLAYBACK:
+ route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
+ break;
+ case ADM_PATH_LIVE_REC:
+ case ADM_PATH_NONLIVE_REC:
+ route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
+ break;
+ case ADM_PATH_COMPRESSED_RX:
+ route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
+ break;
+ default:
+ pr_err("%s: Wrong path set[%d]\n", __func__, path);
+ break;
+ }
+ payload = ((u8 *)matrix_map +
+ sizeof(struct adm_cmd_matrix_map_routings_v5));
+ node = (struct adm_session_map_node_v5 *)payload;
+
+ node->session_id = payload_map.session_id;
+ node->num_copps = payload_map.num_copps;
+ payload = (u8 *)node + sizeof(struct adm_session_map_node_v5);
+ copps_list = (uint16_t *)payload;
+ for (i = 0; i < payload_map.num_copps; i++) {
+ port_idx =
+ adm_validate_and_get_port_index(payload_map.port_id[i]);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__,
+ payload_map.port_id[i]);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ copp_idx = payload_map.copp_idx[i];
+ copps_list[i] = atomic_read(&this_adm.copp.id[port_idx]
+ [copp_idx]);
+ }
+ atomic_set(&this_adm.matrix_map_stat, -1);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_map);
+ if (ret < 0) {
+ pr_err("%s: routing for syream %d failed ret %d\n",
+ __func__, payload_map.session_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_adm.matrix_map_wait,
+ atomic_read(&this_adm.matrix_map_stat) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: routing for syream %d failed\n", __func__,
+ payload_map.session_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.matrix_map_stat) > 0) {
+ pr_err("%s: DSP returned error[%s]\n", __func__,
+ adsp_err_get_err_str(atomic_read(
+ &this_adm.matrix_map_stat)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.matrix_map_stat));
+ goto fail_cmd;
+ }
+
+ if ((perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) &&
+ (path != ADM_PATH_COMPRESSED_RX)) {
+ for (i = 0; i < payload_map.num_copps; i++) {
+ port_idx = afe_get_port_index(payload_map.port_id[i]);
+ copp_idx = payload_map.copp_idx[i];
+ if (port_idx < 0 || copp_idx < 0 ||
+ (copp_idx > MAX_COPPS_PER_PORT - 1)) {
+ pr_err("%s: Invalid idx port_idx %d copp_idx %d\n",
+ __func__, port_idx, copp_idx);
+ continue;
+ }
+ if (atomic_read(
+ &this_adm.copp.topology[port_idx][copp_idx]) ==
+ ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX)
+ continue;
+ rtac_add_adm_device(payload_map.port_id[i],
+ atomic_read(&this_adm.copp.id
+ [port_idx][copp_idx]),
+ get_cal_path(path),
+ payload_map.session_id,
+ payload_map.app_type,
+ payload_map.acdb_dev_id);
+
+ if (!test_bit(ADM_STATUS_CALIBRATION_REQUIRED,
+ (void *)&this_adm.copp.adm_status[port_idx]
+ [copp_idx])) {
+ pr_debug("%s: adm copp[0x%x][%d] already sent",
+ __func__, port_idx, copp_idx);
+ continue;
+ }
+ send_adm_cal(payload_map.port_id[i], copp_idx,
+ get_cal_path(path), perf_mode,
+ payload_map.app_type,
+ payload_map.acdb_dev_id,
+ payload_map.sample_rate);
+ /* ADM COPP calibration is already sent */
+ clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
+ (void *)&this_adm.copp.
+ adm_status[port_idx][copp_idx]);
+ pr_debug("%s: copp_id: %d\n", __func__,
+ atomic_read(&this_adm.copp.id[port_idx]
+ [copp_idx]));
+ }
+ }
+
+fail_cmd:
+ kfree(matrix_map);
+ return ret;
+}
+
+void adm_ec_ref_rx_id(int port_id)
+{
+ this_adm.ec_ref_rx = port_id;
+ pr_debug("%s: ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
+}
+
+int adm_close(int port_id, int perf_mode, int copp_idx)
+{
+ struct apr_hdr close;
+
+ int ret = 0, port_idx;
+ int copp_id = RESET_COPP_ID;
+
+ pr_debug("%s: port_id=0x%x perf_mode: %d copp_idx: %d\n", __func__,
+ port_id, perf_mode, copp_idx);
+
+ port_id = q6audio_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n",
+ __func__, port_id);
+ return -EINVAL;
+ }
+
+ if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s: Invalid copp idx: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ if (this_adm.copp.adm_delay[port_idx][copp_idx] && perf_mode
+ == LEGACY_PCM_MODE) {
+ atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx],
+ 1);
+ this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
+ wake_up(&this_adm.copp.adm_delay_wait[port_idx][copp_idx]);
+ }
+
+ atomic_dec(&this_adm.copp.cnt[port_idx][copp_idx]);
+ if (!(atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]))) {
+ copp_id = adm_get_copp_id(port_idx, copp_idx);
+ pr_debug("%s: Closing ADM port_idx:%d copp_idx:%d copp_id:0x%x\n",
+ __func__, port_idx, copp_idx, copp_id);
+ if ((!perf_mode) && (this_adm.outband_memmap.paddr != 0) &&
+ (atomic_read(&this_adm.copp.topology[port_idx][copp_idx]) ==
+ SRS_TRUMEDIA_TOPOLOGY_ID)) {
+ atomic_set(&this_adm.mem_map_index,
+ ADM_SRS_TRUMEDIA);
+ ret = adm_memory_unmap_regions();
+ if (ret < 0) {
+ pr_err("%s: adm mem unmmap err %d",
+ __func__, ret);
+ } else {
+ atomic_set(&this_adm.mem_map_handles
+ [ADM_SRS_TRUMEDIA], 0);
+ }
+ }
+
+ if ((perf_mode == LEGACY_PCM_MODE) &&
+ (this_adm.outband_memmap.paddr != 0) &&
+ (atomic_read(
+ &this_adm.copp.topology[port_idx][copp_idx]) ==
+ ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX)) {
+ atomic_set(&this_adm.mem_map_index, ADM_DTS_EAGLE);
+ ret = adm_memory_unmap_regions();
+ if (ret < 0) {
+ pr_err("%s: adm mem unmmap err %d",
+ __func__, ret);
+ } else {
+ atomic_set(&this_adm.mem_map_handles
+ [ADM_DTS_EAGLE], 0);
+ }
+ }
+
+ if ((afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) &&
+ this_adm.sourceTrackingData.memmap.paddr) {
+ atomic_set(&this_adm.mem_map_index,
+ ADM_MEM_MAP_INDEX_SOURCE_TRACKING);
+ ret = adm_memory_unmap_regions();
+ if (ret < 0) {
+ pr_err("%s: adm mem unmmap err %d",
+ __func__, ret);
+ }
+ msm_audio_ion_free(
+ this_adm.sourceTrackingData.ion_client,
+ this_adm.sourceTrackingData.ion_handle);
+ this_adm.sourceTrackingData.ion_client = NULL;
+ this_adm.sourceTrackingData.ion_handle = NULL;
+ this_adm.sourceTrackingData.memmap.size = 0;
+ this_adm.sourceTrackingData.memmap.kvaddr = NULL;
+ this_adm.sourceTrackingData.memmap.paddr = 0;
+ this_adm.sourceTrackingData.apr_cmd_status = -1;
+ atomic_set(&this_adm.mem_map_handles[
+ ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
+ }
+
+ close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ close.pkt_size = sizeof(close);
+ close.src_svc = APR_SVC_ADM;
+ close.src_domain = APR_DOMAIN_APPS;
+ close.src_port = port_id;
+ close.dest_svc = APR_SVC_ADM;
+ close.dest_domain = APR_DOMAIN_ADSP;
+ close.dest_port = copp_id;
+ close.token = port_idx << 16 | copp_idx;
+ close.opcode = ADM_CMD_DEVICE_CLOSE_V5;
+
+ atomic_set(&this_adm.copp.id[port_idx][copp_idx],
+ RESET_COPP_ID);
+ atomic_set(&this_adm.copp.cnt[port_idx][copp_idx], 0);
+ atomic_set(&this_adm.copp.topology[port_idx][copp_idx], 0);
+ atomic_set(&this_adm.copp.mode[port_idx][copp_idx], 0);
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ atomic_set(&this_adm.copp.rate[port_idx][copp_idx], 0);
+ atomic_set(&this_adm.copp.channels[port_idx][copp_idx], 0);
+ atomic_set(&this_adm.copp.bit_width[port_idx][copp_idx], 0);
+ atomic_set(&this_adm.copp.app_type[port_idx][copp_idx], 0);
+
+ clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
+ (void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
+ if (ret < 0) {
+ pr_err("%s: ADM close failed %d\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: ADM cmd Route timedout for port 0x%x\n",
+ __func__, port_id);
+ return -EINVAL;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ return adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ }
+ }
+
+ if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
+ pr_debug("%s: remove adm device from rtac\n", __func__);
+ rtac_remove_adm_device(port_id, copp_id);
+ }
+ return 0;
+}
+
+int send_rtac_audvol_cal(void)
+{
+ int ret = 0;
+ int ret2 = 0;
+ int i = 0;
+ int copp_idx, port_idx, acdb_id, app_id, path;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_audvol *audvol_cal_info = NULL;
+ struct rtac_adm rtac_adm_data;
+
+ mutex_lock(&this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]->lock);
+
+ cal_block = cal_utils_get_only_cal_block(
+ this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]);
+ if (cal_block == NULL) {
+ pr_err("%s: can't find cal block!\n", __func__);
+ goto unlock;
+ }
+
+ audvol_cal_info = cal_block->cal_info;
+ if (audvol_cal_info == NULL) {
+ pr_err("%s: audvol_cal_info is NULL!\n", __func__);
+ goto unlock;
+ }
+
+ get_rtac_adm_data(&rtac_adm_data);
+ for (; i < rtac_adm_data.num_of_dev; i++) {
+
+ acdb_id = rtac_adm_data.device[i].acdb_dev_id;
+ if (acdb_id == 0)
+ acdb_id = audvol_cal_info->acdb_id;
+
+ app_id = rtac_adm_data.device[i].app_type;
+ if (app_id == 0)
+ app_id = audvol_cal_info->app_type;
+
+ path = afe_get_port_type(rtac_adm_data.device[i].afe_port);
+ if ((acdb_id == audvol_cal_info->acdb_id) &&
+ (app_id == audvol_cal_info->app_type) &&
+ (path == audvol_cal_info->path)) {
+
+ if (adm_get_indexes_from_copp_id(rtac_adm_data.
+ device[i].copp, &copp_idx, &port_idx) != 0) {
+ pr_debug("%s: Copp Id %d is not active\n",
+ __func__,
+ rtac_adm_data.device[i].copp);
+ continue;
+ }
+
+ ret2 = adm_remap_and_send_cal_block(ADM_RTAC_AUDVOL_CAL,
+ rtac_adm_data.device[i].afe_port,
+ copp_idx, cal_block,
+ atomic_read(&this_adm.copp.
+ mode[port_idx][copp_idx]),
+ audvol_cal_info->app_type,
+ audvol_cal_info->acdb_id,
+ atomic_read(&this_adm.copp.
+ rate[port_idx][copp_idx]));
+ if (ret2 < 0) {
+ pr_debug("%s: remap and send failed for copp Id %d, acdb id %d, app type %d, path %d\n",
+ __func__, rtac_adm_data.device[i].copp,
+ audvol_cal_info->acdb_id,
+ audvol_cal_info->app_type,
+ audvol_cal_info->path);
+ ret = ret2;
+ }
+ }
+ }
+unlock:
+ mutex_unlock(&this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]->lock);
+ return ret;
+}
+
+int adm_map_rtac_block(struct rtac_cal_block_data *cal_block)
+{
+ int result = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("%s: cal_block is NULL!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->cal_data.paddr == 0) {
+ pr_debug("%s: No address to map!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->map_data.map_size == 0) {
+ pr_debug("%s: map size is 0!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ /* valid port ID needed for callback use primary I2S */
+ atomic_set(&this_adm.mem_map_index, ADM_RTAC_APR_CAL);
+ result = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
+ &cal_block->map_data.map_size, 1);
+ if (result < 0) {
+ pr_err("%s: RTAC mmap did not work! size = %d result %d\n",
+ __func__,
+ cal_block->map_data.map_size, result);
+ pr_debug("%s: RTAC mmap did not work! addr = 0x%pK, size = %d\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+ goto done;
+ }
+
+ cal_block->map_data.map_handle = atomic_read(
+ &this_adm.mem_map_handles[ADM_RTAC_APR_CAL]);
+done:
+ return result;
+}
+
+int adm_unmap_rtac_block(uint32_t *mem_map_handle)
+{
+ int result = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (mem_map_handle == NULL) {
+ pr_debug("%s: Map handle is NULL, nothing to unmap\n",
+ __func__);
+ goto done;
+ }
+
+ if (*mem_map_handle == 0) {
+ pr_debug("%s: Map handle is 0, nothing to unmap\n",
+ __func__);
+ goto done;
+ }
+
+ if (*mem_map_handle != atomic_read(
+ &this_adm.mem_map_handles[ADM_RTAC_APR_CAL])) {
+ pr_err("%s: Map handles do not match! Unmapping RTAC, RTAC map 0x%x, ADM map 0x%x\n",
+ __func__, *mem_map_handle, atomic_read(
+ &this_adm.mem_map_handles[ADM_RTAC_APR_CAL]));
+
+ /* if mismatch use handle passed in to unmap */
+ atomic_set(&this_adm.mem_map_handles[ADM_RTAC_APR_CAL],
+ *mem_map_handle);
+ }
+
+ /* valid port ID needed for callback use primary I2S */
+ atomic_set(&this_adm.mem_map_index, ADM_RTAC_APR_CAL);
+ result = adm_memory_unmap_regions();
+ if (result < 0) {
+ pr_debug("%s: adm_memory_unmap_regions failed, error %d\n",
+ __func__, result);
+ } else {
+ atomic_set(&this_adm.mem_map_handles[ADM_RTAC_APR_CAL], 0);
+ *mem_map_handle = 0;
+ }
+done:
+ return result;
+}
+
+static int get_cal_type_index(int32_t cal_type)
+{
+ int ret = -EINVAL;
+
+ switch (cal_type) {
+ case ADM_AUDPROC_CAL_TYPE:
+ ret = ADM_AUDPROC_CAL;
+ break;
+ case ADM_AUDVOL_CAL_TYPE:
+ ret = ADM_AUDVOL_CAL;
+ break;
+ case ADM_CUST_TOPOLOGY_CAL_TYPE:
+ ret = ADM_CUSTOM_TOP_CAL;
+ break;
+ case ADM_RTAC_INFO_CAL_TYPE:
+ ret = ADM_RTAC_INFO_CAL;
+ break;
+ case ADM_RTAC_APR_CAL_TYPE:
+ ret = ADM_RTAC_APR_CAL;
+ break;
+ case ADM_RTAC_AUDVOL_CAL_TYPE:
+ ret = ADM_RTAC_AUDVOL_CAL;
+ break;
+ default:
+ pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
+ }
+ return ret;
+}
+
+static int adm_alloc_cal(int32_t cal_type, size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_alloc_cal(data_size, data,
+ this_adm.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int adm_dealloc_cal(int32_t cal_type, size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_dealloc_cal(data_size, data,
+ this_adm.cal_data[cal_index]);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int adm_set_cal(int32_t cal_type, size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_set_cal(data_size, data,
+ this_adm.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (cal_index == ADM_CUSTOM_TOP_CAL) {
+ mutex_lock(&this_adm.cal_data[ADM_CUSTOM_TOP_CAL]->lock);
+ this_adm.set_custom_topology = 1;
+ mutex_unlock(&this_adm.cal_data[ADM_CUSTOM_TOP_CAL]->lock);
+ } else if (cal_index == ADM_RTAC_AUDVOL_CAL) {
+ send_rtac_audvol_cal();
+ }
+done:
+ return ret;
+}
+
+static int adm_map_cal_data(int32_t cal_type,
+ struct cal_block_data *cal_block)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ atomic_set(&this_adm.mem_map_index, cal_index);
+ ret = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
+ (uint32_t *)&cal_block->map_data.map_size, 1);
+ if (ret < 0) {
+ pr_err("%s: map did not work! cal_type %i ret %d\n",
+ __func__, cal_index, ret);
+ ret = -ENODEV;
+ goto done;
+ }
+ cal_block->map_data.q6map_handle = atomic_read(&this_adm.
+ mem_map_handles[cal_index]);
+done:
+ return ret;
+}
+
+static int adm_unmap_cal_data(int32_t cal_type,
+ struct cal_block_data *cal_block)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block == NULL) {
+ pr_err("%s: Cal block is NULL!\n",
+ __func__);
+ goto done;
+ }
+
+ if (cal_block->map_data.q6map_handle == 0) {
+ pr_err("%s: Map handle is NULL, nothing to unmap\n",
+ __func__);
+ goto done;
+ }
+
+ atomic_set(&this_adm.mem_map_handles[cal_index],
+ cal_block->map_data.q6map_handle);
+ atomic_set(&this_adm.mem_map_index, cal_index);
+ ret = adm_memory_unmap_regions();
+ if (ret < 0) {
+ pr_err("%s: unmap did not work! cal_type %i ret %d\n",
+ __func__, cal_index, ret);
+ ret = -ENODEV;
+ goto done;
+ }
+ cal_block->map_data.q6map_handle = 0;
+done:
+ return ret;
+}
+
+static void adm_delete_cal_data(void)
+{
+ pr_debug("%s:\n", __func__);
+
+ cal_utils_destroy_cal_types(ADM_MAX_CAL_TYPES, this_adm.cal_data);
+}
+
+static int adm_init_cal_data(void)
+{
+ int ret = 0;
+ struct cal_type_info cal_type_info[] = {
+ {{ADM_CUST_TOPOLOGY_CAL_TYPE,
+ {adm_alloc_cal, adm_dealloc_cal, NULL,
+ adm_set_cal, NULL, NULL} },
+ {adm_map_cal_data, adm_unmap_cal_data,
+ cal_utils_match_buf_num} },
+
+ {{ADM_AUDPROC_CAL_TYPE,
+ {adm_alloc_cal, adm_dealloc_cal, NULL,
+ adm_set_cal, NULL, NULL} },
+ {adm_map_cal_data, adm_unmap_cal_data,
+ cal_utils_match_buf_num} },
+
+ {{ADM_AUDVOL_CAL_TYPE,
+ {adm_alloc_cal, adm_dealloc_cal, NULL,
+ adm_set_cal, NULL, NULL} },
+ {adm_map_cal_data, adm_unmap_cal_data,
+ cal_utils_match_buf_num} },
+
+ {{ADM_RTAC_INFO_CAL_TYPE,
+ {NULL, NULL, NULL, NULL, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{ADM_RTAC_APR_CAL_TYPE,
+ {NULL, NULL, NULL, NULL, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{DTS_EAGLE_CAL_TYPE,
+ {NULL, NULL, NULL, NULL, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{SRS_TRUMEDIA_CAL_TYPE,
+ {NULL, NULL, NULL, NULL, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{ADM_RTAC_AUDVOL_CAL_TYPE,
+ {adm_alloc_cal, adm_dealloc_cal, NULL,
+ adm_set_cal, NULL, NULL} },
+ {adm_map_cal_data, adm_unmap_cal_data,
+ cal_utils_match_buf_num} },
+ };
+ pr_debug("%s:\n", __func__);
+
+ ret = cal_utils_create_cal_types(ADM_MAX_CAL_TYPES, this_adm.cal_data,
+ cal_type_info);
+ if (ret < 0) {
+ pr_err("%s: could not create cal type! ret %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return ret;
+err:
+ adm_delete_cal_data();
+ return ret;
+}
+
+int adm_set_volume(int port_id, int copp_idx, int volume)
+{
+ struct audproc_volume_ctrl_master_gain audproc_vol;
+ int sz = 0;
+ int rc = 0;
+ int port_idx;
+
+ pr_debug("%s: port_id %d, volume %d\n", __func__, port_id, volume);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct audproc_volume_ctrl_master_gain);
+ audproc_vol.params.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ audproc_vol.params.hdr.pkt_size = sz;
+ audproc_vol.params.hdr.src_svc = APR_SVC_ADM;
+ audproc_vol.params.hdr.src_domain = APR_DOMAIN_APPS;
+ audproc_vol.params.hdr.src_port = port_id;
+ audproc_vol.params.hdr.dest_svc = APR_SVC_ADM;
+ audproc_vol.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ audproc_vol.params.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ audproc_vol.params.hdr.token = port_idx << 16 | copp_idx;
+ audproc_vol.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ audproc_vol.params.payload_addr_lsw = 0;
+ audproc_vol.params.payload_addr_msw = 0;
+ audproc_vol.params.mem_map_handle = 0;
+ audproc_vol.params.payload_size = sizeof(audproc_vol) -
+ sizeof(audproc_vol.params);
+ audproc_vol.data.module_id = AUDPROC_MODULE_ID_VOL_CTRL;
+ audproc_vol.data.param_id = AUDPROC_PARAM_ID_VOL_CTRL_MASTER_GAIN;
+ audproc_vol.data.param_size = audproc_vol.params.payload_size -
+ sizeof(audproc_vol.data);
+ audproc_vol.data.reserved = 0;
+ audproc_vol.master_gain = volume;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)&audproc_vol);
+ if (rc < 0) {
+ pr_err("%s: Set params failed port = %#x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: Vol cntrl Set params timed out port = %#x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int adm_set_softvolume(int port_id, int copp_idx,
+ struct audproc_softvolume_params *softvol_param)
+{
+ struct audproc_soft_step_volume_params audproc_softvol;
+ int sz = 0;
+ int rc = 0;
+ int port_idx;
+
+ pr_debug("%s: period %d step %d curve %d\n", __func__,
+ softvol_param->period, softvol_param->step,
+ softvol_param->rampingcurve);
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct audproc_soft_step_volume_params);
+
+ audproc_softvol.params.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ audproc_softvol.params.hdr.pkt_size = sz;
+ audproc_softvol.params.hdr.src_svc = APR_SVC_ADM;
+ audproc_softvol.params.hdr.src_domain = APR_DOMAIN_APPS;
+ audproc_softvol.params.hdr.src_port = port_id;
+ audproc_softvol.params.hdr.dest_svc = APR_SVC_ADM;
+ audproc_softvol.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ audproc_softvol.params.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ audproc_softvol.params.hdr.token = port_idx << 16 | copp_idx;
+ audproc_softvol.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ audproc_softvol.params.payload_addr_lsw = 0;
+ audproc_softvol.params.payload_addr_msw = 0;
+ audproc_softvol.params.mem_map_handle = 0;
+ audproc_softvol.params.payload_size = sizeof(audproc_softvol) -
+ sizeof(audproc_softvol.params);
+ audproc_softvol.data.module_id = AUDPROC_MODULE_ID_VOL_CTRL;
+ audproc_softvol.data.param_id =
+ AUDPROC_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
+ audproc_softvol.data.param_size = audproc_softvol.params.payload_size -
+ sizeof(audproc_softvol.data);
+ audproc_softvol.data.reserved = 0;
+ audproc_softvol.period = softvol_param->period;
+ audproc_softvol.step = softvol_param->step;
+ audproc_softvol.ramping_curve = softvol_param->rampingcurve;
+
+ pr_debug("%s: period %d, step %d, curve %d\n", __func__,
+ audproc_softvol.period, audproc_softvol.step,
+ audproc_softvol.ramping_curve);
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)&audproc_softvol);
+ if (rc < 0) {
+ pr_err("%s: Set params failed port = %#x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: Soft volume Set params timed out port = %#x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int adm_param_enable(int port_id, int copp_idx, int module_id, int enable)
+{
+ struct audproc_enable_param_t adm_mod_enable;
+ int sz = 0;
+ int rc = 0;
+ int port_idx;
+
+ pr_debug("%s port_id %d, module_id 0x%x, enable %d\n",
+ __func__, port_id, module_id, enable);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct audproc_enable_param_t);
+
+ adm_mod_enable.pp_params.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_mod_enable.pp_params.hdr.pkt_size = sz;
+ adm_mod_enable.pp_params.hdr.src_svc = APR_SVC_ADM;
+ adm_mod_enable.pp_params.hdr.src_domain = APR_DOMAIN_APPS;
+ adm_mod_enable.pp_params.hdr.src_port = port_id;
+ adm_mod_enable.pp_params.hdr.dest_svc = APR_SVC_ADM;
+ adm_mod_enable.pp_params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_mod_enable.pp_params.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_mod_enable.pp_params.hdr.token = port_idx << 16 | copp_idx;
+ adm_mod_enable.pp_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ adm_mod_enable.pp_params.payload_addr_lsw = 0;
+ adm_mod_enable.pp_params.payload_addr_msw = 0;
+ adm_mod_enable.pp_params.mem_map_handle = 0;
+ adm_mod_enable.pp_params.payload_size = sizeof(adm_mod_enable) -
+ sizeof(adm_mod_enable.pp_params) +
+ sizeof(adm_mod_enable.pp_params.params);
+ adm_mod_enable.pp_params.params.module_id = module_id;
+ adm_mod_enable.pp_params.params.param_id = AUDPROC_PARAM_ID_ENABLE;
+ adm_mod_enable.pp_params.params.param_size =
+ adm_mod_enable.pp_params.payload_size -
+ sizeof(adm_mod_enable.pp_params.params);
+ adm_mod_enable.pp_params.params.reserved = 0;
+ adm_mod_enable.enable = enable;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_mod_enable);
+ if (rc < 0) {
+ pr_err("%s: Set params failed port = %#x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: module %x enable %d timed out on port = %#x\n",
+ __func__, module_id, enable, port_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+
+}
+
+int adm_send_calibration(int port_id, int copp_idx, int path, int perf_mode,
+ int cal_type, char *params, int size)
+{
+
+ struct adm_cmd_set_pp_params_v5 *adm_params = NULL;
+ int sz, rc = 0;
+ int port_idx;
+
+ pr_debug("%s:port_id %d, path %d, perf_mode %d, cal_type %d, size %d\n",
+ __func__, port_id, path, perf_mode, cal_type, size);
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ /* Maps audio_dev_ctrl path definition to ACDB definition */
+ if (get_cal_path(path) != RX_DEVICE) {
+ pr_err("%s: acdb_path %d\n", __func__, path);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ sz = sizeof(struct adm_cmd_set_pp_params_v5) + size;
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ if (!adm_params) {
+ pr_err("%s, adm params memory alloc failed", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ memcpy(((u8 *)adm_params + sizeof(struct adm_cmd_set_pp_params_v5)),
+ params, size);
+
+ adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_params->hdr.pkt_size = sz;
+ adm_params->hdr.src_svc = APR_SVC_ADM;
+ adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params->hdr.src_port = port_id;
+ adm_params->hdr.dest_svc = APR_SVC_ADM;
+ adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params->hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ adm_params->hdr.token = port_idx << 16 | copp_idx;
+ adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ /* payload address and mmap handle initialized to zero by kzalloc */
+ adm_params->payload_size = size;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+ if (rc < 0) {
+ pr_err("%s: Set params failed port = %#x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto end;
+ }
+ /* Wait for the callback */
+ rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("%s: Set params timed out port = %#x\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto end;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto end;
+ }
+ rc = 0;
+
+end:
+ kfree(adm_params);
+ return rc;
+}
+
+/*
+ * adm_update_wait_parameters must be called with routing driver locks.
+ * adm_reset_wait_parameters must be called with routing driver locks.
+ * set and reset parmeters are separated to make sure it is always called
+ * under routing driver lock.
+ * adm_wait_timeout is to block until timeout or interrupted. Timeout is
+ * not a an error.
+ */
+int adm_set_wait_parameters(int port_id, int copp_idx)
+{
+
+ int ret = 0, port_idx;
+
+ pr_debug("%s: port_id 0x%x, copp_idx %d\n", __func__, port_id,
+ copp_idx);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ this_adm.copp.adm_delay[port_idx][copp_idx] = 1;
+ atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx], 0);
+
+end:
+ return ret;
+
+}
+
+int adm_reset_wait_parameters(int port_id, int copp_idx)
+{
+ int ret = 0, port_idx;
+
+ pr_debug("%s: port_id 0x%x copp_idx %d\n", __func__, port_id,
+ copp_idx);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx], 1);
+ this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
+
+end:
+ return ret;
+}
+
+int adm_wait_timeout(int port_id, int copp_idx, int wait_time)
+{
+ int ret = 0, port_idx;
+
+ pr_debug("%s: port_id 0x%x, copp_idx %d, wait_time %d\n", __func__,
+ port_id, copp_idx, wait_time);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ ret = wait_event_timeout(
+ this_adm.copp.adm_delay_wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.adm_delay_stat[port_idx][copp_idx]),
+ msecs_to_jiffies(wait_time));
+ pr_debug("%s: return %d\n", __func__, ret);
+ if (ret != 0)
+ ret = -EINTR;
+end:
+ pr_debug("%s: return %d--\n", __func__, ret);
+ return ret;
+}
+
+int adm_store_cal_data(int port_id, int copp_idx, int path, int perf_mode,
+ int cal_index, char *params, int *size)
+{
+ int rc = 0;
+ struct cal_block_data *cal_block = NULL;
+ int app_type, acdb_id, port_idx, sample_rate;
+
+ if (this_adm.cal_data[cal_index] == NULL) {
+ pr_debug("%s: cal_index %d not allocated!\n",
+ __func__, cal_index);
+ goto end;
+ }
+
+ if (get_cal_path(path) != RX_DEVICE) {
+ pr_debug("%s: Invalid path to store calibration %d\n",
+ __func__, path);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ acdb_id = atomic_read(&this_adm.copp.acdb_id[port_idx][copp_idx]);
+ app_type = atomic_read(&this_adm.copp.app_type[port_idx][copp_idx]);
+ sample_rate = atomic_read(&this_adm.copp.rate[port_idx][copp_idx]);
+
+ mutex_lock(&this_adm.cal_data[cal_index]->lock);
+ cal_block = adm_find_cal(cal_index, get_cal_path(path), app_type,
+ acdb_id, sample_rate);
+ if (cal_block == NULL)
+ goto unlock;
+
+ if (cal_block->cal_data.size <= 0) {
+ pr_debug("%s: No ADM cal send for port_id = 0x%x!\n",
+ __func__, port_id);
+ rc = -EINVAL;
+ goto unlock;
+ }
+
+ if (cal_index == ADM_AUDPROC_CAL) {
+ if (cal_block->cal_data.size > AUD_PROC_BLOCK_SIZE) {
+ pr_err("%s:audproc:invalid size exp/actual[%zd, %d]\n",
+ __func__, cal_block->cal_data.size, *size);
+ rc = -ENOMEM;
+ goto unlock;
+ }
+ } else if (cal_index == ADM_AUDVOL_CAL) {
+ if (cal_block->cal_data.size > AUD_VOL_BLOCK_SIZE) {
+ pr_err("%s:aud_vol:invalid size exp/actual[%zd, %d]\n",
+ __func__, cal_block->cal_data.size, *size);
+ rc = -ENOMEM;
+ goto unlock;
+ }
+ } else {
+ pr_debug("%s: Not valid calibration for dolby topolgy\n",
+ __func__);
+ rc = -EINVAL;
+ goto unlock;
+ }
+ memcpy(params, cal_block->cal_data.kvaddr, cal_block->cal_data.size);
+ *size = cal_block->cal_data.size;
+
+ pr_debug("%s:port_id %d, copp_idx %d, path %d",
+ __func__, port_id, copp_idx, path);
+ pr_debug("perf_mode %d, cal_type %d, size %d\n",
+ perf_mode, cal_index, *size);
+
+unlock:
+ mutex_unlock(&this_adm.cal_data[cal_index]->lock);
+end:
+ return rc;
+}
+
+int adm_send_compressed_device_mute(int port_id, int copp_idx, bool mute_on)
+{
+ struct adm_set_compressed_device_mute mute_params;
+ int ret = 0;
+ int port_idx;
+
+ pr_debug("%s port_id: 0x%x, copp_idx %d, mute_on: %d\n",
+ __func__, port_id, copp_idx, mute_on);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
+ pr_err("%s: Invalid port_id %#x copp_idx %d\n",
+ __func__, port_id, copp_idx);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ mute_params.command.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mute_params.command.hdr.pkt_size =
+ sizeof(struct adm_set_compressed_device_mute);
+ mute_params.command.hdr.src_svc = APR_SVC_ADM;
+ mute_params.command.hdr.src_domain = APR_DOMAIN_APPS;
+ mute_params.command.hdr.src_port = port_id;
+ mute_params.command.hdr.dest_svc = APR_SVC_ADM;
+ mute_params.command.hdr.dest_domain = APR_DOMAIN_ADSP;
+ mute_params.command.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ mute_params.command.hdr.token = port_idx << 16 | copp_idx;
+ mute_params.command.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ mute_params.command.payload_addr_lsw = 0;
+ mute_params.command.payload_addr_msw = 0;
+ mute_params.command.mem_map_handle = 0;
+ mute_params.command.payload_size = sizeof(mute_params) -
+ sizeof(mute_params.command);
+ mute_params.params.module_id = AUDPROC_MODULE_ID_COMPRESSED_MUTE;
+ mute_params.params.param_id = AUDPROC_PARAM_ID_COMPRESSED_MUTE;
+ mute_params.params.param_size = mute_params.command.payload_size -
+ sizeof(mute_params.params);
+ mute_params.params.reserved = 0;
+ mute_params.mute_on = mute_on;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&mute_params);
+ if (ret < 0) {
+ pr_err("%s: device mute for port %d copp %d failed, ret %d\n",
+ __func__, port_id, copp_idx, ret);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ /* Wait for the callback */
+ ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: send device mute for port %d copp %d failed\n",
+ __func__, port_id, copp_idx);
+ ret = -EINVAL;
+ goto end;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto end;
+ }
+ ret = 0;
+end:
+ return ret;
+}
+
+int adm_send_compressed_device_latency(int port_id, int copp_idx, int latency)
+{
+ struct adm_set_compressed_device_latency latency_params;
+ int port_idx;
+ int ret = 0;
+
+ pr_debug("%s port_id: 0x%x, copp_idx %d latency: %d\n", __func__,
+ port_id, copp_idx, latency);
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
+ pr_err("%s: Invalid port_id %#x copp_idx %d\n",
+ __func__, port_id, copp_idx);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ latency_params.command.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ latency_params.command.hdr.pkt_size =
+ sizeof(struct adm_set_compressed_device_latency);
+ latency_params.command.hdr.src_svc = APR_SVC_ADM;
+ latency_params.command.hdr.src_domain = APR_DOMAIN_APPS;
+ latency_params.command.hdr.src_port = port_id;
+ latency_params.command.hdr.dest_svc = APR_SVC_ADM;
+ latency_params.command.hdr.dest_domain = APR_DOMAIN_ADSP;
+ latency_params.command.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ latency_params.command.hdr.token = port_idx << 16 | copp_idx;
+ latency_params.command.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ latency_params.command.payload_addr_lsw = 0;
+ latency_params.command.payload_addr_msw = 0;
+ latency_params.command.mem_map_handle = 0;
+ latency_params.command.payload_size = sizeof(latency_params) -
+ sizeof(latency_params.command);
+ latency_params.params.module_id = AUDPROC_MODULE_ID_COMPRESSED_LATENCY;
+ latency_params.params.param_id = AUDPROC_PARAM_ID_COMPRESSED_LATENCY;
+ latency_params.params.param_size = latency_params.command.payload_size -
+ sizeof(latency_params.params);
+ latency_params.params.reserved = 0;
+ latency_params.latency = latency;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&latency_params);
+ if (ret < 0) {
+ pr_err("%s: send device latency err %d for port %d copp %d\n",
+ __func__, port_id, copp_idx, ret);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ /* Wait for the callback */
+ ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: send device latency for port %d failed\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto end;
+ } else if (atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx])));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [port_idx][copp_idx]));
+ goto end;
+ }
+ ret = 0;
+end:
+ return ret;
+}
+
+int adm_set_sound_focus(int port_id, int copp_idx,
+ struct sound_focus_param soundFocusData)
+{
+ struct adm_set_fluence_soundfocus_param soundfocus_params;
+ int sz = 0;
+ int ret = 0;
+ int port_idx;
+ int i;
+
+ pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
+ __func__, port_id, copp_idx);
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ port_idx = adm_validate_and_get_port_index(port_id);
+ if (port_idx < 0) {
+ pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+ pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ sz = sizeof(struct adm_set_fluence_soundfocus_param);
+ soundfocus_params.params.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ soundfocus_params.params.hdr.pkt_size = sz;
+ soundfocus_params.params.hdr.src_svc = APR_SVC_ADM;
+ soundfocus_params.params.hdr.src_domain = APR_DOMAIN_APPS;
+ soundfocus_params.params.hdr.src_port = port_id;
+ soundfocus_params.params.hdr.dest_svc = APR_SVC_ADM;
+ soundfocus_params.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ soundfocus_params.params.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ soundfocus_params.params.hdr.token = port_idx << 16 |
+ ADM_CLIENT_ID_SOURCE_TRACKING << 8 | copp_idx;
+ soundfocus_params.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ soundfocus_params.params.payload_addr_lsw = 0;
+ soundfocus_params.params.payload_addr_msw = 0;
+ soundfocus_params.params.mem_map_handle = 0;
+ soundfocus_params.params.payload_size = sizeof(soundfocus_params) -
+ sizeof(soundfocus_params.params);
+ soundfocus_params.data.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
+ soundfocus_params.data.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS;
+ soundfocus_params.data.param_size =
+ soundfocus_params.params.payload_size -
+ sizeof(soundfocus_params.data);
+ soundfocus_params.data.reserved = 0;
+
+ memset(&(soundfocus_params.soundfocus_data), 0xFF,
+ sizeof(struct adm_param_fluence_soundfocus_t));
+ for (i = 0; i < MAX_SECTORS; i++) {
+ soundfocus_params.soundfocus_data.start_angles[i] =
+ soundFocusData.start_angle[i];
+ soundfocus_params.soundfocus_data.enables[i] =
+ soundFocusData.enable[i];
+ pr_debug("%s: start_angle[%d] = %d\n",
+ __func__, i, soundFocusData.start_angle[i]);
+ pr_debug("%s: enable[%d] = %d\n",
+ __func__, i, soundFocusData.enable[i]);
+ }
+ soundfocus_params.soundfocus_data.gain_step =
+ soundFocusData.gain_step;
+ pr_debug("%s: gain_step = %d\n", __func__, soundFocusData.gain_step);
+
+ soundfocus_params.soundfocus_data.reserved = 0;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&soundfocus_params);
+ if (ret < 0) {
+ pr_err("%s: Set params failed\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Wait for the callback */
+ ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Set params timed out\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
+ pr_err("%s - set params returned error [%s]\n",
+ __func__, adsp_err_get_err_str(
+ this_adm.sourceTrackingData.apr_cmd_status));
+
+ ret = adsp_err_get_lnx_err_code(
+ this_adm.sourceTrackingData.apr_cmd_status);
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int adm_get_sound_focus(int port_id, int copp_idx,
+ struct sound_focus_param *soundFocusData)
+{
+ int ret = 0, i;
+ char *params_value;
+ uint32_t param_payload_len = sizeof(struct adm_param_data_v5) +
+ sizeof(struct adm_param_fluence_soundfocus_t);
+ struct adm_param_fluence_soundfocus_t *soundfocus_params;
+
+ pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
+ __func__, port_id, copp_idx);
+
+ params_value = kzalloc(param_payload_len, GFP_KERNEL);
+ if (!params_value) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ret = adm_get_params_v2(port_id, copp_idx,
+ VOICEPROC_MODULE_ID_GENERIC_TX,
+ VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS,
+ param_payload_len,
+ params_value,
+ ADM_CLIENT_ID_SOURCE_TRACKING);
+ if (ret) {
+ pr_err("%s: get parameters failed ret:%d\n", __func__, ret);
+
+ kfree(params_value);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
+ pr_err("%s - get params returned error [%s]\n",
+ __func__, adsp_err_get_err_str(
+ this_adm.sourceTrackingData.apr_cmd_status));
+
+ kfree(params_value);
+ ret = adsp_err_get_lnx_err_code(
+ this_adm.sourceTrackingData.apr_cmd_status);
+ goto done;
+ }
+
+ soundfocus_params = (struct adm_param_fluence_soundfocus_t *)
+ params_value;
+ for (i = 0; i < MAX_SECTORS; i++) {
+ soundFocusData->start_angle[i] =
+ soundfocus_params->start_angles[i];
+ soundFocusData->enable[i] = soundfocus_params->enables[i];
+ pr_debug("%s: start_angle[%d] = %d\n",
+ __func__, i, soundFocusData->start_angle[i]);
+ pr_debug("%s: enable[%d] = %d\n",
+ __func__, i, soundFocusData->enable[i]);
+ }
+ soundFocusData->gain_step = soundfocus_params->gain_step;
+ pr_debug("%s: gain_step = %d\n", __func__, soundFocusData->gain_step);
+
+ kfree(params_value);
+
+done:
+ pr_debug("%s: Exit, ret = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int adm_source_tracking_alloc_map_memory(void)
+{
+ int ret;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ ret = msm_audio_ion_alloc("SOURCE_TRACKING",
+ &this_adm.sourceTrackingData.ion_client,
+ &this_adm.sourceTrackingData.ion_handle,
+ AUD_PROC_BLOCK_SIZE,
+ &this_adm.sourceTrackingData.memmap.paddr,
+ &this_adm.sourceTrackingData.memmap.size,
+ &this_adm.sourceTrackingData.memmap.kvaddr);
+ if (ret) {
+ pr_err("%s: failed to allocate memory\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ atomic_set(&this_adm.mem_map_index, ADM_MEM_MAP_INDEX_SOURCE_TRACKING);
+ ret = adm_memory_map_regions(&this_adm.sourceTrackingData.memmap.paddr,
+ 0,
+ (uint32_t *)&this_adm.sourceTrackingData.memmap.size,
+ 1);
+ if (ret < 0) {
+ pr_err("%s: failed to map memory, paddr = 0x%pK, size = %d\n",
+ __func__,
+ (void *)this_adm.sourceTrackingData.memmap.paddr,
+ (uint32_t)this_adm.sourceTrackingData.memmap.size);
+
+ msm_audio_ion_free(this_adm.sourceTrackingData.ion_client,
+ this_adm.sourceTrackingData.ion_handle);
+ this_adm.sourceTrackingData.ion_client = NULL;
+ this_adm.sourceTrackingData.ion_handle = NULL;
+ this_adm.sourceTrackingData.memmap.size = 0;
+ this_adm.sourceTrackingData.memmap.kvaddr = NULL;
+ this_adm.sourceTrackingData.memmap.paddr = 0;
+ this_adm.sourceTrackingData.apr_cmd_status = -1;
+ atomic_set(&this_adm.mem_map_handles
+ [ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = 0;
+ pr_debug("%s: paddr = 0x%pK, size = %d, mem_map_handle = 0x%x\n",
+ __func__, (void *)this_adm.sourceTrackingData.memmap.paddr,
+ (uint32_t)this_adm.sourceTrackingData.memmap.size,
+ atomic_read(&this_adm.mem_map_handles
+ [ADM_MEM_MAP_INDEX_SOURCE_TRACKING]));
+
+done:
+ pr_debug("%s: Exit, ret = %d\n", __func__, ret);
+
+ return ret;
+}
+
+int adm_get_source_tracking(int port_id, int copp_idx,
+ struct source_tracking_param *sourceTrackingData)
+{
+ struct adm_cmd_get_pp_params_v5 admp;
+ int p_idx, ret = 0, i;
+ struct adm_param_fluence_sourcetracking_t *source_tracking_params;
+
+ pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
+ __func__, port_id, copp_idx);
+
+ if (!this_adm.sourceTrackingData.memmap.paddr) {
+ /* Allocate and map shared memory for out of band usage */
+ ret = adm_source_tracking_alloc_map_memory();
+ if (ret != 0) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+ p_idx = adm_validate_and_get_port_index(port_id);
+ if (p_idx < 0) {
+ pr_err("%s - invalid port index %i, port id %i, copp idx %i\n",
+ __func__, p_idx, port_id, copp_idx);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ admp.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ admp.hdr.pkt_size = sizeof(admp);
+ admp.hdr.src_svc = APR_SVC_ADM;
+ admp.hdr.src_domain = APR_DOMAIN_APPS;
+ admp.hdr.src_port = port_id;
+ admp.hdr.dest_svc = APR_SVC_ADM;
+ admp.hdr.dest_domain = APR_DOMAIN_ADSP;
+ admp.hdr.dest_port = atomic_read(&this_adm.copp.id[p_idx][copp_idx]);
+ admp.hdr.token = p_idx << 16 | ADM_CLIENT_ID_SOURCE_TRACKING << 8 |
+ copp_idx;
+ admp.hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5;
+ admp.data_payload_addr_lsw =
+ lower_32_bits(this_adm.sourceTrackingData.memmap.paddr);
+ admp.data_payload_addr_msw =
+ msm_audio_populate_upper_32_bits(
+ this_adm.sourceTrackingData.memmap.paddr);
+ admp.mem_map_handle = atomic_read(&this_adm.mem_map_handles[
+ ADM_MEM_MAP_INDEX_SOURCE_TRACKING]);
+ admp.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
+ admp.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOURCETRACKING;
+ admp.param_max_size = sizeof(struct adm_param_fluence_sourcetracking_t)
+ + sizeof(struct adm_param_data_v5);
+ admp.reserved = 0;
+
+ atomic_set(&this_adm.copp.stat[p_idx][copp_idx], -1);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&admp);
+ if (ret < 0) {
+ pr_err("%s - failed to get Source Tracking Params\n",
+ __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = wait_event_timeout(this_adm.copp.wait[p_idx][copp_idx],
+ atomic_read(&this_adm.copp.stat[p_idx][copp_idx]) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s - get params timed out\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ } else if (atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx]) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx])));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_adm.copp.stat
+ [p_idx][copp_idx]));
+ goto done;
+ }
+
+ if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
+ pr_err("%s - get params returned error [%s]\n",
+ __func__, adsp_err_get_err_str(
+ this_adm.sourceTrackingData.apr_cmd_status));
+
+ ret = adsp_err_get_lnx_err_code(
+ this_adm.sourceTrackingData.apr_cmd_status);
+ goto done;
+ }
+
+ source_tracking_params = (struct adm_param_fluence_sourcetracking_t *)
+ (this_adm.sourceTrackingData.memmap.kvaddr +
+ sizeof(struct adm_param_data_v5));
+ for (i = 0; i < MAX_SECTORS; i++) {
+ sourceTrackingData->vad[i] = source_tracking_params->vad[i];
+ pr_debug("%s: vad[%d] = %d\n",
+ __func__, i, sourceTrackingData->vad[i]);
+ }
+ sourceTrackingData->doa_speech = source_tracking_params->doa_speech;
+ pr_debug("%s: doa_speech = %d\n",
+ __func__, sourceTrackingData->doa_speech);
+
+ for (i = 0; i < MAX_NOISE_SOURCE_INDICATORS; i++) {
+ sourceTrackingData->doa_noise[i] =
+ source_tracking_params->doa_noise[i];
+ pr_debug("%s: doa_noise[%d] = %d\n",
+ __func__, i, sourceTrackingData->doa_noise[i]);
+ }
+ for (i = 0; i < MAX_POLAR_ACTIVITY_INDICATORS; i++) {
+ sourceTrackingData->polar_activity[i] =
+ source_tracking_params->polar_activity[i];
+ pr_debug("%s: polar_activity[%d] = %d\n",
+ __func__, i, sourceTrackingData->polar_activity[i]);
+ }
+
+ ret = 0;
+
+done:
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int __init adm_init(void)
+{
+ int i = 0, j;
+
+ this_adm.apr = NULL;
+ this_adm.ec_ref_rx = -1;
+ atomic_set(&this_adm.matrix_map_stat, 0);
+ init_waitqueue_head(&this_adm.matrix_map_wait);
+ atomic_set(&this_adm.adm_stat, 0);
+ init_waitqueue_head(&this_adm.adm_wait);
+
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+ atomic_set(&this_adm.copp.id[i][j], RESET_COPP_ID);
+ atomic_set(&this_adm.copp.cnt[i][j], 0);
+ atomic_set(&this_adm.copp.topology[i][j], 0);
+ atomic_set(&this_adm.copp.mode[i][j], 0);
+ atomic_set(&this_adm.copp.stat[i][j], 0);
+ atomic_set(&this_adm.copp.rate[i][j], 0);
+ atomic_set(&this_adm.copp.channels[i][j], 0);
+ atomic_set(&this_adm.copp.bit_width[i][j], 0);
+ atomic_set(&this_adm.copp.app_type[i][j], 0);
+ atomic_set(&this_adm.copp.acdb_id[i][j], 0);
+ init_waitqueue_head(&this_adm.copp.wait[i][j]);
+ atomic_set(&this_adm.copp.adm_delay_stat[i][j], 0);
+ init_waitqueue_head(
+ &this_adm.copp.adm_delay_wait[i][j]);
+ atomic_set(&this_adm.copp.topology[i][j], 0);
+ this_adm.copp.adm_delay[i][j] = 0;
+ this_adm.copp.adm_status[i][j] =
+ ADM_STATUS_CALIBRATION_REQUIRED;
+ }
+ }
+
+ if (adm_init_cal_data())
+ pr_err("%s: could not init cal data!\n", __func__);
+
+ this_adm.sourceTrackingData.ion_client = NULL;
+ this_adm.sourceTrackingData.ion_handle = NULL;
+ this_adm.sourceTrackingData.memmap.size = 0;
+ this_adm.sourceTrackingData.memmap.kvaddr = NULL;
+ this_adm.sourceTrackingData.memmap.paddr = 0;
+ this_adm.sourceTrackingData.apr_cmd_status = -1;
+ atomic_set(&this_adm.mem_map_handles[ADM_MEM_MAP_INDEX_SOURCE_TRACKING],
+ 0);
+
+ return 0;
+}
+
+static void __exit adm_exit(void)
+{
+ adm_delete_cal_data();
+}
+
+device_initcall(adm_init);
+module_exit(adm_exit);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
new file mode 100644
index 0000000..43c39d3
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -0,0 +1,6626 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/delay.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6audio-v2.h>
+#include "msm-pcm-routing-v2.h"
+#include <sound/audio_cal_utils.h>
+#include <sound/adsp_err.h>
+#include <linux/qdsp6v2/apr_tal.h>
+
+#define WAKELOCK_TIMEOUT 5000
+enum {
+ AFE_COMMON_RX_CAL = 0,
+ AFE_COMMON_TX_CAL,
+ AFE_AANC_CAL,
+ AFE_FB_SPKR_PROT_CAL,
+ AFE_HW_DELAY_CAL,
+ AFE_SIDETONE_CAL,
+ AFE_TOPOLOGY_CAL,
+ AFE_CUST_TOPOLOGY_CAL,
+ AFE_FB_SPKR_PROT_TH_VI_CAL,
+ AFE_FB_SPKR_PROT_EX_VI_CAL,
+ MAX_AFE_CAL_TYPES
+};
+
+enum fbsp_state {
+ FBSP_INCORRECT_OP_MODE,
+ FBSP_INACTIVE,
+ FBSP_WARMUP,
+ FBSP_IN_PROGRESS,
+ FBSP_SUCCESS,
+ FBSP_FAILED,
+ MAX_FBSP_STATE
+};
+
+static char fbsp_state[MAX_FBSP_STATE][50] = {
+ [FBSP_INCORRECT_OP_MODE] = "incorrect operation mode",
+ [FBSP_INACTIVE] = "port not started",
+ [FBSP_WARMUP] = "waiting for warmup",
+ [FBSP_IN_PROGRESS] = "in progress state",
+ [FBSP_SUCCESS] = "success",
+ [FBSP_FAILED] = "failed"
+};
+
+enum {
+ USE_CALIBRATED_R0TO,
+ USE_SAFE_R0TO
+};
+
+enum {
+ QUICK_CALIB_DISABLE,
+ QUICK_CALIB_ENABLE
+};
+
+enum {
+ Q6AFE_MSM_SPKR_PROCESSING = 0,
+ Q6AFE_MSM_SPKR_CALIBRATION,
+ Q6AFE_MSM_SPKR_FTM_MODE
+};
+
+struct wlock {
+ struct wakeup_source ws;
+};
+
+static struct wlock wl;
+
+struct afe_ctl {
+ void *apr;
+ atomic_t state;
+ atomic_t status;
+ wait_queue_head_t wait[AFE_MAX_PORTS];
+ struct task_struct *task;
+ void (*tx_cb)(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv);
+ void (*rx_cb)(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv);
+ void *tx_private_data;
+ void *rx_private_data;
+ uint32_t mmap_handle;
+
+ int topology[AFE_MAX_PORTS];
+ struct cal_type_data *cal_data[MAX_AFE_CAL_TYPES];
+
+ atomic_t mem_map_cal_handles[MAX_AFE_CAL_TYPES];
+ atomic_t mem_map_cal_index;
+ u32 afe_cal_mode[AFE_MAX_PORTS];
+
+ u16 dtmf_gen_rx_portid;
+ struct audio_cal_info_spk_prot_cfg prot_cfg;
+ struct afe_spkr_prot_calib_get_resp calib_data;
+ struct audio_cal_info_sp_th_vi_ftm_cfg th_ftm_cfg;
+ struct audio_cal_info_sp_ex_vi_ftm_cfg ex_ftm_cfg;
+ struct afe_sp_th_vi_get_param_resp th_vi_resp;
+ struct afe_sp_ex_vi_get_param_resp ex_vi_resp;
+ int vi_tx_port;
+ int vi_rx_port;
+ uint32_t afe_sample_rates[AFE_MAX_PORTS];
+ struct aanc_data aanc_info;
+ struct mutex afe_cmd_lock;
+ int set_custom_topology;
+};
+
+static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
+static unsigned long afe_configured_cmd;
+
+static struct afe_ctl this_afe;
+
+#define TIMEOUT_MS 1000
+#define Q6AFE_MAX_VOLUME 0x3FFF
+
+static int pcm_afe_instance[2];
+static int proxy_afe_instance[2];
+bool afe_close_done[2] = {true, true};
+
+#define SIZEOF_CFG_CMD(y) \
+ (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
+
+static int afe_get_cal_hw_delay(int32_t path,
+ struct audio_cal_hw_delay_entry *entry);
+static int remap_cal_data(struct cal_block_data *cal_block, int cal_index);
+
+int afe_get_topology(int port_id)
+{
+ int topology;
+ int port_index = afe_get_port_index(port_id);
+
+ if ((port_index < 0) || (port_index > AFE_MAX_PORTS)) {
+ pr_err("%s: Invalid port index %d\n", __func__, port_index);
+ topology = -EINVAL;
+ goto done;
+ }
+
+ topology = this_afe.topology[port_index];
+done:
+ return topology;
+}
+
+void afe_set_aanc_info(struct aanc_data *q6_aanc_info)
+{
+ this_afe.aanc_info.aanc_active = q6_aanc_info->aanc_active;
+ this_afe.aanc_info.aanc_rx_port = q6_aanc_info->aanc_rx_port;
+ this_afe.aanc_info.aanc_tx_port = q6_aanc_info->aanc_tx_port;
+
+ pr_debug("%s: aanc active is %d rx port is 0x%x, tx port is 0x%x\n",
+ __func__,
+ this_afe.aanc_info.aanc_active,
+ this_afe.aanc_info.aanc_rx_port,
+ this_afe.aanc_info.aanc_tx_port);
+}
+
+static void afe_callback_debug_print(struct apr_client_data *data)
+{
+ uint32_t *payload;
+
+ payload = data->payload;
+
+ if (data->payload_size >= 8)
+ pr_debug("%s: code = 0x%x PL#0[0x%x], PL#1[0x%x], size = %d\n",
+ __func__, data->opcode, payload[0], payload[1],
+ data->payload_size);
+ else if (data->payload_size >= 4)
+ pr_debug("%s: code = 0x%x PL#0[0x%x], size = %d\n",
+ __func__, data->opcode, payload[0],
+ data->payload_size);
+ else
+ pr_debug("%s: code = 0x%x, size = %d\n",
+ __func__, data->opcode, data->payload_size);
+}
+
+static int32_t sp_make_afe_callback(uint32_t *payload, uint32_t payload_size)
+{
+ u32 param_id;
+ struct afe_spkr_prot_calib_get_resp *resp =
+ (struct afe_spkr_prot_calib_get_resp *) payload;
+
+ if (!(&(resp->pdata))) {
+ pr_err("%s: Error: resp pdata is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ param_id = resp->pdata.param_id;
+ if (param_id == AFE_PARAM_ID_CALIB_RES_CFG_V2) {
+ if (payload_size < sizeof(this_afe.calib_data)) {
+ pr_err("%s: Error: received size %d, calib_data size %zu\n",
+ __func__, payload_size,
+ sizeof(this_afe.calib_data));
+ return -EINVAL;
+ }
+ memcpy(&this_afe.calib_data, payload,
+ sizeof(this_afe.calib_data));
+ if (!this_afe.calib_data.status) {
+ atomic_set(&this_afe.state, 0);
+ } else {
+ pr_debug("%s: calib resp status: %d", __func__,
+ this_afe.calib_data.status);
+ atomic_set(&this_afe.state, -1);
+ }
+ }
+ if (param_id == AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS) {
+ if (payload_size < sizeof(this_afe.th_vi_resp)) {
+ pr_err("%s: Error: received size %d, th_vi_resp size %zu\n",
+ __func__, payload_size,
+ sizeof(this_afe.th_vi_resp));
+ return -EINVAL;
+ }
+ memcpy(&this_afe.th_vi_resp, payload,
+ sizeof(this_afe.th_vi_resp));
+ if (!this_afe.th_vi_resp.status) {
+ atomic_set(&this_afe.state, 0);
+ } else {
+ pr_debug("%s: th vi resp status: %d", __func__,
+ this_afe.th_vi_resp.status);
+ atomic_set(&this_afe.state, -1);
+ }
+ }
+ if (param_id == AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS) {
+ if (payload_size < sizeof(this_afe.ex_vi_resp)) {
+ pr_err("%s: Error: received size %d, ex_vi_resp size %zu\n",
+ __func__, payload_size,
+ sizeof(this_afe.ex_vi_resp));
+ return -EINVAL;
+ }
+ memcpy(&this_afe.ex_vi_resp, payload,
+ sizeof(this_afe.ex_vi_resp));
+ if (!this_afe.ex_vi_resp.status) {
+ atomic_set(&this_afe.state, 0);
+ } else {
+ pr_debug("%s: ex vi resp status: %d", __func__,
+ this_afe.ex_vi_resp.status);
+ atomic_set(&this_afe.state, -1);
+ }
+ }
+
+ return 0;
+}
+
+static int32_t afe_callback(struct apr_client_data *data, void *priv)
+{
+ if (!data) {
+ pr_err("%s: Invalid param data\n", __func__);
+ return -EINVAL;
+ }
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: reset event = %d %d apr[%pK]\n",
+ __func__,
+ data->reset_event, data->reset_proc, this_afe.apr);
+
+ cal_utils_clear_cal_block_q6maps(MAX_AFE_CAL_TYPES,
+ this_afe.cal_data);
+
+ /* Reset the custom topology mode: to resend again to AFE. */
+ mutex_lock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
+ this_afe.set_custom_topology = 1;
+ mutex_unlock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
+
+ if (this_afe.apr) {
+ apr_reset(this_afe.apr);
+ atomic_set(&this_afe.state, 0);
+ this_afe.apr = NULL;
+ rtac_set_afe_handle(this_afe.apr);
+ }
+ /* send info to user */
+ if (this_afe.task == NULL)
+ this_afe.task = current;
+ pr_debug("%s: task_name = %s pid = %d\n",
+ __func__,
+ this_afe.task->comm, this_afe.task->pid);
+
+ /*
+ * Pass reset events to proxy driver, if cb is registered
+ */
+ if (this_afe.tx_cb) {
+ this_afe.tx_cb(data->opcode, data->token,
+ data->payload,
+ this_afe.tx_private_data);
+ this_afe.tx_cb = NULL;
+ }
+ if (this_afe.rx_cb) {
+ this_afe.rx_cb(data->opcode, data->token,
+ data->payload,
+ this_afe.rx_private_data);
+ this_afe.rx_cb = NULL;
+ }
+
+ return 0;
+ }
+ afe_callback_debug_print(data);
+ if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V2) {
+ u8 *payload = data->payload;
+
+ if (rtac_make_afe_callback(data->payload, data->payload_size))
+ return 0;
+
+ if (!payload || (data->token >= AFE_MAX_PORTS)) {
+ pr_err("%s: Error: size %d payload %pK token %d\n",
+ __func__, data->payload_size,
+ payload, data->token);
+ return -EINVAL;
+ }
+ if (sp_make_afe_callback(data->payload, data->payload_size))
+ return -EINVAL;
+
+ wake_up(&this_afe.wait[data->token]);
+ } else if (data->payload_size) {
+ uint32_t *payload;
+ uint16_t port_id = 0;
+
+ payload = data->payload;
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x token=%d\n",
+ __func__, data->opcode,
+ payload[0], payload[1], data->token);
+ /* payload[1] contains the error status for response */
+ if (payload[1] != 0) {
+ atomic_set(&this_afe.status, payload[1]);
+ pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+ __func__, payload[0], payload[1]);
+ }
+ switch (payload[0]) {
+ case AFE_PORT_CMD_SET_PARAM_V2:
+ if (rtac_make_afe_callback(payload,
+ data->payload_size))
+ return 0;
+ case AFE_PORT_CMD_DEVICE_STOP:
+ case AFE_PORT_CMD_DEVICE_START:
+ case AFE_PSEUDOPORT_CMD_START:
+ case AFE_PSEUDOPORT_CMD_STOP:
+ case AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS:
+ case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
+ case AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER:
+ case AFE_PORTS_CMD_DTMF_CTL:
+ case AFE_SVC_CMD_SET_PARAM:
+ atomic_set(&this_afe.state, 0);
+ wake_up(&this_afe.wait[data->token]);
+ break;
+ case AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER:
+ break;
+ case AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2:
+ port_id = RT_PROXY_PORT_001_TX;
+ break;
+ case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2:
+ port_id = RT_PROXY_PORT_001_RX;
+ break;
+ case AFE_CMD_ADD_TOPOLOGIES:
+ atomic_set(&this_afe.state, 0);
+ wake_up(&this_afe.wait[data->token]);
+ pr_debug("%s: AFE_CMD_ADD_TOPOLOGIES cmd 0x%x\n",
+ __func__, payload[1]);
+ break;
+ default:
+ pr_err("%s: Unknown cmd 0x%x\n", __func__,
+ payload[0]);
+ break;
+ }
+ } else if (data->opcode ==
+ AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS) {
+ pr_debug("%s: mmap_handle: 0x%x, cal index %d\n",
+ __func__, payload[0],
+ atomic_read(&this_afe.mem_map_cal_index));
+ if (atomic_read(&this_afe.mem_map_cal_index) != -1)
+ atomic_set(&this_afe.mem_map_cal_handles[
+ atomic_read(
+ &this_afe.mem_map_cal_index)],
+ (uint32_t)payload[0]);
+ else
+ this_afe.mmap_handle = payload[0];
+ atomic_set(&this_afe.state, 0);
+ wake_up(&this_afe.wait[data->token]);
+ } else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
+ port_id = (uint16_t)(0x0000FFFF & payload[0]);
+ }
+ pr_debug("%s: port_id = 0x%x\n", __func__, port_id);
+ switch (port_id) {
+ case RT_PROXY_PORT_001_TX: {
+ if (this_afe.tx_cb) {
+ this_afe.tx_cb(data->opcode, data->token,
+ data->payload,
+ this_afe.tx_private_data);
+ }
+ break;
+ }
+ case RT_PROXY_PORT_001_RX: {
+ if (this_afe.rx_cb) {
+ this_afe.rx_cb(data->opcode, data->token,
+ data->payload,
+ this_afe.rx_private_data);
+ }
+ break;
+ }
+ default:
+ pr_debug("%s: default case 0x%x\n", __func__, port_id);
+ break;
+ }
+ }
+ return 0;
+}
+
+int afe_get_port_type(u16 port_id)
+{
+ int ret;
+
+ switch (port_id) {
+ case PRIMARY_I2S_RX:
+ case SECONDARY_I2S_RX:
+ case MI2S_RX:
+ case HDMI_RX:
+ case DISPLAY_PORT_RX:
+ case AFE_PORT_ID_SPDIF_RX:
+ case SLIMBUS_0_RX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_5_RX:
+ case SLIMBUS_6_RX:
+ case SLIMBUS_7_RX:
+ case SLIMBUS_8_RX:
+ case INT_BT_SCO_RX:
+ case INT_BT_A2DP_RX:
+ case INT_FM_RX:
+ case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
+ case RT_PROXY_PORT_001_RX:
+ case AUDIO_PORT_ID_I2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUINARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ case AFE_PORT_ID_USB_RX:
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ ret = MSM_AFE_PORT_TYPE_RX;
+ break;
+
+ case PRIMARY_I2S_TX:
+ case SECONDARY_I2S_TX:
+ case MI2S_TX:
+ case DIGI_MIC_TX:
+ case VOICE_RECORD_TX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
+ case SLIMBUS_6_TX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_TX:
+ case INT_FM_TX:
+ case VOICE_RECORD_RX:
+ case INT_BT_SCO_TX:
+ case RT_PROXY_PORT_001_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_QUINARY_MI2S_TX:
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ case AFE_PORT_ID_USB_TX:
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ case AFE_PORT_ID_INT6_MI2S_TX:
+ ret = MSM_AFE_PORT_TYPE_TX;
+ break;
+
+ default:
+ WARN_ON(1);
+ pr_err("%s: Invalid port id = 0x%x\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int afe_sizeof_cfg_cmd(u16 port_id)
+{
+ int ret_size;
+
+ switch (port_id) {
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
+ case SECONDARY_I2S_RX:
+ case SECONDARY_I2S_TX:
+ case MI2S_RX:
+ case MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_QUINARY_MI2S_RX:
+ case AFE_PORT_ID_QUINARY_MI2S_TX:
+ ret_size = SIZEOF_CFG_CMD(afe_param_id_i2s_cfg);
+ break;
+ case HDMI_RX:
+ case DISPLAY_PORT_RX:
+ ret_size =
+ SIZEOF_CFG_CMD(afe_param_id_hdmi_multi_chan_audio_cfg);
+ break;
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_4_TX:
+ case SLIMBUS_5_RX:
+ case SLIMBUS_5_TX:
+ case SLIMBUS_6_RX:
+ case SLIMBUS_6_TX:
+ case SLIMBUS_7_RX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_RX:
+ case SLIMBUS_8_TX:
+ ret_size = SIZEOF_CFG_CMD(afe_param_id_slimbus_cfg);
+ break;
+ case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ ret_size = SIZEOF_CFG_CMD(afe_param_id_pseudo_port_cfg);
+ break;
+ case RT_PROXY_PORT_001_RX:
+ case RT_PROXY_PORT_001_TX:
+ ret_size = SIZEOF_CFG_CMD(afe_param_id_rt_proxy_port_cfg);
+ break;
+ case AFE_PORT_ID_USB_RX:
+ case AFE_PORT_ID_USB_TX:
+ ret_size = SIZEOF_CFG_CMD(afe_param_id_usb_audio_cfg);
+ break;
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ default:
+ pr_debug("%s: default case 0x%x\n", __func__, port_id);
+ ret_size = SIZEOF_CFG_CMD(afe_param_id_pcm_cfg);
+ break;
+ }
+ return ret_size;
+}
+
+int afe_q6_interface_prepare(void)
+{
+ int ret = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+ return ret;
+}
+
+/*
+ * afe_apr_send_pkt : returns 0 on success, negative otherwise.
+ */
+static int afe_apr_send_pkt(void *data, wait_queue_head_t *wait)
+{
+ int ret;
+
+ if (wait)
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, data);
+ if (ret > 0) {
+ if (wait) {
+ ret = wait_event_timeout(*wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ ret = -ETIMEDOUT;
+ } else if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: DSP returned error[%s]\n", __func__,
+ adsp_err_get_err_str(atomic_read(
+ &this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ } else {
+ ret = 0;
+ }
+ } else {
+ ret = 0;
+ }
+ } else if (ret == 0) {
+ pr_err("%s: packet not transmitted\n", __func__);
+ /* apr_send_pkt can return 0 when nothing is transmitted */
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_send_cal_block(u16 port_id, struct cal_block_data *cal_block)
+{
+ int result = 0;
+ int index = 0;
+ struct afe_audioif_config_command_no_payload afe_cal;
+
+ if (!cal_block) {
+ pr_debug("%s: No AFE cal to send!\n", __func__);
+ result = -EINVAL;
+ goto done;
+ }
+ if (cal_block->cal_data.size <= 0) {
+ pr_debug("%s: AFE cal has invalid size!\n", __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ result = -EINVAL;
+ goto done;
+ }
+
+ afe_cal.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ afe_cal.hdr.pkt_size = sizeof(afe_cal);
+ afe_cal.hdr.src_port = 0;
+ afe_cal.hdr.dest_port = 0;
+ afe_cal.hdr.token = index;
+ afe_cal.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ afe_cal.param.port_id = port_id;
+ afe_cal.param.payload_size = cal_block->cal_data.size;
+ afe_cal.param.payload_address_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ afe_cal.param.payload_address_msw =
+ msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
+ afe_cal.param.mem_map_handle = cal_block->map_data.q6map_handle;
+
+ pr_debug("%s: AFE cal sent for device port = 0x%x, cal size = %zd, cal addr = 0x%pK\n",
+ __func__, port_id,
+ cal_block->cal_data.size, &cal_block->cal_data.paddr);
+
+ result = afe_apr_send_pkt(&afe_cal, &this_afe.wait[index]);
+ if (result)
+ pr_err("%s: AFE cal for port 0x%x failed %d\n",
+ __func__, port_id, result);
+
+done:
+ return result;
+}
+
+
+static int afe_send_custom_topology_block(struct cal_block_data *cal_block)
+{
+ int result = 0;
+ int index = 0;
+ struct cmd_set_topologies afe_cal;
+
+ if (!cal_block) {
+ pr_err("%s: No AFE SVC cal to send!\n", __func__);
+ return -EINVAL;
+ }
+ if (cal_block->cal_data.size <= 0) {
+ pr_err("%s: AFE SVC cal has invalid size: %zd!\n",
+ __func__, cal_block->cal_data.size);
+ return -EINVAL;
+ }
+
+ afe_cal.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ afe_cal.hdr.pkt_size = sizeof(afe_cal);
+ afe_cal.hdr.src_port = 0;
+ afe_cal.hdr.dest_port = 0;
+ afe_cal.hdr.token = index;
+ afe_cal.hdr.opcode = AFE_CMD_ADD_TOPOLOGIES;
+
+ afe_cal.payload_size = cal_block->cal_data.size;
+ afe_cal.payload_addr_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ afe_cal.payload_addr_msw =
+ msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
+ afe_cal.mem_map_handle = cal_block->map_data.q6map_handle;
+
+ pr_debug("%s:cmd_id:0x%x calsize:%zd memmap_hdl:0x%x caladdr:0x%pK",
+ __func__, AFE_CMD_ADD_TOPOLOGIES, cal_block->cal_data.size,
+ afe_cal.mem_map_handle, &cal_block->cal_data.paddr);
+
+ result = afe_apr_send_pkt(&afe_cal, &this_afe.wait[index]);
+ if (result)
+ pr_err("%s: AFE send topology for command 0x%x failed %d\n",
+ __func__, AFE_CMD_ADD_TOPOLOGIES, result);
+
+ return result;
+}
+
+static void afe_send_custom_topology(void)
+{
+ struct cal_block_data *cal_block = NULL;
+ int cal_index = AFE_CUST_TOPOLOGY_CAL;
+ int ret;
+
+ if (this_afe.cal_data[cal_index] == NULL) {
+ pr_err("%s: cal_index %d not allocated!\n",
+ __func__, cal_index);
+ return;
+ }
+ mutex_lock(&this_afe.cal_data[cal_index]->lock);
+
+ if (!this_afe.set_custom_topology)
+ goto unlock;
+ this_afe.set_custom_topology = 0;
+ cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]);
+ if (cal_block == NULL) {
+ pr_err("%s cal_block not found!!\n", __func__);
+ goto unlock;
+ }
+
+ pr_debug("%s: Sending cal_index cal %d\n", __func__, cal_index);
+
+ ret = remap_cal_data(cal_block, cal_index);
+ if (ret) {
+ pr_err("%s: Remap_cal_data failed for cal %d!\n",
+ __func__, cal_index);
+ goto unlock;
+ }
+ ret = afe_send_custom_topology_block(cal_block);
+ if (ret < 0) {
+ pr_err("%s: No cal sent for cal_index %d! ret %d\n",
+ __func__, cal_index, ret);
+ goto unlock;
+ }
+ pr_debug("%s:sent custom topology for AFE\n", __func__);
+unlock:
+ mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+}
+
+static int afe_spk_ramp_dn_cfg(int port)
+{
+ int ret = -EINVAL;
+ int index = 0;
+ struct afe_spkr_prot_config_command config;
+
+ if (afe_get_port_type(port) != MSM_AFE_PORT_TYPE_RX) {
+ pr_debug("%s: port doesn't match 0x%x\n", __func__, port);
+ return 0;
+ }
+ if (this_afe.prot_cfg.mode == MSM_SPKR_PROT_DISABLED ||
+ (this_afe.vi_rx_port != port)) {
+ pr_debug("%s: spkr protection disabled port 0x%x %d 0x%x\n",
+ __func__, port, ret, this_afe.vi_rx_port);
+ return 0;
+ }
+ memset(&config, 0, sizeof(config));
+ ret = q6audio_validate_port(port);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d", __func__, port, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(port);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port);
+ config.param.payload_size =
+ sizeof(config) - sizeof(config.hdr) - sizeof(config.param)
+ - sizeof(config.prot_config);
+ config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_V2_RX;
+ config.pdata.param_id = AFE_PARAM_ID_FBSP_PTONE_RAMP_CFG;
+ config.pdata.param_size = 0;
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+ if (ret < 0) {
+ pr_err("%s: port = 0x%x param = 0x%x failed %d\n",
+ __func__, port, config.pdata.param_id, ret);
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+ /* dsp needs atleast 15ms to ramp down pilot tone*/
+ usleep_range(15000, 15010);
+ ret = 0;
+fail_cmd:
+ pr_debug("%s: config.pdata.param_id 0x%x status %d\n",
+ __func__, config.pdata.param_id, ret);
+return ret;
+}
+
+static int afe_spk_prot_prepare(int src_port, int dst_port, int param_id,
+ union afe_spkr_prot_config *prot_config)
+{
+ int ret = -EINVAL;
+ int index = 0;
+ struct afe_spkr_prot_config_command config;
+
+ memset(&config, 0, sizeof(config));
+ if (!prot_config) {
+ pr_err("%s: Invalid params\n", __func__);
+ goto fail_cmd;
+ }
+ ret = q6audio_validate_port(src_port);
+ if (ret < 0) {
+ pr_err("%s: Invalid src port 0x%x ret %d",
+ __func__, src_port, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = q6audio_validate_port(dst_port);
+ if (ret < 0) {
+ pr_err("%s: Invalid dst port 0x%x ret %d", __func__,
+ dst_port, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(src_port);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ switch (param_id) {
+ case AFE_PARAM_ID_FBSP_MODE_RX_CFG:
+ config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_V2_RX;
+ break;
+ case AFE_PARAM_ID_FEEDBACK_PATH_CFG:
+ this_afe.vi_tx_port = src_port;
+ this_afe.vi_rx_port = dst_port;
+ config.pdata.module_id = AFE_MODULE_FEEDBACK;
+ break;
+ /*
+ * AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2 is same as
+ * AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG
+ */
+ case AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2:
+ case AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG:
+ config.pdata.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
+ break;
+ case AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG:
+ case AFE_PARAM_ID_SP_V2_EX_VI_FTM_CFG:
+ config.pdata.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI;
+ break;
+ default:
+ pr_err("%s: default case 0x%x\n", __func__, param_id);
+ goto fail_cmd;
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(src_port);
+ config.param.payload_size = sizeof(config) - sizeof(config.hdr)
+ - sizeof(config.param);
+ config.pdata.param_id = param_id;
+ config.pdata.param_size = sizeof(config.prot_config);
+ config.prot_config = *prot_config;
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+ if (ret < 0) {
+ pr_err("%s: port = 0x%x param = 0x%x failed %d\n",
+ __func__, src_port, param_id, ret);
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+ ret = 0;
+fail_cmd:
+ pr_debug("%s: config.pdata.param_id 0x%x status %d 0x%x\n",
+ __func__, config.pdata.param_id, ret, src_port);
+ return ret;
+}
+
+static void afe_send_cal_spkr_prot_tx(int port_id)
+{
+ union afe_spkr_prot_config afe_spk_config;
+
+ if (this_afe.cal_data[AFE_FB_SPKR_PROT_CAL] == NULL ||
+ this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
+ this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL] == NULL)
+ return;
+
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
+ if ((this_afe.prot_cfg.mode != MSM_SPKR_PROT_DISABLED) &&
+ (this_afe.vi_tx_port == port_id)) {
+ if (this_afe.prot_cfg.mode ==
+ MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS) {
+ afe_spk_config.vi_proc_cfg.operation_mode =
+ Q6AFE_MSM_SPKR_CALIBRATION;
+ afe_spk_config.vi_proc_cfg.quick_calib_flag =
+ this_afe.prot_cfg.quick_calib_flag;
+ } else {
+ afe_spk_config.vi_proc_cfg.operation_mode =
+ Q6AFE_MSM_SPKR_PROCESSING;
+ }
+
+ if (this_afe.th_ftm_cfg.mode == MSM_SPKR_PROT_IN_FTM_MODE)
+ afe_spk_config.vi_proc_cfg.operation_mode =
+ Q6AFE_MSM_SPKR_FTM_MODE;
+ afe_spk_config.vi_proc_cfg.minor_version = 1;
+ afe_spk_config.vi_proc_cfg.r0_cali_q24[SP_V2_SPKR_1] =
+ (uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_1];
+ afe_spk_config.vi_proc_cfg.r0_cali_q24[SP_V2_SPKR_2] =
+ (uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_2];
+ afe_spk_config.vi_proc_cfg.t0_cali_q6[SP_V2_SPKR_1] =
+ (uint32_t) this_afe.prot_cfg.t0[SP_V2_SPKR_1];
+ afe_spk_config.vi_proc_cfg.t0_cali_q6[SP_V2_SPKR_2] =
+ (uint32_t) this_afe.prot_cfg.t0[SP_V2_SPKR_2];
+ if (this_afe.prot_cfg.mode != MSM_SPKR_PROT_NOT_CALIBRATED) {
+ struct asm_spkr_calib_vi_proc_cfg *vi_proc_cfg;
+
+ vi_proc_cfg = &afe_spk_config.vi_proc_cfg;
+ vi_proc_cfg->r0_t0_selection_flag[SP_V2_SPKR_1] =
+ USE_CALIBRATED_R0TO;
+ vi_proc_cfg->r0_t0_selection_flag[SP_V2_SPKR_2] =
+ USE_CALIBRATED_R0TO;
+ } else {
+ struct asm_spkr_calib_vi_proc_cfg *vi_proc_cfg;
+
+ vi_proc_cfg = &afe_spk_config.vi_proc_cfg;
+ vi_proc_cfg->r0_t0_selection_flag[SP_V2_SPKR_1] =
+ USE_SAFE_R0TO;
+ vi_proc_cfg->r0_t0_selection_flag[SP_V2_SPKR_2] =
+ USE_SAFE_R0TO;
+ }
+ if (afe_spk_prot_prepare(port_id, 0,
+ AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2,
+ &afe_spk_config))
+ pr_err("%s: SPKR_CALIB_VI_PROC_CFG failed\n",
+ __func__);
+ }
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
+
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+ if ((this_afe.th_ftm_cfg.mode == MSM_SPKR_PROT_IN_FTM_MODE) &&
+ (this_afe.vi_tx_port == port_id)) {
+ afe_spk_config.th_vi_ftm_cfg.minor_version = 1;
+ afe_spk_config.th_vi_ftm_cfg.wait_time_ms[SP_V2_SPKR_1] =
+ this_afe.th_ftm_cfg.wait_time[SP_V2_SPKR_1];
+ afe_spk_config.th_vi_ftm_cfg.wait_time_ms[SP_V2_SPKR_2] =
+ this_afe.th_ftm_cfg.wait_time[SP_V2_SPKR_2];
+ afe_spk_config.th_vi_ftm_cfg.ftm_time_ms[SP_V2_SPKR_1] =
+ this_afe.th_ftm_cfg.ftm_time[SP_V2_SPKR_1];
+ afe_spk_config.th_vi_ftm_cfg.ftm_time_ms[SP_V2_SPKR_2] =
+ this_afe.th_ftm_cfg.ftm_time[SP_V2_SPKR_2];
+
+ if (afe_spk_prot_prepare(port_id, 0,
+ AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG,
+ &afe_spk_config))
+ pr_err("%s: th vi ftm cfg failed\n", __func__);
+ this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
+ }
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
+ if ((this_afe.ex_ftm_cfg.mode == MSM_SPKR_PROT_IN_FTM_MODE) &&
+ (this_afe.vi_tx_port == port_id)) {
+ afe_spk_config.ex_vi_mode_cfg.minor_version = 1;
+ afe_spk_config.ex_vi_mode_cfg.operation_mode =
+ Q6AFE_MSM_SPKR_FTM_MODE;
+ if (afe_spk_prot_prepare(port_id, 0,
+ AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG,
+ &afe_spk_config))
+ pr_err("%s: ex vi mode cfg failed\n", __func__);
+
+ afe_spk_config.ex_vi_ftm_cfg.minor_version = 1;
+ afe_spk_config.ex_vi_ftm_cfg.wait_time_ms[SP_V2_SPKR_1] =
+ this_afe.ex_ftm_cfg.wait_time[SP_V2_SPKR_1];
+ afe_spk_config.ex_vi_ftm_cfg.wait_time_ms[SP_V2_SPKR_2] =
+ this_afe.ex_ftm_cfg.wait_time[SP_V2_SPKR_2];
+ afe_spk_config.ex_vi_ftm_cfg.ftm_time_ms[SP_V2_SPKR_1] =
+ this_afe.ex_ftm_cfg.ftm_time[SP_V2_SPKR_1];
+ afe_spk_config.ex_vi_ftm_cfg.ftm_time_ms[SP_V2_SPKR_2] =
+ this_afe.ex_ftm_cfg.ftm_time[SP_V2_SPKR_2];
+
+ if (afe_spk_prot_prepare(port_id, 0,
+ AFE_PARAM_ID_SP_V2_EX_VI_FTM_CFG,
+ &afe_spk_config))
+ pr_err("%s: ex vi ftm cfg failed\n", __func__);
+ this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
+ }
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
+
+}
+
+static void afe_send_cal_spkr_prot_rx(int port_id)
+{
+ union afe_spkr_prot_config afe_spk_config;
+
+ if (this_afe.cal_data[AFE_FB_SPKR_PROT_CAL] == NULL)
+ goto done;
+
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
+
+ if (this_afe.prot_cfg.mode != MSM_SPKR_PROT_DISABLED &&
+ (this_afe.vi_rx_port == port_id)) {
+ if (this_afe.prot_cfg.mode ==
+ MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS)
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_CALIBRATION;
+ else
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_PROCESSING;
+ afe_spk_config.mode_rx_cfg.minor_version = 1;
+ if (afe_spk_prot_prepare(port_id, 0,
+ AFE_PARAM_ID_FBSP_MODE_RX_CFG,
+ &afe_spk_config))
+ pr_err("%s: RX MODE_VI_PROC_CFG failed\n",
+ __func__);
+ }
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
+done:
+ return;
+}
+
+static int afe_send_hw_delay(u16 port_id, u32 rate)
+{
+ struct audio_cal_hw_delay_entry delay_entry;
+ struct afe_audioif_config_command config;
+ int index = 0;
+ int ret = -EINVAL;
+
+ pr_debug("%s:\n", __func__);
+
+ delay_entry.sample_rate = rate;
+ if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+ ret = afe_get_cal_hw_delay(TX_DEVICE, &delay_entry);
+ else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+ ret = afe_get_cal_hw_delay(RX_DEVICE, &delay_entry);
+
+ /*
+ * HW delay is only used for IMS calls to sync audio with video
+ * It is only needed for devices & sample rates used for IMS video
+ * calls. Values are received from ACDB calbration files
+ */
+ if (ret != 0) {
+ pr_debug("%s: debug: HW delay info not available %d\n",
+ __func__, ret);
+ goto fail_cmd;
+ }
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY;
+ config.pdata.param_size = sizeof(config.port);
+
+ config.port.hw_delay.delay_in_us = delay_entry.delay_usec;
+ config.port.hw_delay.device_hw_delay_minor_version =
+ AFE_API_VERSION_DEVICE_HW_DELAY;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE hw delay for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ pr_debug("%s: port_id 0x%x rate %u delay_usec %d status %d\n",
+ __func__, port_id, rate, delay_entry.delay_usec, ret);
+ return ret;
+}
+
+static struct cal_block_data *afe_find_cal_topo_id_by_port(
+ struct cal_type_data *cal_type, u16 port_id)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+ int32_t path;
+ struct audio_cal_info_afe_top *afe_top;
+
+ list_for_each_safe(ptr, next,
+ &cal_type->cal_blocks) {
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ path = ((afe_get_port_type(port_id) ==
+ MSM_AFE_PORT_TYPE_TX)?(TX_DEVICE):(RX_DEVICE));
+ afe_top =
+ (struct audio_cal_info_afe_top *)cal_block->cal_info;
+ if (afe_top->path == path) {
+ pr_debug("%s: top_id:%x acdb_id:%d afe_port:%d\n",
+ __func__, afe_top->topology, afe_top->acdb_id,
+ q6audio_get_port_id(port_id));
+ return cal_block;
+ }
+ }
+ return NULL;
+}
+
+static int afe_get_cal_topology_id(u16 port_id, u32 *topology_id)
+{
+ int ret = 0;
+
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_afe_top *afe_top_info = NULL;
+
+ if (this_afe.cal_data[AFE_TOPOLOGY_CAL] == NULL) {
+ pr_err("%s: [AFE_TOPOLOGY_CAL] not initialized\n", __func__);
+ return -EINVAL;
+ }
+ if (topology_id == NULL) {
+ pr_err("%s: topology_id is NULL\n", __func__);
+ return -EINVAL;
+ }
+ *topology_id = 0;
+
+ mutex_lock(&this_afe.cal_data[AFE_TOPOLOGY_CAL]->lock);
+ cal_block = afe_find_cal_topo_id_by_port(
+ this_afe.cal_data[AFE_TOPOLOGY_CAL], port_id);
+ if (cal_block == NULL) {
+ pr_err("%s: [AFE_TOPOLOGY_CAL] not initialized for this port %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ afe_top_info = ((struct audio_cal_info_afe_top *)
+ cal_block->cal_info);
+ if (!afe_top_info->topology) {
+ pr_err("%s: invalid topology id : [%d, %d]\n",
+ __func__, afe_top_info->acdb_id, afe_top_info->topology);
+ ret = -EINVAL;
+ goto unlock;
+ }
+ *topology_id = (u32)afe_top_info->topology;
+
+ pr_debug("%s: port_id = %u acdb_id = %d topology_id = %u ret=%d\n",
+ __func__, port_id, afe_top_info->acdb_id,
+ afe_top_info->topology, ret);
+unlock:
+ mutex_unlock(&this_afe.cal_data[AFE_TOPOLOGY_CAL]->lock);
+ return ret;
+}
+
+static int afe_send_port_topology_id(u16 port_id)
+{
+ struct afe_audioif_config_command config;
+ int index = 0;
+ int ret = 0;
+ u32 topology_id = 0;
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS - 1) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+
+ ret = afe_get_cal_topology_id(port_id, &topology_id);
+ if (ret || !topology_id) {
+ pr_debug("%s: AFE port[%d] get_cal_topology[%d] invalid!\n",
+ __func__, port_id, topology_id);
+ goto done;
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ config.pdata.param_id = AFE_PARAM_ID_SET_TOPOLOGY;
+ config.pdata.param_size = sizeof(config.port);
+ config.port.topology.minor_version = AFE_API_VERSION_TOPOLOGY_V1;
+ config.port.topology.topology_id = topology_id;
+
+ pr_debug("%s: param PL size=%d iparam_size[%d][%zd %zd %zd %zd] param_id[0x%x]\n",
+ __func__, config.param.payload_size, config.pdata.param_size,
+ sizeof(config), sizeof(config.param), sizeof(config.port),
+ sizeof(struct apr_hdr), config.pdata.param_id);
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE set topology id enable for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto done;
+ }
+
+ this_afe.topology[index] = topology_id;
+done:
+ pr_debug("%s: AFE set topology id 0x%x enable for port 0x%x ret %d\n",
+ __func__, topology_id, port_id, ret);
+ return ret;
+
+}
+
+static int remap_cal_data(struct cal_block_data *cal_block, int cal_index)
+{
+ int ret = 0;
+
+ if (cal_block->map_data.ion_client == NULL) {
+ pr_err("%s: No ION allocation for cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((cal_block->map_data.map_size > 0) &&
+ (cal_block->map_data.q6map_handle == 0)) {
+ atomic_set(&this_afe.mem_map_cal_index, cal_index);
+ ret = afe_cmd_memory_map(cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+ atomic_set(&this_afe.mem_map_cal_index, -1);
+ if (ret < 0) {
+ pr_err("%s: mmap did not work! size = %zd ret %d\n",
+ __func__,
+ cal_block->map_data.map_size, ret);
+ pr_debug("%s: mmap did not work! addr = 0x%pK, size = %zd\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+ goto done;
+ }
+ cal_block->map_data.q6map_handle = atomic_read(&this_afe.
+ mem_map_cal_handles[cal_index]);
+ }
+done:
+ return ret;
+}
+
+static void send_afe_cal_type(int cal_index, int port_id)
+{
+ struct cal_block_data *cal_block = NULL;
+ int ret;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.cal_data[cal_index] == NULL) {
+ pr_warn("%s: cal_index %d not allocated!\n",
+ __func__, cal_index);
+ goto done;
+ }
+
+ mutex_lock(&this_afe.cal_data[cal_index]->lock);
+ cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]);
+ if (cal_block == NULL) {
+ pr_err("%s cal_block not found!!\n", __func__);
+ goto unlock;
+ }
+
+ pr_debug("%s: Sending cal_index cal %d\n", __func__, cal_index);
+
+ ret = remap_cal_data(cal_block, cal_index);
+ if (ret) {
+ pr_err("%s: Remap_cal_data failed for cal %d!\n",
+ __func__, cal_index);
+ goto unlock;
+ }
+ ret = afe_send_cal_block(port_id, cal_block);
+ if (ret < 0)
+ pr_debug("%s: No cal sent for cal_index %d, port_id = 0x%x! ret %d\n",
+ __func__, cal_index, port_id, ret);
+unlock:
+ mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+done:
+ return;
+}
+
+void afe_send_cal(u16 port_id)
+{
+ pr_debug("%s: port_id=0x%x\n", __func__, port_id);
+
+ if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) {
+ afe_send_cal_spkr_prot_tx(port_id);
+ send_afe_cal_type(AFE_COMMON_TX_CAL, port_id);
+ } else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) {
+ afe_send_cal_spkr_prot_rx(port_id);
+ send_afe_cal_type(AFE_COMMON_RX_CAL, port_id);
+ }
+}
+
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 enable)
+{
+ int ret;
+ struct afe_cmd_hw_mad_ctrl config;
+
+ pr_debug("%s: enter\n", __func__);
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = SLIMBUS_5_TX;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_HW_MAD;
+ config.pdata.param_id = AFE_PARAM_ID_HW_MAD_CTRL;
+ config.pdata.param_size = sizeof(config.payload);
+ config.payload.minor_version = 1;
+ config.payload.mad_type = mad_type;
+ config.payload.mad_enable = enable;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_HW_MAD_CTRL failed %d\n", __func__,
+ ret);
+ return ret;
+}
+
+static int afe_send_slimbus_slave_cfg(
+ struct afe_param_cdc_slimbus_slave_cfg *sb_slave_cfg)
+{
+ int ret;
+ struct afe_svc_cmd_sb_slave_cfg config;
+
+ pr_debug("%s: enter\n", __func__);
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG;
+ config.pdata.param_size =
+ sizeof(struct afe_param_cdc_slimbus_slave_cfg);
+ config.sb_slave_cfg = *sb_slave_cfg;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG failed %d\n",
+ __func__, ret);
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_send_codec_reg_page_config(
+ struct afe_param_cdc_reg_page_cfg *cdc_reg_page_cfg)
+{
+ struct afe_svc_cmd_cdc_reg_page_cfg config;
+ int ret;
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CDC_REG_PAGE_CFG;
+ config.pdata.param_size =
+ sizeof(struct afe_param_cdc_reg_page_cfg);
+ config.cdc_reg_page_cfg = *cdc_reg_page_cfg;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_CDC_REG_PAGE_CFG failed %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int afe_send_codec_reg_config(
+ struct afe_param_cdc_reg_cfg_data *cdc_reg_cfg)
+{
+ int i, j, ret = -EINVAL;
+ int pkt_size, payload_size, reg_per_pkt, num_pkts, num_regs;
+ struct afe_svc_cmd_cdc_reg_cfg *config;
+ struct afe_svc_cmd_set_param *param;
+
+ reg_per_pkt = (APR_MAX_BUF - sizeof(*config)) /
+ sizeof(struct afe_param_cdc_reg_cfg_payload);
+ if (reg_per_pkt > 0) {
+ num_pkts = (cdc_reg_cfg->num_registers / reg_per_pkt) +
+ (cdc_reg_cfg->num_registers % reg_per_pkt == 0 ? 0 : 1);
+ } else {
+ pr_err("%s: Failed to build codec reg config APR packet\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < num_pkts; ++j) {
+ /*
+ * num_regs is set to reg_per_pkt on each pass through the loop
+ * except the last, when it is set to the number of registers
+ * remaining from the total
+ */
+ num_regs = (j < (num_pkts - 1) ? reg_per_pkt :
+ cdc_reg_cfg->num_registers - (reg_per_pkt * j));
+ payload_size = sizeof(struct afe_param_cdc_reg_cfg_payload) *
+ num_regs;
+ pkt_size = sizeof(*config) + payload_size;
+ pr_debug("%s: pkt_size %d, payload_size %d\n", __func__,
+ pkt_size, payload_size);
+ config = kzalloc(pkt_size, GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
+
+ config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config->hdr.pkt_size = pkt_size;
+ config->hdr.src_port = 0;
+ config->hdr.dest_port = 0;
+ config->hdr.token = IDX_GLOBAL_CFG;
+ config->hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ param = &config->param;
+ param->payload_size = payload_size;
+ param->payload_address_lsw = 0x00;
+ param->payload_address_msw = 0x00;
+ param->mem_map_handle = 0x00;
+
+ for (i = 0; i < num_regs; i++) {
+ config->reg_data[i].common.module_id =
+ AFE_MODULE_CDC_DEV_CFG;
+ config->reg_data[i].common.param_id =
+ AFE_PARAM_ID_CDC_REG_CFG;
+ config->reg_data[i].common.param_size =
+ sizeof(config->reg_data[i].reg_cfg);
+ config->reg_data[i].reg_cfg =
+ cdc_reg_cfg->reg_data[i + (j * reg_per_pkt)];
+ }
+
+ ret = afe_apr_send_pkt(config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CDC_REG_CFG failed %d\n",
+ __func__, ret);
+ kfree(config);
+ break;
+ }
+ kfree(config);
+ }
+
+ return ret;
+}
+
+static int afe_init_cdc_reg_config(void)
+{
+ int ret;
+ struct afe_svc_cmd_init_cdc_reg_cfg config;
+
+ pr_debug("%s: enter\n", __func__);
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.init.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.init.param_id = AFE_PARAM_ID_CDC_REG_CFG_INIT;
+ config.init.param_size = 0;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CDC_INIT_REG_CFG failed %d\n",
+ __func__, ret);
+ }
+
+ return ret;
+}
+
+static int afe_send_slimbus_slave_port_cfg(
+ struct afe_param_slimbus_slave_port_cfg *port_config, u16 port_id)
+{
+ int ret, index;
+ struct afe_cmd_hw_mad_slimbus_slave_port_cfg config;
+
+ pr_debug("%s: enter, port_id = 0x%x\n", __func__, port_id);
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id = 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = port_id;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_HW_MAD;
+ config.pdata.param_id = AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG;
+ config.pdata.param_size = sizeof(*port_config);
+ config.sb_port_cfg = *port_config;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG failed %d\n",
+ __func__, ret);
+ }
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+static int afe_aanc_port_cfg(void *apr, uint16_t tx_port, uint16_t rx_port)
+{
+ struct afe_port_cmd_set_aanc_param cfg;
+ int ret = 0;
+ int index = 0;
+
+ pr_debug("%s: tx_port 0x%x, rx_port 0x%x\n",
+ __func__, tx_port, rx_port);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ index = q6audio_get_port_index(tx_port);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(tx_port);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, tx_port, ret);
+ return -EINVAL;
+ }
+ pr_debug("%s: AANC sample rate tx rate: %d rx rate %d\n",
+ __func__, this_afe.aanc_info.aanc_tx_port_sample_rate,
+ this_afe.aanc_info.aanc_rx_port_sample_rate);
+ /*
+ * If aanc tx sample rate or rx sample rate is zero, skip aanc
+ * configuration as AFE resampler will fail for invalid sample
+ * rates.
+ */
+ if (!this_afe.aanc_info.aanc_tx_port_sample_rate ||
+ !this_afe.aanc_info.aanc_rx_port_sample_rate) {
+ return -EINVAL;
+ }
+
+ cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cfg.hdr.pkt_size = sizeof(cfg);
+ cfg.hdr.src_port = 0;
+ cfg.hdr.dest_port = 0;
+ cfg.hdr.token = index;
+ cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+ cfg.param.port_id = tx_port;
+ cfg.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_aanc_port_cfg);
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.payload_address_msw = 0;
+ cfg.param.mem_map_handle = 0;
+
+ cfg.pdata.module_id = AFE_MODULE_AANC;
+ cfg.pdata.param_id = AFE_PARAM_ID_AANC_PORT_CONFIG;
+ cfg.pdata.param_size = sizeof(struct afe_param_aanc_port_cfg);
+ cfg.pdata.reserved = 0;
+
+ cfg.data.aanc_port_cfg.aanc_port_cfg_minor_version =
+ AFE_API_VERSION_AANC_PORT_CONFIG;
+ cfg.data.aanc_port_cfg.tx_port_sample_rate =
+ this_afe.aanc_info.aanc_tx_port_sample_rate;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[0] = AANC_TX_VOICE_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[1] = AANC_TX_NOISE_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[2] = AANC_TX_ERROR_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[3] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[4] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[5] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[6] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[7] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_num_channels = 3;
+ cfg.data.aanc_port_cfg.rx_path_ref_port_id = rx_port;
+ cfg.data.aanc_port_cfg.ref_port_sample_rate =
+ this_afe.aanc_info.aanc_rx_port_sample_rate;
+
+ ret = afe_apr_send_pkt((uint32_t *) &cfg, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE AANC port config failed for tx_port 0x%x, rx_port 0x%x ret %d\n",
+ __func__, tx_port, rx_port, ret);
+ }
+
+ return ret;
+}
+
+static int afe_aanc_mod_enable(void *apr, uint16_t tx_port, uint16_t enable)
+{
+ struct afe_port_cmd_set_aanc_param cfg;
+ int ret = 0;
+ int index = 0;
+
+ pr_debug("%s: tx_port 0x%x\n",
+ __func__, tx_port);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ index = q6audio_get_port_index(tx_port);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(tx_port);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, tx_port, ret);
+ return -EINVAL;
+ }
+
+ cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cfg.hdr.pkt_size = sizeof(cfg);
+ cfg.hdr.src_port = 0;
+ cfg.hdr.dest_port = 0;
+ cfg.hdr.token = index;
+ cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+ cfg.param.port_id = tx_port;
+ cfg.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_mod_enable_param);
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.mem_map_handle = 0;
+
+ cfg.pdata.module_id = AFE_MODULE_AANC;
+ cfg.pdata.param_id = AFE_PARAM_ID_ENABLE;
+ cfg.pdata.param_size = sizeof(struct afe_mod_enable_param);
+ cfg.pdata.reserved = 0;
+
+ cfg.data.mod_enable.enable = enable;
+ cfg.data.mod_enable.reserved = 0;
+
+ ret = afe_apr_send_pkt((uint32_t *) &cfg, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE AANC enable failed for tx_port 0x%x ret %d\n",
+ __func__, tx_port, ret);
+ }
+ return ret;
+}
+
+static int afe_send_bank_selection_clip(
+ struct afe_param_id_clip_bank_sel *param)
+{
+ int ret;
+ struct afe_svc_cmd_set_clip_bank_selection config;
+
+ if (!param) {
+ pr_err("%s: Invalid params", __func__);
+ return -EINVAL;
+ }
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_id_clip_bank_sel);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CLIP_BANK_SEL_CFG;
+ config.pdata.param_size =
+ sizeof(struct afe_param_id_clip_bank_sel);
+ config.bank_sel = *param;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CLIP_BANK_SEL_CFG failed %d\n",
+ __func__, ret);
+ }
+ return ret;
+}
+int afe_send_aanc_version(
+ struct afe_param_id_cdc_aanc_version *version_cfg)
+{
+ int ret;
+ struct afe_svc_cmd_cdc_aanc_version config;
+
+ pr_debug("%s: enter\n", __func__);
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_id_cdc_aanc_version);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CDC_AANC_VERSION;
+ config.pdata.param_size =
+ sizeof(struct afe_param_id_cdc_aanc_version);
+ config.version = *version_cfg;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CDC_AANC_VERSION failed %d\n",
+ __func__, ret);
+ }
+ return ret;
+}
+
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type)
+{
+ int i;
+
+ if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX) {
+ mad_type = MAD_SW_AUDIO;
+ return 0;
+ }
+
+ i = port_id - SLIMBUS_0_RX;
+ if (i < 0 || i >= ARRAY_SIZE(afe_ports_mad_type)) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+ atomic_set(&afe_ports_mad_type[i], mad_type);
+ return 0;
+}
+
+enum afe_mad_type afe_port_get_mad_type(u16 port_id)
+{
+ int i;
+
+ if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX)
+ return MAD_SW_AUDIO;
+
+ i = port_id - SLIMBUS_0_RX;
+ if (i < 0 || i >= ARRAY_SIZE(afe_ports_mad_type)) {
+ pr_debug("%s: Non Slimbus port_id 0x%x\n", __func__, port_id);
+ return MAD_HW_NONE;
+ }
+ return (enum afe_mad_type) atomic_read(&afe_ports_mad_type[i]);
+}
+
+int afe_set_config(enum afe_config_type config_type, void *config_data, int arg)
+{
+ int ret;
+
+ pr_debug("%s: enter config_type %d\n", __func__, config_type);
+ ret = afe_q6_interface_prepare();
+ if (ret) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ switch (config_type) {
+ case AFE_SLIMBUS_SLAVE_CONFIG:
+ ret = afe_send_slimbus_slave_cfg(config_data);
+ if (!ret)
+ ret = afe_init_cdc_reg_config();
+ else
+ pr_err("%s: Sending slimbus slave config failed %d\n",
+ __func__, ret);
+ break;
+ case AFE_CDC_REGISTERS_CONFIG:
+ ret = afe_send_codec_reg_config(config_data);
+ break;
+ case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+ ret = afe_send_slimbus_slave_port_cfg(config_data, arg);
+ break;
+ case AFE_AANC_VERSION:
+ ret = afe_send_aanc_version(config_data);
+ break;
+ case AFE_CLIP_BANK_SEL:
+ ret = afe_send_bank_selection_clip(config_data);
+ break;
+ case AFE_CDC_CLIP_REGISTERS_CONFIG:
+ ret = afe_send_codec_reg_config(config_data);
+ break;
+ case AFE_CDC_REGISTER_PAGE_CONFIG:
+ ret = afe_send_codec_reg_page_config(config_data);
+ break;
+ default:
+ pr_err("%s: unknown configuration type %d",
+ __func__, config_type);
+ ret = -EINVAL;
+ }
+
+ if (!ret)
+ set_bit(config_type, &afe_configured_cmd);
+
+ return ret;
+}
+
+/*
+ * afe_clear_config - If SSR happens ADSP loses AFE configs, let AFE driver know
+ * about the state so client driver can wait until AFE is
+ * reconfigured.
+ */
+void afe_clear_config(enum afe_config_type config)
+{
+ clear_bit(config, &afe_configured_cmd);
+}
+
+bool afe_has_config(enum afe_config_type config)
+{
+ return !!test_bit(config, &afe_configured_cmd);
+}
+
+int afe_send_spdif_clk_cfg(struct afe_param_id_spdif_clk_cfg *cfg,
+ u16 port_id)
+{
+ struct afe_spdif_clk_config_command clk_cfg;
+ int ret = 0;
+ int index = 0;
+
+ if (!cfg) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+ clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
+ clk_cfg.hdr.src_port = 0;
+ clk_cfg.hdr.dest_port = 0;
+ clk_cfg.hdr.token = index;
+
+ clk_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ clk_cfg.param.port_id = q6audio_get_port_id(port_id);
+ clk_cfg.param.payload_address_lsw = 0x00;
+ clk_cfg.param.payload_address_msw = 0x00;
+ clk_cfg.param.mem_map_handle = 0x00;
+ clk_cfg.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ clk_cfg.pdata.param_id = AFE_PARAM_ID_SPDIF_CLK_CONFIG;
+ clk_cfg.pdata.param_size = sizeof(clk_cfg.clk_cfg);
+ clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
+ - sizeof(clk_cfg.param);
+ clk_cfg.clk_cfg = *cfg;
+
+ pr_debug("%s: Minor version = 0x%x clk val = %d\n"
+ "clk root = 0x%x\n port id = 0x%x\n",
+ __func__, cfg->clk_cfg_minor_version,
+ cfg->clk_value, cfg->clk_root,
+ q6audio_get_port_id(port_id));
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
+ if (ret < 0) {
+ pr_err("%s: AFE send clock config for port 0x%x failed ret = %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+int afe_send_spdif_ch_status_cfg(struct afe_param_id_spdif_ch_status_cfg
+ *ch_status_cfg, u16 port_id)
+{
+ struct afe_spdif_chstatus_config_command ch_status;
+ int ret = 0;
+ int index = 0;
+
+ if (!ch_status_cfg) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+ ch_status.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ ch_status.hdr.pkt_size = sizeof(ch_status_cfg);
+ ch_status.hdr.src_port = 0;
+ ch_status.hdr.dest_port = 0;
+ ch_status.hdr.token = index;
+
+ ch_status.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ ch_status.param.port_id = q6audio_get_port_id(port_id);
+ ch_status.param.payload_address_lsw = 0x00;
+ ch_status.param.payload_address_msw = 0x00;
+ ch_status.param.mem_map_handle = 0x00;
+ ch_status.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ ch_status.pdata.param_id = AFE_PARAM_ID_SPDIF_CLK_CONFIG;
+ ch_status.pdata.param_size = sizeof(ch_status.ch_status);
+ ch_status.param.payload_size = sizeof(ch_status)
+ - sizeof(struct apr_hdr) - sizeof(ch_status.param);
+ ch_status.ch_status = *ch_status_cfg;
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &ch_status);
+ if (ret < 0) {
+ pr_err("%s: AFE send channel status for port 0x%x failed ret = %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+static int afe_send_cmd_port_start(u16 port_id)
+{
+ struct afe_port_cmd_device_start start;
+ int ret, index;
+
+ pr_debug("%s: enter\n", __func__);
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = index;
+ start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+ start.port_id = q6audio_get_port_id(port_id);
+ pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
+ __func__, start.hdr.opcode, start.port_id);
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE enable for port 0x%x failed %d\n", __func__,
+ port_id, ret);
+ } else if (this_afe.task != current) {
+ this_afe.task = current;
+ pr_debug("task_name = %s pid = %d\n",
+ this_afe.task->comm, this_afe.task->pid);
+ }
+
+ return ret;
+}
+
+static int afe_aanc_start(uint16_t tx_port_id, uint16_t rx_port_id)
+{
+ int ret;
+
+ pr_debug("%s: Tx port is 0x%x, Rx port is 0x%x\n",
+ __func__, tx_port_id, rx_port_id);
+ ret = afe_aanc_port_cfg(this_afe.apr, tx_port_id, rx_port_id);
+ if (ret) {
+ pr_err("%s: Send AANC Port Config failed %d\n",
+ __func__, ret);
+ goto fail_cmd;
+ }
+ send_afe_cal_type(AFE_AANC_CAL, tx_port_id);
+
+fail_cmd:
+ return ret;
+}
+
+int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port,
+ u32 rate)
+{
+ struct afe_audioif_config_command config;
+ int ret = 0;
+ int index = 0;
+ uint16_t port_index;
+
+ if (!spdif_port) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ pr_debug("%s: port id: 0x%x\n", __func__, port_id);
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ afe_send_cal(port_id);
+ afe_send_hw_delay(port_id, rate);
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ config.pdata.param_id = AFE_PARAM_ID_SPDIF_CONFIG;
+ config.pdata.param_size = sizeof(config.port);
+ config.port.spdif = spdif_port->cfg;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE enable for port 0x%x failed ret = %d\n",
+ __func__, port_id, ret);
+ goto fail_cmd;
+ }
+
+ port_index = afe_get_port_index(port_id);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[port_index] = rate;
+ } else {
+ pr_err("%s: Invalid port index %d\n", __func__, port_index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = afe_send_spdif_ch_status_cfg(&spdif_port->ch_status, port_id);
+ if (ret < 0) {
+ pr_err("%s: afe send failed %d\n", __func__, ret);
+ goto fail_cmd;
+ }
+
+ return afe_send_cmd_port_start(port_id);
+
+fail_cmd:
+ return ret;
+}
+
+int afe_send_slot_mapping_cfg(
+ struct afe_param_id_slot_mapping_cfg *slot_mapping_cfg,
+ u16 port_id)
+{
+ struct afe_slot_mapping_config_command config;
+ int ret = 0;
+ int index = 0;
+
+ if (!slot_mapping_cfg) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: port id: 0x%x\n", __func__, port_id);
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config)
+ - sizeof(struct apr_hdr) - sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_TDM;
+ config.pdata.param_id = AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG;
+ config.pdata.param_size = sizeof(config.slot_mapping);
+ config.slot_mapping = *slot_mapping_cfg;
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+ if (ret < 0) {
+ pr_err("%s: AFE send slot mapping for port 0x%x failed ret = %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+int afe_send_custom_tdm_header_cfg(
+ struct afe_param_id_custom_tdm_header_cfg *custom_tdm_header_cfg,
+ u16 port_id)
+{
+ struct afe_custom_tdm_header_config_command config;
+ int ret = 0;
+ int index = 0;
+
+ if (!custom_tdm_header_cfg) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: port id: 0x%x\n", __func__, port_id);
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config)
+ - sizeof(struct apr_hdr) - sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_TDM;
+ config.pdata.param_id = AFE_PARAM_ID_CUSTOM_TDM_HEADER_CONFIG;
+ config.pdata.param_size = sizeof(config.custom_tdm_header);
+ config.custom_tdm_header = *custom_tdm_header_cfg;
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+ if (ret < 0) {
+ pr_err("%s: AFE send custom tdm header for port 0x%x failed ret = %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
+ u32 rate)
+{
+ struct afe_audioif_config_command config;
+ int ret = 0;
+ int index = 0;
+ uint16_t port_index = 0;
+ enum afe_mad_type mad_type = MAD_HW_NONE;
+
+ if (!tdm_port) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: port id: 0x%x\n", __func__, port_id);
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* Also send the topology id here: */
+ port_index = afe_get_port_index(port_id);
+ if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE)) {
+ /* One time call: only for first time */
+ afe_send_custom_topology();
+ afe_send_port_topology_id(port_id);
+ afe_send_cal(port_id);
+ afe_send_hw_delay(port_id, rate);
+ }
+
+ /* Start SW MAD module */
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ if (mad_type != MAD_HW_NONE && mad_type != MAD_SW_AUDIO) {
+ if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
+ !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
+ pr_err("%s: AFE isn't configured yet for\n"
+ "HW MAD try Again\n", __func__);
+ ret = -EAGAIN;
+ goto fail_cmd;
+ }
+ ret = afe_turn_onoff_hw_mad(mad_type, true);
+ if (ret) {
+ pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+ __func__, ret);
+ goto fail_cmd;
+ }
+ }
+
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ config.pdata.param_id = AFE_PARAM_ID_TDM_CONFIG;
+ config.pdata.param_size = sizeof(config.port);
+ config.port.tdm = tdm_port->tdm;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE enable for port 0x%x failed ret = %d\n",
+ __func__, port_id, ret);
+ goto fail_cmd;
+ }
+
+ port_index = afe_get_port_index(port_id);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[port_index] = rate;
+ } else {
+ pr_err("%s: Invalid port index %d\n", __func__, port_index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = afe_send_slot_mapping_cfg(&tdm_port->slot_mapping, port_id);
+ if (ret < 0) {
+ pr_err("%s: afe send failed %d\n", __func__, ret);
+ goto fail_cmd;
+ }
+
+ if (tdm_port->custom_tdm_header.header_type) {
+ ret = afe_send_custom_tdm_header_cfg(
+ &tdm_port->custom_tdm_header, port_id);
+ if (ret < 0) {
+ pr_err("%s: afe send failed %d\n", __func__, ret);
+ goto fail_cmd;
+ }
+ }
+
+ ret = afe_send_cmd_port_start(port_id);
+
+fail_cmd:
+ return ret;
+}
+
+void afe_set_cal_mode(u16 port_id, enum afe_cal_mode afe_cal_mode)
+{
+ uint16_t port_index;
+
+ port_index = afe_get_port_index(port_id);
+ this_afe.afe_cal_mode[port_index] = afe_cal_mode;
+}
+
+int afe_port_send_usb_dev_param(u16 port_id, union afe_port_config *afe_config)
+{
+ struct afe_usb_audio_dev_param_command config;
+ int ret = 0, index = 0;
+
+ if (!afe_config) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid! for port ID 0x%x\n",
+ __func__, index, port_id);
+ ret = -EINVAL;
+ goto exit;
+ }
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ config.pdata.param_id = AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS;
+ config.pdata.param_size = sizeof(config.usb_dev);
+ config.usb_dev.cfg_minor_version =
+ AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG;
+ config.usb_dev.dev_token = afe_config->usb_audio.dev_token;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE device param cmd failed %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+exit:
+ return ret;
+}
+
+static int q6afe_send_enc_config(u16 port_id,
+ union afe_enc_config_data *cfg, u32 format,
+ union afe_port_config afe_config,
+ u16 afe_in_channels, u16 afe_in_bit_width)
+{
+ struct afe_audioif_config_command config;
+ int index;
+ int ret;
+ int payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param) - sizeof(config.port);
+
+ pr_debug("%s:update DSP for enc format = %d\n", __func__, format);
+ if (format != ASM_MEDIA_FMT_SBC && format != ASM_MEDIA_FMT_AAC_V2 &&
+ format != ASM_MEDIA_FMT_APTX && format != ASM_MEDIA_FMT_APTX_HD) {
+ pr_err("%s:Unsuppported format Ignore AFE config\n", __func__);
+ return 0;
+ }
+ memset(&config, 0, sizeof(config));
+ index = q6audio_get_port_index(port_id);
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = payload_size + sizeof(config.port.enc_fmt);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_ID_ENCODER;
+ config.pdata.param_id = AFE_ENCODER_PARAM_ID_ENC_FMT_ID;
+ config.pdata.param_size = sizeof(config.port.enc_fmt);
+ config.port.enc_fmt.fmt_id = format;
+ pr_debug("%s:sending AFE_ENCODER_PARAM_ID_ENC_FMT_ID payload: %d\n",
+ __func__, config.param.payload_size);
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s:unable to send AFE_ENCODER_PARAM_ID_ENC_FMT_ID",
+ __func__);
+ goto exit;
+ }
+
+ config.param.payload_size = payload_size
+ + sizeof(config.port.enc_blk_param);
+ pr_debug("%s:send AFE_ENCODER_PARAM_ID_ENC_CFG_BLK to DSP payload:%d\n",
+ __func__, config.param.payload_size);
+ config.pdata.param_id = AFE_ENCODER_PARAM_ID_ENC_CFG_BLK;
+ config.pdata.param_size = sizeof(config.port.enc_blk_param);
+ config.port.enc_blk_param.enc_cfg_blk_size =
+ sizeof(config.port.enc_blk_param.enc_blk_config);
+ config.port.enc_blk_param.enc_blk_config = *cfg;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_ENCODER_PARAM_ID_ENC_CFG_BLK for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto exit;
+ }
+
+ config.param.payload_size =
+ payload_size + sizeof(config.port.enc_pkt_id_param);
+ pr_debug("%s:sending AFE_ENCODER_PARAM_ID_PACKETIZER to DSP payload = %d",
+ __func__, config.param.payload_size);
+ config.pdata.param_id = AFE_ENCODER_PARAM_ID_PACKETIZER_ID;
+ config.pdata.param_size = sizeof(config.port.enc_pkt_id_param);
+ config.port.enc_pkt_id_param.enc_packetizer_id =
+ AFE_MODULE_ID_PACKETIZER_COP;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_ENCODER_PARAM_ID_PACKETIZER for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto exit;
+ }
+
+ config.param.payload_size =
+ payload_size + sizeof(config.port.media_type);
+ config.pdata.param_size = sizeof(config.port.media_type);
+
+ pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP", __func__);
+ config.pdata.module_id = AFE_MODULE_PORT;
+ config.pdata.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE;
+ config.port.media_type.minor_version = AFE_API_VERSION_PORT_MEDIA_TYPE;
+ config.port.media_type.sample_rate = afe_config.slim_sch.sample_rate;
+ if (afe_in_bit_width)
+ config.port.media_type.bit_width = afe_in_bit_width;
+ else
+ config.port.media_type.bit_width =
+ afe_config.slim_sch.bit_width;
+
+ if (afe_in_channels)
+ config.port.media_type.num_channels = afe_in_channels;
+ else
+ config.port.media_type.num_channels =
+ afe_config.slim_sch.num_channels;
+ config.port.media_type.data_format = AFE_PORT_DATA_FORMAT_PCM;
+ config.port.media_type.reserved = 0;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_API_VERSION_PORT_MEDIA_TYPE for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
+ u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
+ union afe_enc_config_data *cfg, u32 enc_format)
+{
+ struct afe_audioif_config_command config;
+ int ret = 0;
+ int cfg_type;
+ int index = 0;
+ enum afe_mad_type mad_type;
+ uint16_t port_index;
+
+ if (!afe_config) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ if ((port_id == RT_PROXY_DAI_001_RX) ||
+ (port_id == RT_PROXY_DAI_002_TX)) {
+ pr_debug("%s: before incrementing pcm_afe_instance %d",
+ " port_id 0x%x\n", __func__,
+ pcm_afe_instance[port_id & 0x1], port_id);
+ port_id = VIRTUAL_ID_TO_PORTID(port_id);
+ pcm_afe_instance[port_id & 0x1]++;
+ return 0;
+ }
+ if ((port_id == RT_PROXY_DAI_002_RX) ||
+ (port_id == RT_PROXY_DAI_001_TX)) {
+ pr_debug("%s: before incrementing proxy_afe_instance %d",
+ " port_id 0x%x\n", __func__,
+ proxy_afe_instance[port_id & 0x1], port_id);
+
+ if (!afe_close_done[port_id & 0x1]) {
+ /*close pcm dai corresponding to the proxy dai*/
+ afe_close(port_id - 0x10);
+ pcm_afe_instance[port_id & 0x1]++;
+ pr_debug("%s: reconfigure afe port again\n", __func__);
+ }
+ proxy_afe_instance[port_id & 0x1]++;
+ afe_close_done[port_id & 0x1] = false;
+ port_id = VIRTUAL_ID_TO_PORTID(port_id);
+ }
+
+ pr_debug("%s: port id: 0x%x\n", __func__, port_id);
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ mutex_lock(&this_afe.afe_cmd_lock);
+ /* Also send the topology id here: */
+ port_index = afe_get_port_index(port_id);
+ if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE)) {
+ /* One time call: only for first time */
+ afe_send_custom_topology();
+ afe_send_port_topology_id(port_id);
+ afe_send_cal(port_id);
+ afe_send_hw_delay(port_id, rate);
+ }
+
+ /* Start SW MAD module */
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ if (mad_type != MAD_HW_NONE && mad_type != MAD_SW_AUDIO) {
+ if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
+ !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
+ pr_err("%s: AFE isn't configured yet for\n"
+ "HW MAD try Again\n", __func__);
+ ret = -EAGAIN;
+ goto fail_cmd;
+ }
+ ret = afe_turn_onoff_hw_mad(mad_type, true);
+ if (ret) {
+ pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+ __func__, ret);
+ goto fail_cmd;
+ }
+ }
+
+ if ((this_afe.aanc_info.aanc_active) &&
+ (this_afe.aanc_info.aanc_tx_port == port_id)) {
+ this_afe.aanc_info.aanc_tx_port_sample_rate = rate;
+ port_index =
+ afe_get_port_index(this_afe.aanc_info.aanc_rx_port);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.aanc_info.aanc_rx_port_sample_rate =
+ this_afe.afe_sample_rates[port_index];
+ } else {
+ pr_err("%s: Invalid port index %d\n",
+ __func__, port_index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = afe_aanc_start(this_afe.aanc_info.aanc_tx_port,
+ this_afe.aanc_info.aanc_rx_port);
+ pr_debug("%s: afe_aanc_start ret %d\n", __func__, ret);
+ }
+
+ if ((port_id == AFE_PORT_ID_USB_RX) ||
+ (port_id == AFE_PORT_ID_USB_TX)) {
+ ret = afe_port_send_usb_dev_param(port_id, afe_config);
+ if (ret) {
+ pr_err("%s: AFE device param for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ switch (port_id) {
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ cfg_type = AFE_PARAM_ID_PCM_CONFIG;
+ break;
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
+ case SECONDARY_I2S_RX:
+ case SECONDARY_I2S_TX:
+ case MI2S_RX:
+ case MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_QUINARY_MI2S_RX:
+ case AFE_PORT_ID_QUINARY_MI2S_TX:
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ cfg_type = AFE_PARAM_ID_I2S_CONFIG;
+ break;
+ case HDMI_RX:
+ case DISPLAY_PORT_RX:
+ cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
+ break;
+ case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ cfg_type = AFE_PARAM_ID_PSEUDO_PORT_CONFIG;
+ break;
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_4_TX:
+ case SLIMBUS_5_RX:
+ case SLIMBUS_5_TX:
+ case SLIMBUS_6_RX:
+ case SLIMBUS_6_TX:
+ case SLIMBUS_7_RX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_RX:
+ case SLIMBUS_8_TX:
+ cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
+ break;
+ case AFE_PORT_ID_USB_RX:
+ case AFE_PORT_ID_USB_TX:
+ cfg_type = AFE_PARAM_ID_USB_AUDIO_CONFIG;
+ break;
+ case RT_PROXY_PORT_001_RX:
+ case RT_PROXY_PORT_001_TX:
+ cfg_type = AFE_PARAM_ID_RT_PROXY_CONFIG;
+ break;
+ case INT_BT_SCO_RX:
+ case INT_BT_A2DP_RX:
+ case INT_BT_SCO_TX:
+ case INT_FM_RX:
+ case INT_FM_TX:
+ cfg_type = AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG;
+ break;
+ default:
+ pr_err("%s: Invalid port id 0x%x\n", __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ config.pdata.param_id = cfg_type;
+ config.pdata.param_size = sizeof(config.port);
+
+ config.port = *afe_config;
+ if ((enc_format != ASM_MEDIA_FMT_NONE) &&
+ (cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) {
+ config.port.slim_sch.data_format =
+ AFE_SB_DATA_FORMAT_GENERIC_COMPRESSED;
+ }
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE enable for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto fail_cmd;
+ }
+
+ if ((enc_format != ASM_MEDIA_FMT_NONE) &&
+ (cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) {
+ pr_debug("%s: Found AFE encoder support for SLIMBUS enc_format = %d\n",
+ __func__, enc_format);
+ ret = q6afe_send_enc_config(port_id, cfg, enc_format,
+ *afe_config, afe_in_channels,
+ afe_in_bit_width);
+ if (ret) {
+ pr_err("%s: AFE encoder config for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto fail_cmd;
+ }
+ }
+
+ port_index = afe_get_port_index(port_id);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[port_index] = rate;
+ /*
+ * If afe_port_start() for tx port called before
+ * rx port, then aanc rx sample rate is zero. So,
+ * AANC state machine in AFE will not get triggered.
+ * Make sure to check whether aanc is active during
+ * afe_port_start() for rx port and if aanc rx
+ * sample rate is zero, call afe_aanc_start to configure
+ * aanc with valid sample rates.
+ */
+ if (this_afe.aanc_info.aanc_active &&
+ !this_afe.aanc_info.aanc_rx_port_sample_rate) {
+ this_afe.aanc_info.aanc_rx_port_sample_rate =
+ this_afe.afe_sample_rates[port_index];
+ ret = afe_aanc_start(this_afe.aanc_info.aanc_tx_port,
+ this_afe.aanc_info.aanc_rx_port);
+ pr_debug("%s: afe_aanc_start ret %d\n", __func__, ret);
+ }
+ } else {
+ pr_err("%s: Invalid port index %d\n", __func__, port_index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = afe_send_cmd_port_start(port_id);
+
+fail_cmd:
+ mutex_unlock(&this_afe.afe_cmd_lock);
+ return ret;
+}
+
+/**
+ * afe_port_start - to configure AFE session with
+ * specified port configuration
+ *
+ * @port_id: AFE port id number
+ * @afe_config: port configutation
+ * @rate: sampling rate of port
+ *
+ * Returns 0 on success or error value on port start failure.
+ */
+int afe_port_start(u16 port_id, union afe_port_config *afe_config,
+ u32 rate)
+{
+ return __afe_port_start(port_id, afe_config, rate,
+ 0, 0, NULL, ASM_MEDIA_FMT_NONE);
+}
+EXPORT_SYMBOL(afe_port_start);
+
+/**
+ * afe_port_start_v2 - to configure AFE session with
+ * specified port configuration and encoder params
+ *
+ * @port_id: AFE port id number
+ * @afe_config: port configutation
+ * @rate: sampling rate of port
+ * @cfg: AFE encoder configuration information to setup encoder
+ * @afe_in_channels: AFE input channel configuration, this needs
+ * update only if input channel is differ from AFE output
+ *
+ * Returns 0 on success or error value on port start failure.
+ */
+int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
+ u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
+ struct afe_enc_config *enc_cfg)
+{
+ return __afe_port_start(port_id, afe_config, rate,
+ afe_in_channels, afe_in_bit_width,
+ &enc_cfg->data, enc_cfg->format);
+}
+EXPORT_SYMBOL(afe_port_start_v2);
+
+int afe_get_port_index(u16 port_id)
+{
+ switch (port_id) {
+ case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
+ case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_PCM_RX;
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_PCM_TX;
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ return IDX_AFE_PORT_ID_SECONDARY_PCM_RX;
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ return IDX_AFE_PORT_ID_SECONDARY_PCM_TX;
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_PCM_RX;
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_PCM_TX;
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_PCM_RX;
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_PCM_TX;
+ case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
+ case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
+ case MI2S_RX: return IDX_MI2S_RX;
+ case MI2S_TX: return IDX_MI2S_TX;
+ case HDMI_RX: return IDX_HDMI_RX;
+ case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX;
+ case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX;
+ case RSVD_2: return IDX_RSVD_2;
+ case RSVD_3: return IDX_RSVD_3;
+ case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
+ case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
+ case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
+ case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
+ case VOICE2_PLAYBACK_TX: return IDX_VOICE2_PLAYBACK_TX;
+ case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
+ case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
+ case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
+ case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
+ case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
+ case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
+ case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
+ case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
+ case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
+ case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
+ case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
+ case INT_FM_RX: return IDX_INT_FM_RX;
+ case INT_FM_TX: return IDX_INT_FM_TX;
+ case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
+ case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
+ case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
+ case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+ case SLIMBUS_5_RX: return IDX_SLIMBUS_5_RX;
+ case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
+ case SLIMBUS_6_RX: return IDX_SLIMBUS_6_RX;
+ case SLIMBUS_6_TX: return IDX_SLIMBUS_6_TX;
+ case SLIMBUS_7_RX: return IDX_SLIMBUS_7_RX;
+ case SLIMBUS_7_TX: return IDX_SLIMBUS_7_TX;
+ case SLIMBUS_8_RX: return IDX_SLIMBUS_8_RX;
+ case SLIMBUS_8_TX: return IDX_SLIMBUS_8_TX;
+ case AFE_PORT_ID_USB_RX: return IDX_AFE_PORT_ID_USB_RX;
+ case AFE_PORT_ID_USB_TX: return IDX_AFE_PORT_ID_USB_TX;
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX;
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_TX;
+ case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX_SD1;
+ case AFE_PORT_ID_QUINARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_QUINARY_MI2S_RX;
+ case AFE_PORT_ID_QUINARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_QUINARY_MI2S_TX;
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_SENARY_MI2S_TX;
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_0;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_0;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_1;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_1;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_2;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_2;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_3;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_3;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_4;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_4;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_5;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_5;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_6;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_6;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_7;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_7;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_0;
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_0;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_1;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_1;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_2;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_2;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_3;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_3;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_4;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_4;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_5;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_5;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_6;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_6;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_7;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_7;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_0;
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_0;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_1;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_1;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_2;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_2;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_3;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_3;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_4;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_4;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_5;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_5;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_6;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_6;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_7;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_7;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_0;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_0;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_1;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_1;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_2;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_2;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_3;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_3;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_4;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_4;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_5;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_5;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_6;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_6;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_7;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_7;
+ default:
+ pr_err("%s: port 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+}
+
+int afe_open(u16 port_id,
+ union afe_port_config *afe_config, int rate)
+{
+ struct afe_port_cmd_device_start start;
+ struct afe_audioif_config_command config;
+ int ret = 0;
+ int cfg_type;
+ int index = 0;
+
+ if (!afe_config) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ pr_err("%s: port_id 0x%x rate %d\n", __func__, port_id, rate);
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ if ((port_id == RT_PROXY_DAI_001_RX) ||
+ (port_id == RT_PROXY_DAI_002_TX)) {
+ pr_err("%s: wrong port 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+ if ((port_id == RT_PROXY_DAI_002_RX) ||
+ (port_id == RT_PROXY_DAI_001_TX))
+ port_id = VIRTUAL_ID_TO_PORTID(port_id);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return -EINVAL;
+ }
+ /* Also send the topology id here: */
+ afe_send_custom_topology(); /* One time call: only for first time */
+ afe_send_port_topology_id(port_id);
+
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Failed : Invalid Port id = 0x%x ret %d\n",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+ mutex_lock(&this_afe.afe_cmd_lock);
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+ switch (port_id) {
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
+ cfg_type = AFE_PARAM_ID_I2S_CONFIG;
+ break;
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ cfg_type = AFE_PARAM_ID_PCM_CONFIG;
+ break;
+ case SECONDARY_I2S_RX:
+ case SECONDARY_I2S_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case MI2S_RX:
+ case MI2S_TX:
+ case AFE_PORT_ID_QUINARY_MI2S_RX:
+ case AFE_PORT_ID_QUINARY_MI2S_TX:
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ cfg_type = AFE_PARAM_ID_I2S_CONFIG;
+ break;
+ case HDMI_RX:
+ case DISPLAY_PORT_RX:
+ cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
+ break;
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_4_TX:
+ case SLIMBUS_5_RX:
+ case SLIMBUS_6_RX:
+ case SLIMBUS_6_TX:
+ case SLIMBUS_7_RX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_RX:
+ case SLIMBUS_8_TX:
+ cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
+ break;
+ case AFE_PORT_ID_USB_RX:
+ case AFE_PORT_ID_USB_TX:
+ cfg_type = AFE_PARAM_ID_USB_AUDIO_CONFIG;
+ break;
+ default:
+ pr_err("%s: Invalid port id 0x%x\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr)
+ - sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ config.pdata.param_id = cfg_type;
+ config.pdata.param_size = sizeof(config.port);
+
+ config.port = *afe_config;
+ pr_debug("%s: param PL size=%d iparam_size[%d][%zd %zd %zd %zd] param_id[0x%x]\n",
+ __func__, config.param.payload_size, config.pdata.param_size,
+ sizeof(config), sizeof(config.param), sizeof(config.port),
+ sizeof(struct apr_hdr), config.pdata.param_id);
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE enable for port 0x%x opcode[0x%x]failed %d\n",
+ __func__, port_id, cfg_type, ret);
+ goto fail_cmd;
+ }
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = index;
+ start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+ start.port_id = q6audio_get_port_id(port_id);
+ pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
+ __func__, start.hdr.opcode, start.port_id);
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE enable for port 0x%x failed %d\n", __func__,
+ port_id, ret);
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ mutex_unlock(&this_afe.afe_cmd_lock);
+ return ret;
+}
+
+int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
+{
+ struct afe_loopback_cfg_v1 lb_cmd;
+ int ret = 0;
+ int index = 0;
+
+ if (rx_port == MI2S_RX)
+ rx_port = AFE_PORT_ID_PRIMARY_MI2S_RX;
+ if (tx_port == MI2S_TX)
+ tx_port = AFE_PORT_ID_PRIMARY_MI2S_TX;
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ index = q6audio_get_port_index(rx_port);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(rx_port);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d", __func__, rx_port, ret);
+ return -EINVAL;
+ }
+
+ lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ lb_cmd.hdr.pkt_size = sizeof(lb_cmd);
+ lb_cmd.hdr.src_port = 0;
+ lb_cmd.hdr.dest_port = 0;
+ lb_cmd.hdr.token = index;
+ lb_cmd.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ lb_cmd.param.port_id = tx_port;
+ lb_cmd.param.payload_size = (sizeof(lb_cmd) - sizeof(struct apr_hdr) -
+ sizeof(struct afe_port_cmd_set_param_v2));
+ lb_cmd.param.payload_address_lsw = 0x00;
+ lb_cmd.param.payload_address_msw = 0x00;
+ lb_cmd.param.mem_map_handle = 0x00;
+ lb_cmd.pdata.module_id = AFE_MODULE_LOOPBACK;
+ lb_cmd.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+ lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
+ sizeof(struct afe_port_param_data_v2);
+
+ lb_cmd.dst_port_id = rx_port;
+ lb_cmd.routing_mode = LB_MODE_DEFAULT;
+ lb_cmd.enable = (enable ? 1 : 0);
+ lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
+
+ ret = afe_apr_send_pkt(&lb_cmd, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE loopback failed %d\n", __func__, ret);
+ return ret;
+}
+
+int afe_loopback_gain(u16 port_id, u16 volume)
+{
+ struct afe_loopback_gain_per_path_param set_param;
+ int ret = 0;
+ int index = 0;
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Failed : Invalid Port id = 0x%x ret %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ /* RX ports numbers are even .TX ports numbers are odd. */
+ if (port_id % 2 == 0) {
+ pr_err("%s: Failed : afe loopback gain only for TX ports. port_id %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ pr_debug("%s: port 0x%x volume %d\n", __func__, port_id, volume);
+
+ set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ set_param.hdr.pkt_size = sizeof(set_param);
+ set_param.hdr.src_port = 0;
+ set_param.hdr.dest_port = 0;
+ set_param.hdr.token = index;
+ set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+ set_param.param.port_id = port_id;
+ set_param.param.payload_size =
+ (sizeof(struct afe_loopback_gain_per_path_param) -
+ sizeof(struct apr_hdr) - sizeof(struct afe_port_cmd_set_param_v2));
+ set_param.param.payload_address_lsw = 0;
+ set_param.param.payload_address_msw = 0;
+ set_param.param.mem_map_handle = 0;
+
+ set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
+ set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+ set_param.pdata.param_size =
+ (set_param.param.payload_size -
+ sizeof(struct afe_port_param_data_v2));
+ set_param.rx_port_id = port_id;
+ set_param.gain = volume;
+
+ ret = afe_apr_send_pkt(&set_param, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE param set failed for port 0x%x ret %d\n",
+ __func__, port_id, ret);
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+int afe_pseudo_port_start_nowait(u16 port_id)
+{
+ struct afe_pseudoport_start_command start;
+ int ret = 0;
+
+ pr_debug("%s: port_id=0x%x\n", __func__, port_id);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE APR is not registered\n", __func__);
+ return -ENODEV;
+ }
+
+
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = 0;
+ start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+ start.port_id = port_id;
+ start.timing = 1;
+
+ ret = afe_apr_send_pkt(&start, NULL);
+ if (ret) {
+ pr_err("%s: AFE enable for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ return ret;
+ }
+ return 0;
+}
+
+int afe_start_pseudo_port(u16 port_id)
+{
+ int ret = 0;
+ struct afe_pseudoport_start_command start;
+ int index = 0;
+
+ pr_debug("%s: port_id = 0x%x\n", __func__, port_id);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = 0;
+ start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+ start.port_id = port_id;
+ start.timing = 1;
+ start.hdr.token = index;
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE enable for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ return ret;
+}
+
+int afe_pseudo_port_stop_nowait(u16 port_id)
+{
+ int ret = 0;
+ struct afe_pseudoport_stop_command stop;
+ int index = 0;
+
+ pr_debug("%s: port_id = 0x%x\n", __func__, port_id);
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE is already closed\n", __func__);
+ return -EINVAL;
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ stop.hdr.pkt_size = sizeof(stop);
+ stop.hdr.src_port = 0;
+ stop.hdr.dest_port = 0;
+ stop.hdr.token = 0;
+ stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+ stop.port_id = port_id;
+ stop.reserved = 0;
+ stop.hdr.token = index;
+
+ ret = afe_apr_send_pkt(&stop, NULL);
+ if (ret)
+ pr_err("%s: AFE close failed %d\n", __func__, ret);
+
+ return ret;
+}
+
+int afe_port_group_set_param(u16 group_id,
+ union afe_port_group_config *afe_group_config)
+{
+ int ret;
+ struct afe_port_group_create config;
+ int cfg_type;
+
+ if (!afe_group_config) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: group id: 0x%x\n", __func__, group_id);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ switch (group_id) {
+ case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX:
+ case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX:
+ case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX:
+ case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX:
+ case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX:
+ case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX:
+ case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX:
+ case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX:
+ cfg_type = AFE_PARAM_ID_GROUP_DEVICE_TDM_CONFIG;
+ break;
+ default:
+ pr_err("%s: Invalid group id 0x%x\n", __func__, group_id);
+ return -EINVAL;
+ }
+
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_GROUP_DEVICE;
+ config.pdata.param_id = cfg_type;
+ config.pdata.param_size = sizeof(config.data);
+ config.data = *afe_group_config;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_GROUP_DEVICE_CFG failed %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+int afe_port_group_enable(u16 group_id,
+ union afe_port_group_config *afe_group_config,
+ u16 enable)
+{
+ int ret;
+ struct afe_port_group_create config;
+
+ pr_debug("%s: group id: 0x%x enable: %d\n", __func__,
+ group_id, enable);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ if (enable) {
+ ret = afe_port_group_set_param(group_id, afe_group_config);
+ if (ret < 0) {
+ pr_err("%s: afe send failed %d\n", __func__, ret);
+ return ret;
+ }
+ }
+
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_GROUP_DEVICE;
+ config.pdata.param_id = AFE_PARAM_ID_GROUP_DEVICE_ENABLE;
+ config.pdata.param_size = sizeof(config.data);
+ config.data.group_enable.group_id = group_id;
+ config.data.group_enable.enable = enable;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_GROUP_DEVICE_ENABLE failed %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+int afe_stop_pseudo_port(u16 port_id)
+{
+ int ret = 0;
+ struct afe_pseudoport_stop_command stop;
+ int index = 0;
+
+ pr_debug("%s: port_id = 0x%x\n", __func__, port_id);
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE is already closed\n", __func__);
+ return -EINVAL;
+ }
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d\n",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ stop.hdr.pkt_size = sizeof(stop);
+ stop.hdr.src_port = 0;
+ stop.hdr.dest_port = 0;
+ stop.hdr.token = 0;
+ stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+ stop.port_id = port_id;
+ stop.reserved = 0;
+ stop.hdr.token = index;
+
+ ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE close failed %d\n", __func__, ret);
+
+ return ret;
+}
+
+uint32_t afe_req_mmap_handle(struct afe_audio_client *ac)
+{
+ return ac->mem_map_handle;
+}
+
+struct afe_audio_client *q6afe_audio_client_alloc(void *priv)
+{
+ struct afe_audio_client *ac;
+ int lcnt = 0;
+
+ ac = kzalloc(sizeof(struct afe_audio_client), GFP_KERNEL);
+ if (!ac)
+ return NULL;
+
+ ac->priv = priv;
+
+ init_waitqueue_head(&ac->cmd_wait);
+ INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
+ INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
+ pr_debug("%s: mem_map_handle list init'ed\n", __func__);
+ mutex_init(&ac->cmd_lock);
+ for (lcnt = 0; lcnt <= OUT; lcnt++) {
+ mutex_init(&ac->port[lcnt].lock);
+ spin_lock_init(&ac->port[lcnt].dsp_lock);
+ }
+ atomic_set(&ac->cmd_state, 0);
+
+ return ac;
+}
+
+int q6afe_audio_client_buf_alloc_contiguous(unsigned int dir,
+ struct afe_audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt)
+{
+ int cnt = 0;
+ int rc = 0;
+ struct afe_audio_buffer *buf;
+ size_t len;
+
+ if (!(ac) || ((dir != IN) && (dir != OUT))) {
+ pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: bufsz[%d]bufcnt[%d]\n",
+ __func__,
+ bufsz, bufcnt);
+
+ if (ac->port[dir].buf) {
+ pr_debug("%s: buffer already allocated\n", __func__);
+ return 0;
+ }
+ mutex_lock(&ac->cmd_lock);
+ buf = kzalloc(((sizeof(struct afe_audio_buffer))*bufcnt),
+ GFP_KERNEL);
+
+ if (!buf) {
+ pr_err("%s: null buf\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ ac->port[dir].buf = buf;
+
+ rc = msm_audio_ion_alloc("afe_client", &buf[0].client,
+ &buf[0].handle, bufsz*bufcnt,
+ &buf[0].phys, &len,
+ &buf[0].data);
+ if (rc) {
+ pr_err("%s: audio ION alloc failed, rc = %d\n",
+ __func__, rc);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ buf[0].used = dir ^ 1;
+ buf[0].size = bufsz;
+ buf[0].actual_size = bufsz;
+ cnt = 1;
+ while (cnt < bufcnt) {
+ if (bufsz > 0) {
+ buf[cnt].data = buf[0].data + (cnt * bufsz);
+ buf[cnt].phys = buf[0].phys + (cnt * bufsz);
+ if (!buf[cnt].data) {
+ pr_err("%s: Buf alloc failed\n",
+ __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+ buf[cnt].used = dir ^ 1;
+ buf[cnt].size = bufsz;
+ buf[cnt].actual_size = bufsz;
+ pr_debug("%s: data[%pK]phys[%pK][%pK]\n", __func__,
+ buf[cnt].data,
+ &buf[cnt].phys,
+ &buf[cnt].phys);
+ }
+ cnt++;
+ }
+ ac->port[dir].max_buf_cnt = cnt;
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+fail:
+ pr_err("%s: jump fail\n", __func__);
+ q6afe_audio_client_buf_free_contiguous(dir, ac);
+ return -EINVAL;
+}
+
+int afe_memory_map(phys_addr_t dma_addr_p, u32 dma_buf_sz,
+ struct afe_audio_client *ac)
+{
+ int ret = 0;
+
+ mutex_lock(&this_afe.afe_cmd_lock);
+ ac->mem_map_handle = 0;
+ ret = afe_cmd_memory_map(dma_addr_p, dma_buf_sz);
+ if (ret < 0) {
+ pr_err("%s: afe_cmd_memory_map failed %d\n",
+ __func__, ret);
+
+ mutex_unlock(&this_afe.afe_cmd_lock);
+ return ret;
+ }
+ ac->mem_map_handle = this_afe.mmap_handle;
+ mutex_unlock(&this_afe.afe_cmd_lock);
+
+ return ret;
+}
+
+int afe_cmd_memory_map(phys_addr_t dma_addr_p, u32 dma_buf_sz)
+{
+ int ret = 0;
+ int cmd_size = 0;
+ void *payload = NULL;
+ void *mmap_region_cmd = NULL;
+ struct afe_service_cmd_shared_mem_map_regions *mregion = NULL;
+ struct afe_service_shared_map_region_payload *mregion_pl = NULL;
+ int index = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+ if (dma_buf_sz % SZ_4K != 0) {
+ /*
+ * The memory allocated by msm_audio_ion_alloc is always 4kB
+ * aligned, ADSP expects the size to be 4kB aligned as well
+ * so re-adjusts the buffer size before passing to ADSP.
+ */
+ dma_buf_sz = PAGE_ALIGN(dma_buf_sz);
+ }
+
+ cmd_size = sizeof(struct afe_service_cmd_shared_mem_map_regions)
+ + sizeof(struct afe_service_shared_map_region_payload);
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (!mmap_region_cmd)
+ return -ENOMEM;
+
+ mregion = (struct afe_service_cmd_shared_mem_map_regions *)
+ mmap_region_cmd;
+ mregion->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mregion->hdr.pkt_size = cmd_size;
+ mregion->hdr.src_port = 0;
+ mregion->hdr.dest_port = 0;
+ mregion->hdr.token = 0;
+ mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
+ mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ mregion->num_regions = 1;
+ mregion->property_flag = 0x00;
+ /* Todo */
+ index = mregion->hdr.token = IDX_RSVD_2;
+
+ payload = ((u8 *) mmap_region_cmd +
+ sizeof(struct afe_service_cmd_shared_mem_map_regions));
+
+ mregion_pl = (struct afe_service_shared_map_region_payload *)payload;
+
+ mregion_pl->shm_addr_lsw = lower_32_bits(dma_addr_p);
+ mregion_pl->shm_addr_msw = msm_audio_populate_upper_32_bits(dma_addr_p);
+ mregion_pl->mem_size_bytes = dma_buf_sz;
+
+ pr_debug("%s: dma_addr_p 0x%pK , size %d\n", __func__,
+ &dma_addr_p, dma_buf_sz);
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ this_afe.mmap_handle = 0;
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
+ if (ret < 0) {
+ pr_err("%s: AFE memory map cmd failed %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+ kfree(mmap_region_cmd);
+ return 0;
+fail_cmd:
+ kfree(mmap_region_cmd);
+ pr_err("%s: fail_cmd\n", __func__);
+ return ret;
+}
+
+int afe_cmd_memory_map_nowait(int port_id, phys_addr_t dma_addr_p,
+ u32 dma_buf_sz)
+{
+ int ret = 0;
+ int cmd_size = 0;
+ void *payload = NULL;
+ void *mmap_region_cmd = NULL;
+ struct afe_service_cmd_shared_mem_map_regions *mregion = NULL;
+ struct afe_service_shared_map_region_payload *mregion_pl = NULL;
+ int index = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ cmd_size = sizeof(struct afe_service_cmd_shared_mem_map_regions)
+ + sizeof(struct afe_service_shared_map_region_payload);
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (!mmap_region_cmd)
+ return -ENOMEM;
+
+ mregion = (struct afe_service_cmd_shared_mem_map_regions *)
+ mmap_region_cmd;
+ mregion->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mregion->hdr.pkt_size = sizeof(mregion);
+ mregion->hdr.src_port = 0;
+ mregion->hdr.dest_port = 0;
+ mregion->hdr.token = 0;
+ mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
+ mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ mregion->num_regions = 1;
+ mregion->property_flag = 0x00;
+
+ payload = ((u8 *) mmap_region_cmd +
+ sizeof(struct afe_service_cmd_shared_mem_map_regions));
+ mregion_pl = (struct afe_service_shared_map_region_payload *)payload;
+
+ mregion_pl->shm_addr_lsw = lower_32_bits(dma_addr_p);
+ mregion_pl->shm_addr_msw = msm_audio_populate_upper_32_bits(dma_addr_p);
+ mregion_pl->mem_size_bytes = dma_buf_sz;
+
+ ret = afe_apr_send_pkt(mmap_region_cmd, NULL);
+ if (ret)
+ pr_err("%s: AFE memory map cmd failed %d\n",
+ __func__, ret);
+ kfree(mmap_region_cmd);
+ return ret;
+}
+int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
+ struct afe_audio_client *ac)
+{
+ struct afe_audio_port_data *port;
+ int cnt = 0;
+
+ mutex_lock(&ac->cmd_lock);
+ port = &ac->port[dir];
+ if (!port->buf) {
+ pr_err("%s: buf is null\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+ }
+ cnt = port->max_buf_cnt - 1;
+
+ if (port->buf[0].data) {
+ pr_debug("%s: data[%pK]phys[%pK][%pK] , client[%pK] handle[%pK]\n",
+ __func__,
+ port->buf[0].data,
+ &port->buf[0].phys,
+ &port->buf[0].phys,
+ port->buf[0].client,
+ port->buf[0].handle);
+ msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
+ port->buf[0].client = NULL;
+ port->buf[0].handle = NULL;
+ }
+
+ while (cnt >= 0) {
+ port->buf[cnt].data = NULL;
+ port->buf[cnt].phys = 0;
+ cnt--;
+ }
+ port->max_buf_cnt = 0;
+ kfree(port->buf);
+ port->buf = NULL;
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+}
+
+void q6afe_audio_client_free(struct afe_audio_client *ac)
+{
+ int loopcnt;
+ struct afe_audio_port_data *port;
+
+ if (!ac) {
+ pr_err("%s: audio client is NULL\n", __func__);
+ return;
+ }
+ for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+ port = &ac->port[loopcnt];
+ if (!port->buf)
+ continue;
+ pr_debug("%s: loopcnt = %d\n", __func__, loopcnt);
+ q6afe_audio_client_buf_free_contiguous(loopcnt, ac);
+ }
+ kfree(ac);
+}
+
+int afe_cmd_memory_unmap(u32 mem_map_handle)
+{
+ int ret = 0;
+ struct afe_service_cmd_shared_mem_unmap_regions mregion;
+ int index = 0;
+
+ pr_debug("%s: handle 0x%x\n", __func__, mem_map_handle);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+
+ mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mregion.hdr.pkt_size = sizeof(mregion);
+ mregion.hdr.src_port = 0;
+ mregion.hdr.dest_port = 0;
+ mregion.hdr.token = 0;
+ mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
+ mregion.mem_map_handle = mem_map_handle;
+
+ /* Todo */
+ index = mregion.hdr.token = IDX_RSVD_2;
+
+ atomic_set(&this_afe.status, 0);
+ ret = afe_apr_send_pkt(&mregion, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE memory unmap cmd failed %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+int afe_cmd_memory_unmap_nowait(u32 mem_map_handle)
+{
+ int ret = 0;
+ struct afe_service_cmd_shared_mem_unmap_regions mregion;
+
+ pr_debug("%s: handle 0x%x\n", __func__, mem_map_handle);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+
+ mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mregion.hdr.pkt_size = sizeof(mregion);
+ mregion.hdr.src_port = 0;
+ mregion.hdr.dest_port = 0;
+ mregion.hdr.token = 0;
+ mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
+ mregion.mem_map_handle = mem_map_handle;
+
+ ret = afe_apr_send_pkt(&mregion, NULL);
+ if (ret)
+ pr_err("%s: AFE memory unmap cmd failed %d\n",
+ __func__, ret);
+ return ret;
+}
+
+int afe_register_get_events(u16 port_id,
+ void (*cb)(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv),
+ void *private_data)
+{
+ int ret = 0;
+ struct afe_service_cmd_register_rt_port_driver rtproxy;
+
+ pr_debug("%s: port_id: 0x%x\n", __func__, port_id);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+ if ((port_id == RT_PROXY_DAI_002_RX) ||
+ (port_id == RT_PROXY_DAI_001_TX)) {
+ port_id = VIRTUAL_ID_TO_PORTID(port_id);
+ } else {
+ pr_err("%s: wrong port id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ if (port_id == RT_PROXY_PORT_001_TX) {
+ this_afe.tx_cb = cb;
+ this_afe.tx_private_data = private_data;
+ } else if (port_id == RT_PROXY_PORT_001_RX) {
+ this_afe.rx_cb = cb;
+ this_afe.rx_private_data = private_data;
+ }
+
+ rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ rtproxy.hdr.pkt_size = sizeof(rtproxy);
+ rtproxy.hdr.src_port = 1;
+ rtproxy.hdr.dest_port = 1;
+ rtproxy.hdr.opcode = AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER;
+ rtproxy.port_id = port_id;
+ rtproxy.reserved = 0;
+
+ ret = afe_apr_send_pkt(&rtproxy, NULL);
+ if (ret)
+ pr_err("%s: AFE reg. rtproxy_event failed %d\n",
+ __func__, ret);
+ return ret;
+}
+
+int afe_unregister_get_events(u16 port_id)
+{
+ int ret = 0;
+ struct afe_service_cmd_unregister_rt_port_driver rtproxy;
+ int index = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+
+ if ((port_id == RT_PROXY_DAI_002_RX) ||
+ (port_id == RT_PROXY_DAI_001_TX)) {
+ port_id = VIRTUAL_ID_TO_PORTID(port_id);
+ } else {
+ pr_err("%s: wrong port id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x ret %d", __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ rtproxy.hdr.pkt_size = sizeof(rtproxy);
+ rtproxy.hdr.src_port = 0;
+ rtproxy.hdr.dest_port = 0;
+ rtproxy.hdr.token = 0;
+ rtproxy.hdr.opcode = AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER;
+ rtproxy.port_id = port_id;
+ rtproxy.reserved = 0;
+
+ rtproxy.hdr.token = index;
+
+ if (port_id == RT_PROXY_PORT_001_TX) {
+ this_afe.tx_cb = NULL;
+ this_afe.tx_private_data = NULL;
+ } else if (port_id == RT_PROXY_PORT_001_RX) {
+ this_afe.rx_cb = NULL;
+ this_afe.rx_private_data = NULL;
+ }
+
+ ret = afe_apr_send_pkt(&rtproxy, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
+ __func__, ret);
+ return ret;
+}
+
+int afe_rt_proxy_port_write(phys_addr_t buf_addr_p,
+ u32 mem_map_handle, int bytes)
+{
+ int ret = 0;
+ struct afe_port_data_cmd_rt_proxy_port_write_v2 afecmd_wr;
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: register to AFE is not done\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ pr_debug("%s: buf_addr_p = 0x%pK bytes = %d\n", __func__,
+ &buf_addr_p, bytes);
+
+ afecmd_wr.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ afecmd_wr.hdr.pkt_size = sizeof(afecmd_wr);
+ afecmd_wr.hdr.src_port = 0;
+ afecmd_wr.hdr.dest_port = 0;
+ afecmd_wr.hdr.token = 0;
+ afecmd_wr.hdr.opcode = AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2;
+ afecmd_wr.port_id = RT_PROXY_PORT_001_TX;
+ afecmd_wr.buffer_address_lsw = lower_32_bits(buf_addr_p);
+ afecmd_wr.buffer_address_msw =
+ msm_audio_populate_upper_32_bits(buf_addr_p);
+ afecmd_wr.mem_map_handle = mem_map_handle;
+ afecmd_wr.available_bytes = bytes;
+ afecmd_wr.reserved = 0;
+
+ ret = afe_apr_send_pkt(&afecmd_wr, NULL);
+ if (ret)
+ pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
+ __func__, afecmd_wr.port_id, ret);
+ return ret;
+
+}
+
+int afe_rt_proxy_port_read(phys_addr_t buf_addr_p,
+ u32 mem_map_handle, int bytes)
+{
+ int ret = 0;
+ struct afe_port_data_cmd_rt_proxy_port_read_v2 afecmd_rd;
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: register to AFE is not done\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ pr_debug("%s: buf_addr_p = 0x%pK bytes = %d\n", __func__,
+ &buf_addr_p, bytes);
+
+ afecmd_rd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ afecmd_rd.hdr.pkt_size = sizeof(afecmd_rd);
+ afecmd_rd.hdr.src_port = 0;
+ afecmd_rd.hdr.dest_port = 0;
+ afecmd_rd.hdr.token = 0;
+ afecmd_rd.hdr.opcode = AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2;
+ afecmd_rd.port_id = RT_PROXY_PORT_001_RX;
+ afecmd_rd.buffer_address_lsw = lower_32_bits(buf_addr_p);
+ afecmd_rd.buffer_address_msw =
+ msm_audio_populate_upper_32_bits(buf_addr_p);
+ afecmd_rd.available_bytes = bytes;
+ afecmd_rd.mem_map_handle = mem_map_handle;
+
+ ret = afe_apr_send_pkt(&afecmd_rd, NULL);
+ if (ret)
+ pr_err("%s: AFE rtproxy read cmd to port 0x%x failed %d\n",
+ __func__, afecmd_rd.port_id, ret);
+ return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_afelb;
+static struct dentry *debugfs_afelb_gain;
+
+static int afe_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ pr_info("%s: debug intf %s\n", __func__, (char *) file->private_data);
+ return 0;
+}
+
+static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
+{
+ char *token;
+ int base, cnt;
+
+ token = strsep(&buf, " ");
+
+ for (cnt = 0; cnt < num_of_par; cnt++) {
+ if (token != NULL) {
+ if ((token[1] == 'x') || (token[1] == 'X'))
+ base = 16;
+ else
+ base = 10;
+
+ if (kstrtoul(token, base, ¶m1[cnt]) != 0) {
+ pr_err("%s: kstrtoul failed\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ token = strsep(&buf, " ");
+ } else {
+ pr_err("%s: token NULL\n", __func__);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+#define AFE_LOOPBACK_ON (1)
+#define AFE_LOOPBACK_OFF (0)
+static ssize_t afe_debug_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char *lb_str = filp->private_data;
+ char lbuf[32];
+ int rc;
+ unsigned long param[5];
+
+ if (cnt > sizeof(lbuf) - 1) {
+ pr_err("%s: cnt %zd size %zd\n", __func__, cnt, sizeof(lbuf)-1);
+ return -EINVAL;
+ }
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc) {
+ pr_err("%s: copy from user failed %d\n", __func__, rc);
+ return -EFAULT;
+ }
+
+ lbuf[cnt] = '\0';
+
+ if (!strcmp(lb_str, "afe_loopback")) {
+ rc = afe_get_parameters(lbuf, param, 3);
+ if (!rc) {
+ pr_info("%s: %lu %lu %lu\n", lb_str, param[0], param[1],
+ param[2]);
+
+ if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
+ AFE_LOOPBACK_OFF)) {
+ pr_err("%s: Error, parameter 0 incorrect\n",
+ __func__);
+ rc = -EINVAL;
+ goto afe_error;
+ }
+ if ((q6audio_validate_port(param[1]) < 0) ||
+ (q6audio_validate_port(param[2])) < 0) {
+ pr_err("%s: Error, invalid afe port\n",
+ __func__);
+ }
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Error, AFE not opened\n", __func__);
+ rc = -EINVAL;
+ } else {
+ rc = afe_loopback(param[0], param[1], param[2]);
+ }
+ } else {
+ pr_err("%s: Error, invalid parameters\n", __func__);
+ rc = -EINVAL;
+ }
+
+ } else if (!strcmp(lb_str, "afe_loopback_gain")) {
+ rc = afe_get_parameters(lbuf, param, 2);
+ if (!rc) {
+ pr_info("%s: %s %lu %lu\n",
+ __func__, lb_str, param[0], param[1]);
+
+ rc = q6audio_validate_port(param[0]);
+ if (rc < 0) {
+ pr_err("%s: Error, invalid afe port %d %lu\n",
+ __func__, rc, param[0]);
+ rc = -EINVAL;
+ goto afe_error;
+ }
+
+ if (param[1] > 100) {
+ pr_err("%s: Error, volume should be 0 to 100 percentage param = %lu\n",
+ __func__, param[1]);
+ rc = -EINVAL;
+ goto afe_error;
+ }
+
+ param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Error, AFE not opened\n", __func__);
+ rc = -EINVAL;
+ } else {
+ rc = afe_loopback_gain(param[0], param[1]);
+ }
+ } else {
+ pr_err("%s: Error, invalid parameters\n", __func__);
+ rc = -EINVAL;
+ }
+ }
+
+afe_error:
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static const struct file_operations afe_debug_fops = {
+ .open = afe_debug_open,
+ .write = afe_debug_write
+};
+
+static void config_debug_fs_init(void)
+{
+ debugfs_afelb = debugfs_create_file("afe_loopback",
+ 0664, NULL, (void *) "afe_loopback",
+ &afe_debug_fops);
+
+ debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
+ 0664, NULL, (void *) "afe_loopback_gain",
+ &afe_debug_fops);
+}
+static void config_debug_fs_exit(void)
+{
+ debugfs_remove(debugfs_afelb);
+ debugfs_remove(debugfs_afelb_gain);
+}
+#else
+static void config_debug_fs_init(void)
+{
+}
+static void config_debug_fs_exit(void)
+{
+}
+#endif
+
+void afe_set_dtmf_gen_rx_portid(u16 port_id, int set)
+{
+ if (set)
+ this_afe.dtmf_gen_rx_portid = port_id;
+ else if (this_afe.dtmf_gen_rx_portid == port_id)
+ this_afe.dtmf_gen_rx_portid = -1;
+}
+
+int afe_dtmf_generate_rx(int64_t duration_in_ms,
+ uint16_t high_freq,
+ uint16_t low_freq, uint16_t gain)
+{
+ int ret = 0;
+ int index = 0;
+ struct afe_dtmf_generation_command cmd_dtmf;
+
+ pr_debug("%s: DTMF AFE Gen\n", __func__);
+
+ if (afe_validate_port(this_afe.dtmf_gen_rx_portid) < 0) {
+ pr_err("%s: Failed : Invalid Port id = 0x%x\n",
+ __func__, this_afe.dtmf_gen_rx_portid);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_afe_handle(this_afe.apr);
+ }
+
+ pr_debug("%s: dur=%lld: hfreq=%d lfreq=%d gain=%d portid=0x%x\n",
+ __func__,
+ duration_in_ms, high_freq, low_freq, gain,
+ this_afe.dtmf_gen_rx_portid);
+
+ cmd_dtmf.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cmd_dtmf.hdr.pkt_size = sizeof(cmd_dtmf);
+ cmd_dtmf.hdr.src_port = 0;
+ cmd_dtmf.hdr.dest_port = 0;
+ cmd_dtmf.hdr.token = 0;
+ cmd_dtmf.hdr.opcode = AFE_PORTS_CMD_DTMF_CTL;
+ cmd_dtmf.duration_in_ms = duration_in_ms;
+ cmd_dtmf.high_freq = high_freq;
+ cmd_dtmf.low_freq = low_freq;
+ cmd_dtmf.gain = gain;
+ cmd_dtmf.num_ports = 1;
+ cmd_dtmf.port_ids = q6audio_get_port_id(this_afe.dtmf_gen_rx_portid);
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_dtmf);
+ if (ret < 0) {
+ pr_err("%s: AFE DTMF failed for num_ports:%d ids:0x%x\n",
+ __func__, cmd_dtmf.num_ports, cmd_dtmf.port_ids);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(this_afe.dtmf_gen_rx_portid);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+ return 0;
+
+fail_cmd:
+ pr_err("%s: failed %d\n", __func__, ret);
+ return ret;
+}
+
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
+{
+ struct afe_loopback_cfg_v1 cmd_sidetone;
+ int ret = 0;
+ int index = 0;
+
+ pr_info("%s: tx_port_id: 0x%x rx_port_id: 0x%x enable:%d gain:%d\n",
+ __func__, tx_port_id, rx_port_id, enable, gain);
+ index = q6audio_get_port_index(rx_port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(rx_port_id);
+ if (ret < 0) {
+ pr_err("%s: Invalid port 0x%x %d", __func__, rx_port_id, ret);
+ return -EINVAL;
+ }
+
+ cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
+ cmd_sidetone.hdr.src_port = 0;
+ cmd_sidetone.hdr.dest_port = 0;
+ cmd_sidetone.hdr.token = 0;
+ cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ /* should it be rx or tx port id ?? , bharath*/
+ cmd_sidetone.param.port_id = tx_port_id;
+ /* size of data param & payload */
+ cmd_sidetone.param.payload_size = (sizeof(cmd_sidetone) -
+ sizeof(struct apr_hdr) -
+ sizeof(struct afe_port_cmd_set_param_v2));
+ cmd_sidetone.param.payload_address_lsw = 0x00;
+ cmd_sidetone.param.payload_address_msw = 0x00;
+ cmd_sidetone.param.mem_map_handle = 0x00;
+ cmd_sidetone.pdata.module_id = AFE_MODULE_LOOPBACK;
+ cmd_sidetone.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+ /* size of actual payload only */
+ cmd_sidetone.pdata.param_size = cmd_sidetone.param.payload_size -
+ sizeof(struct afe_port_param_data_v2);
+
+ cmd_sidetone.loopback_cfg_minor_version =
+ AFE_API_VERSION_LOOPBACK_CONFIG;
+ cmd_sidetone.dst_port_id = rx_port_id;
+ cmd_sidetone.routing_mode = LB_MODE_SIDETONE;
+ cmd_sidetone.enable = enable;
+
+ ret = afe_apr_send_pkt(&cmd_sidetone, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: sidetone failed tx_port:0x%x rx_port:0x%x ret%d\n",
+ __func__, tx_port_id, rx_port_id, ret);
+ return ret;
+}
+
+int afe_validate_port(u16 port_id)
+{
+ int ret;
+
+ switch (port_id) {
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ case SECONDARY_I2S_RX:
+ case SECONDARY_I2S_TX:
+ case MI2S_RX:
+ case MI2S_TX:
+ case HDMI_RX:
+ case DISPLAY_PORT_RX:
+ case AFE_PORT_ID_SPDIF_RX:
+ case RSVD_2:
+ case RSVD_3:
+ case DIGI_MIC_TX:
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
+ case INT_BT_SCO_RX:
+ case INT_BT_SCO_TX:
+ case INT_BT_A2DP_RX:
+ case INT_FM_RX:
+ case INT_FM_TX:
+ case RT_PROXY_PORT_001_RX:
+ case RT_PROXY_PORT_001_TX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_4_TX:
+ case SLIMBUS_5_RX:
+ case SLIMBUS_6_RX:
+ case SLIMBUS_6_TX:
+ case SLIMBUS_7_RX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_RX:
+ case SLIMBUS_8_TX:
+ case AFE_PORT_ID_USB_RX:
+ case AFE_PORT_ID_USB_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ case AFE_PORT_ID_QUINARY_MI2S_RX:
+ case AFE_PORT_ID_QUINARY_MI2S_TX:
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ {
+ ret = 0;
+ break;
+ }
+
+ default:
+ pr_err("%s: default ret 0x%x\n", __func__, port_id);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int afe_convert_virtual_to_portid(u16 port_id)
+{
+ int ret;
+
+ /*
+ * if port_id is virtual, convert to physical..
+ * if port_id is already physical, return physical
+ */
+ if (afe_validate_port(port_id) < 0) {
+ if (port_id == RT_PROXY_DAI_001_RX ||
+ port_id == RT_PROXY_DAI_001_TX ||
+ port_id == RT_PROXY_DAI_002_RX ||
+ port_id == RT_PROXY_DAI_002_TX) {
+ ret = VIRTUAL_ID_TO_PORTID(port_id);
+ } else {
+ pr_err("%s: wrong port 0x%x\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ }
+ } else
+ ret = port_id;
+
+ return ret;
+}
+int afe_port_stop_nowait(int port_id)
+{
+ struct afe_port_cmd_device_stop stop;
+ int ret = 0;
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE is already closed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ pr_debug("%s: port_id = 0x%x\n", __func__, port_id);
+ port_id = q6audio_convert_virtual_to_portid(port_id);
+
+ stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ stop.hdr.pkt_size = sizeof(stop);
+ stop.hdr.src_port = 0;
+ stop.hdr.dest_port = 0;
+ stop.hdr.token = 0;
+ stop.hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
+ stop.port_id = port_id;
+ stop.reserved = 0;
+
+ ret = afe_apr_send_pkt(&stop, NULL);
+ if (ret)
+ pr_err("%s: AFE close failed %d\n", __func__, ret);
+
+fail_cmd:
+ return ret;
+
+}
+
+int afe_close(int port_id)
+{
+ struct afe_port_cmd_device_stop stop;
+ enum afe_mad_type mad_type;
+ int ret = 0;
+ int index = 0;
+ uint16_t port_index;
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE is already closed\n", __func__);
+ if ((port_id == RT_PROXY_DAI_001_RX) ||
+ (port_id == RT_PROXY_DAI_002_TX))
+ pcm_afe_instance[port_id & 0x1] = 0;
+ if ((port_id == RT_PROXY_DAI_002_RX) ||
+ (port_id == RT_PROXY_DAI_001_TX))
+ proxy_afe_instance[port_id & 0x1] = 0;
+ afe_close_done[port_id & 0x1] = true;
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ pr_debug("%s: port_id = 0x%x\n", __func__, port_id);
+ if ((port_id == RT_PROXY_DAI_001_RX) ||
+ (port_id == RT_PROXY_DAI_002_TX)) {
+ pr_debug("%s: before decrementing pcm_afe_instance %d\n",
+ __func__, pcm_afe_instance[port_id & 0x1]);
+ port_id = VIRTUAL_ID_TO_PORTID(port_id);
+ pcm_afe_instance[port_id & 0x1]--;
+ if ((!(pcm_afe_instance[port_id & 0x1] == 0 &&
+ proxy_afe_instance[port_id & 0x1] == 0)) ||
+ afe_close_done[port_id & 0x1] == true)
+ return 0;
+
+ afe_close_done[port_id & 0x1] = true;
+ }
+
+ if ((port_id == RT_PROXY_DAI_002_RX) ||
+ (port_id == RT_PROXY_DAI_001_TX)) {
+ pr_debug("%s: before decrementing proxy_afe_instance %d\n",
+ __func__, proxy_afe_instance[port_id & 0x1]);
+ port_id = VIRTUAL_ID_TO_PORTID(port_id);
+ proxy_afe_instance[port_id & 0x1]--;
+ if ((!(pcm_afe_instance[port_id & 0x1] == 0 &&
+ proxy_afe_instance[port_id & 0x1] == 0)) ||
+ afe_close_done[port_id & 0x1] == true)
+ return 0;
+
+ afe_close_done[port_id & 0x1] = true;
+ }
+
+ port_id = q6audio_convert_virtual_to_portid(port_id);
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_validate_port(port_id);
+ if (ret < 0) {
+ pr_warn("%s: Not a valid port id 0x%x ret %d\n",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ if (mad_type != MAD_HW_NONE && mad_type != MAD_SW_AUDIO) {
+ pr_debug("%s: Turn off MAD\n", __func__);
+ ret = afe_turn_onoff_hw_mad(mad_type, false);
+ if (ret) {
+ pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+ } else {
+ pr_debug("%s: Not a MAD port\n", __func__);
+ }
+
+ port_index = afe_get_port_index(port_id);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[port_index] = 0;
+ this_afe.topology[port_index] = 0;
+ } else {
+ pr_err("%s: port %d\n", __func__, port_index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if ((port_id == this_afe.aanc_info.aanc_tx_port) &&
+ (this_afe.aanc_info.aanc_active)) {
+ memset(&this_afe.aanc_info, 0x00, sizeof(this_afe.aanc_info));
+ ret = afe_aanc_mod_enable(this_afe.apr, port_id, 0);
+ if (ret)
+ pr_err("%s: AFE mod disable failed %d\n",
+ __func__, ret);
+ }
+
+ /*
+ * even if ramp down configuration failed it is not serious enough to
+ * warrant bailaing out.
+ */
+ if (afe_spk_ramp_dn_cfg(port_id) < 0)
+ pr_err("%s: ramp down configuration failed\n", __func__);
+
+ stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ stop.hdr.pkt_size = sizeof(stop);
+ stop.hdr.src_port = 0;
+ stop.hdr.dest_port = 0;
+ stop.hdr.token = index;
+ stop.hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
+ stop.port_id = q6audio_get_port_id(port_id);
+ stop.reserved = 0;
+
+ ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE close failed %d\n", __func__, ret);
+
+fail_cmd:
+ return ret;
+}
+
+int afe_set_digital_codec_core_clock(u16 port_id,
+ struct afe_digital_clk_cfg *cfg)
+{
+ struct afe_lpass_digital_clk_config_command clk_cfg;
+ int index = 0;
+ int ret = 0;
+
+ if (!cfg) {
+ pr_err("%s: clock cfg is NULL\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
+ clk_cfg.hdr.src_port = 0;
+ clk_cfg.hdr.dest_port = 0;
+ clk_cfg.hdr.token = index;
+
+ clk_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ /*default rx port is taken to enable the codec digital clock*/
+ clk_cfg.param.port_id = q6audio_get_port_id(port_id);
+ clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
+ - sizeof(clk_cfg.param);
+ clk_cfg.param.payload_address_lsw = 0x00;
+ clk_cfg.param.payload_address_msw = 0x00;
+ clk_cfg.param.mem_map_handle = 0x00;
+ clk_cfg.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ clk_cfg.pdata.param_id = AFE_PARAM_ID_INTERNAL_DIGIATL_CDC_CLK_CONFIG;
+ clk_cfg.pdata.param_size = sizeof(clk_cfg.clk_cfg);
+ clk_cfg.clk_cfg = *cfg;
+
+ pr_debug("%s: Minor version =0x%x clk val = %d\n"
+ "clk root = 0x%x resrv = 0x%x\n",
+ __func__, cfg->i2s_cfg_minor_version,
+ cfg->clk_val, cfg->clk_root, cfg->reserved);
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port 0x%x ret %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg)
+{
+ struct afe_lpass_clk_config_command clk_cfg;
+ int index = 0;
+ int ret = 0;
+
+ if (!cfg) {
+ pr_err("%s: clock cfg is NULL\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_is_digital_pcm_interface(port_id);
+ if (ret < 0) {
+ pr_err("%s: q6audio_is_digital_pcm_interface fail %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ mutex_lock(&this_afe.afe_cmd_lock);
+ clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
+ clk_cfg.hdr.src_port = 0;
+ clk_cfg.hdr.dest_port = 0;
+ clk_cfg.hdr.token = index;
+
+ clk_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ clk_cfg.param.port_id = q6audio_get_port_id(port_id);
+ clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
+ - sizeof(clk_cfg.param);
+ clk_cfg.param.payload_address_lsw = 0x00;
+ clk_cfg.param.payload_address_msw = 0x00;
+ clk_cfg.param.mem_map_handle = 0x00;
+ clk_cfg.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ clk_cfg.pdata.param_id = AFE_PARAM_ID_LPAIF_CLK_CONFIG;
+ clk_cfg.pdata.param_size = sizeof(clk_cfg.clk_cfg);
+ clk_cfg.clk_cfg = *cfg;
+
+ pr_debug("%s: Minor version =0x%x clk val1 = %d\n"
+ "clk val2 = %d, clk src = 0x%x\n"
+ "clk root = 0x%x clk mode = 0x%x resrv = 0x%x\n"
+ "port id = 0x%x\n",
+ __func__, cfg->i2s_cfg_minor_version,
+ cfg->clk_val1, cfg->clk_val2, cfg->clk_src,
+ cfg->clk_root, cfg->clk_set_mode,
+ cfg->reserved, q6audio_get_port_id(port_id));
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port 0x%x ret %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ mutex_unlock(&this_afe.afe_cmd_lock);
+ return ret;
+}
+
+int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg)
+{
+ struct afe_lpass_clk_config_command_v2 clk_cfg;
+ int ret = 0;
+
+ if (!cfg) {
+ pr_err("%s: clock cfg is NULL\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: index[%d] invalid!\n", __func__, index);
+ return -EINVAL;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ mutex_lock(&this_afe.afe_cmd_lock);
+ clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
+ clk_cfg.hdr.src_port = 0;
+ clk_cfg.hdr.dest_port = 0;
+ clk_cfg.hdr.token = index;
+
+ clk_cfg.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+ clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
+ - sizeof(clk_cfg.param);
+ clk_cfg.param.payload_address_lsw = 0x00;
+ clk_cfg.param.payload_address_msw = 0x00;
+ clk_cfg.param.mem_map_handle = 0x00;
+ clk_cfg.pdata.module_id = AFE_MODULE_CLOCK_SET;
+ clk_cfg.pdata.param_id = AFE_PARAM_ID_CLOCK_SET;
+ clk_cfg.pdata.param_size = sizeof(clk_cfg.clk_cfg);
+ clk_cfg.clk_cfg = *cfg;
+
+
+ pr_debug("%s: Minor version =0x%x clk id = %d\n"
+ "clk freq (Hz) = %d, clk attri = 0x%x\n"
+ "clk root = 0x%x clk enable = 0x%x\n",
+ __func__, cfg->clk_set_minor_version,
+ cfg->clk_id, cfg->clk_freq_in_hz, cfg->clk_attri,
+ cfg->clk_root, cfg->enable);
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
+ if (ret < 0) {
+ pr_err("%s: AFE clk cfg failed with ret %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ } else {
+ /* set ret to 0 as no timeout happened */
+ ret = 0;
+ }
+ if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ mutex_unlock(&this_afe.afe_cmd_lock);
+ return ret;
+}
+
+int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg)
+{
+ int index = 0;
+ int ret = 0;
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_is_digital_pcm_interface(port_id);
+ if (ret < 0) {
+ pr_err("%s: q6audio_is_digital_pcm_interface fail %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = afe_set_lpass_clk_cfg(index, cfg);
+ if (ret)
+ pr_err("%s: afe_set_lpass_clk_cfg_v2 failed %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+int afe_set_lpass_internal_digital_codec_clock(u16 port_id,
+ struct afe_digital_clk_cfg *cfg)
+{
+ struct afe_lpass_digital_clk_config_command clk_cfg;
+ int index = 0;
+ int ret = 0;
+
+ if (!cfg) {
+ pr_err("%s: clock cfg is NULL\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_is_digital_pcm_interface(port_id);
+ if (ret < 0) {
+ pr_err("%s: q6audio_is_digital_pcm_interface fail %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
+ clk_cfg.hdr.src_port = 0;
+ clk_cfg.hdr.dest_port = 0;
+ clk_cfg.hdr.token = index;
+
+ clk_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ clk_cfg.param.port_id = q6audio_get_port_id(port_id);
+ clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
+ - sizeof(clk_cfg.param);
+ clk_cfg.param.payload_address_lsw = 0x00;
+ clk_cfg.param.payload_address_msw = 0x00;
+ clk_cfg.param.mem_map_handle = 0x00;
+ clk_cfg.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ clk_cfg.pdata.param_id = AFE_PARAM_ID_INTERNAL_DIGIATL_CDC_CLK_CONFIG;
+ clk_cfg.pdata.param_size = sizeof(clk_cfg.clk_cfg);
+ clk_cfg.clk_cfg = *cfg;
+
+ pr_debug("%s: Minor version =0x%x clk val = %d\n"
+ "clk root = 0x%x resrv = 0x%x port id = 0x%x\n",
+ __func__, cfg->i2s_cfg_minor_version,
+ cfg->clk_val, cfg->clk_root, cfg->reserved,
+ q6audio_get_port_id(port_id));
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port 0x0x%x ret %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+int afe_enable_lpass_core_shared_clock(u16 port_id, u32 enable)
+{
+ struct afe_lpass_core_shared_clk_config_command clk_cfg;
+ int index = 0;
+ int ret = 0;
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ return -EINVAL;
+ }
+ ret = q6audio_is_digital_pcm_interface(port_id);
+ if (ret < 0) {
+ pr_err("%s: q6audio_is_digital_pcm_interface fail %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ mutex_lock(&this_afe.afe_cmd_lock);
+ clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
+ clk_cfg.hdr.src_port = 0;
+ clk_cfg.hdr.dest_port = 0;
+ clk_cfg.hdr.token = index;
+
+ clk_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ clk_cfg.param.port_id = q6audio_get_port_id(port_id);
+ clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
+ - sizeof(clk_cfg.param);
+ clk_cfg.param.payload_address_lsw = 0x00;
+ clk_cfg.param.payload_address_msw = 0x00;
+ clk_cfg.param.mem_map_handle = 0x00;
+ clk_cfg.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ clk_cfg.pdata.param_id = AFE_PARAM_ID_LPASS_CORE_SHARED_CLOCK_CONFIG;
+ clk_cfg.pdata.param_size = sizeof(clk_cfg.clk_cfg);
+ clk_cfg.clk_cfg.lpass_core_shared_clk_cfg_minor_version =
+ AFE_API_VERSION_LPASS_CORE_SHARED_CLK_CONFIG;
+ clk_cfg.clk_cfg.enable = enable;
+
+ pr_debug("%s: port id = %d, enable = %d\n",
+ __func__, q6audio_get_port_id(port_id), enable);
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port 0x%x ret %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ mutex_unlock(&this_afe.afe_cmd_lock);
+ return ret;
+}
+
+int q6afe_check_osr_clk_freq(u32 freq)
+{
+ int ret = 0;
+
+ switch (freq) {
+ case Q6AFE_LPASS_OSR_CLK_12_P288_MHZ:
+ case Q6AFE_LPASS_OSR_CLK_8_P192_MHZ:
+ case Q6AFE_LPASS_OSR_CLK_6_P144_MHZ:
+ case Q6AFE_LPASS_OSR_CLK_4_P096_MHZ:
+ case Q6AFE_LPASS_OSR_CLK_3_P072_MHZ:
+ case Q6AFE_LPASS_OSR_CLK_2_P048_MHZ:
+ case Q6AFE_LPASS_OSR_CLK_1_P536_MHZ:
+ case Q6AFE_LPASS_OSR_CLK_1_P024_MHZ:
+ case Q6AFE_LPASS_OSR_CLK_768_kHZ:
+ case Q6AFE_LPASS_OSR_CLK_512_kHZ:
+ break;
+ default:
+ pr_err("%s: deafault freq 0x%x\n",
+ __func__, freq);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+int afe_get_sp_th_vi_ftm_data(struct afe_sp_th_vi_get_param *th_vi)
+{
+ int ret = -EINVAL;
+ int index = 0, port = SLIMBUS_4_TX;
+
+ if (!th_vi) {
+ pr_err("%s: Invalid params\n", __func__);
+ goto done;
+ }
+ if (this_afe.vi_tx_port != -1)
+ port = this_afe.vi_tx_port;
+
+ ret = q6audio_validate_port(port);
+ if (ret < 0) {
+ pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret);
+ goto done;
+ }
+ index = q6audio_get_port_index(port);
+ if (index < 0) {
+ pr_err("%s: invalid port 0x%x, index %d\n",
+ __func__, port, index);
+ ret = -EINVAL;
+ goto done;
+ }
+ th_vi->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ th_vi->hdr.pkt_size = sizeof(*th_vi);
+ th_vi->hdr.src_port = 0;
+ th_vi->hdr.dest_port = 0;
+ th_vi->hdr.token = index;
+ th_vi->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2;
+ th_vi->get_param.mem_map_handle = 0;
+ th_vi->get_param.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
+ th_vi->get_param.param_id = AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS;
+ th_vi->get_param.payload_address_lsw = 0;
+ th_vi->get_param.payload_address_msw = 0;
+ th_vi->get_param.payload_size = sizeof(*th_vi)
+ - sizeof(th_vi->get_param) - sizeof(th_vi->hdr);
+ th_vi->get_param.port_id = q6audio_get_port_id(port);
+ th_vi->pdata.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
+ th_vi->pdata.param_id = AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS;
+ th_vi->pdata.param_size = sizeof(th_vi->param);
+ atomic_set(&this_afe.status, 0);
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *)th_vi);
+ if (ret < 0) {
+ pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
+ __func__, port, th_vi->get_param.param_id, ret);
+ goto done;
+ }
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(atomic_read(&this_afe.status));
+ goto done;
+ }
+ memcpy(&th_vi->param, &this_afe.th_vi_resp.param,
+ sizeof(this_afe.th_vi_resp.param));
+ pr_debug("%s: DC resistance %d %d temp %d %d status %d %d\n",
+ __func__, th_vi->param.dc_res_q24[SP_V2_SPKR_1],
+ th_vi->param.dc_res_q24[SP_V2_SPKR_2],
+ th_vi->param.temp_q22[SP_V2_SPKR_1],
+ th_vi->param.temp_q22[SP_V2_SPKR_2],
+ th_vi->param.status[SP_V2_SPKR_1],
+ th_vi->param.status[SP_V2_SPKR_2]);
+ ret = 0;
+done:
+ return ret;
+}
+
+int afe_get_sp_ex_vi_ftm_data(struct afe_sp_ex_vi_get_param *ex_vi)
+{
+ int ret = -EINVAL;
+ int index = 0, port = SLIMBUS_4_TX;
+
+ if (!ex_vi) {
+ pr_err("%s: Invalid params\n", __func__);
+ goto done;
+ }
+ if (this_afe.vi_tx_port != -1)
+ port = this_afe.vi_tx_port;
+
+ ret = q6audio_validate_port(port);
+ if (ret < 0) {
+ pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret);
+ goto done;
+ }
+
+ index = q6audio_get_port_index(port);
+ if (index < 0) {
+ pr_err("%s: invalid index %d port 0x%x\n", __func__,
+ index, port);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ex_vi->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ ex_vi->hdr.pkt_size = sizeof(*ex_vi);
+ ex_vi->hdr.src_port = 0;
+ ex_vi->hdr.dest_port = 0;
+ ex_vi->hdr.token = index;
+ ex_vi->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2;
+ ex_vi->get_param.mem_map_handle = 0;
+ ex_vi->get_param.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI;
+ ex_vi->get_param.param_id = AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS;
+ ex_vi->get_param.payload_address_lsw = 0;
+ ex_vi->get_param.payload_address_msw = 0;
+ ex_vi->get_param.payload_size = sizeof(*ex_vi)
+ - sizeof(ex_vi->get_param) - sizeof(ex_vi->hdr);
+ ex_vi->get_param.port_id = q6audio_get_port_id(port);
+ ex_vi->pdata.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI;
+ ex_vi->pdata.param_id = AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS;
+ ex_vi->pdata.param_size = sizeof(ex_vi->param);
+ atomic_set(&this_afe.status, 0);
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *)ex_vi);
+ if (ret < 0) {
+ pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
+ __func__, port, ex_vi->get_param.param_id, ret);
+ goto done;
+ }
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(atomic_read(&this_afe.status));
+ goto done;
+ }
+ memcpy(&ex_vi->param, &this_afe.ex_vi_resp.param,
+ sizeof(this_afe.ex_vi_resp.param));
+ pr_debug("%s: freq %d %d resistance %d %d qfactor %d %d state %d %d\n",
+ __func__, ex_vi->param.freq_q20[SP_V2_SPKR_1],
+ ex_vi->param.freq_q20[SP_V2_SPKR_2],
+ ex_vi->param.resis_q24[SP_V2_SPKR_1],
+ ex_vi->param.resis_q24[SP_V2_SPKR_2],
+ ex_vi->param.qmct_q24[SP_V2_SPKR_1],
+ ex_vi->param.qmct_q24[SP_V2_SPKR_2],
+ ex_vi->param.status[SP_V2_SPKR_1],
+ ex_vi->param.status[SP_V2_SPKR_2]);
+ ret = 0;
+done:
+ return ret;
+}
+
+int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp)
+{
+ int ret = -EINVAL;
+ int index = 0, port = SLIMBUS_4_TX;
+
+ if (!calib_resp) {
+ pr_err("%s: Invalid params\n", __func__);
+ goto fail_cmd;
+ }
+ if (this_afe.vi_tx_port != -1)
+ port = this_afe.vi_tx_port;
+
+ ret = q6audio_validate_port(port);
+ if (ret < 0) {
+ pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(port);
+ if (index < 0 || index > AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ calib_resp->hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ calib_resp->hdr.pkt_size = sizeof(*calib_resp);
+ calib_resp->hdr.src_port = 0;
+ calib_resp->hdr.dest_port = 0;
+ calib_resp->hdr.token = index;
+ calib_resp->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2;
+ calib_resp->get_param.mem_map_handle = 0;
+ calib_resp->get_param.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC_V2;
+ calib_resp->get_param.param_id = AFE_PARAM_ID_CALIB_RES_CFG_V2;
+ calib_resp->get_param.payload_address_lsw = 0;
+ calib_resp->get_param.payload_address_msw = 0;
+ calib_resp->get_param.payload_size = sizeof(*calib_resp)
+ - sizeof(calib_resp->get_param) - sizeof(calib_resp->hdr);
+ calib_resp->get_param.port_id = q6audio_get_port_id(port);
+ calib_resp->pdata.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC_V2;
+ calib_resp->pdata.param_id = AFE_PARAM_ID_CALIB_RES_CFG_V2;
+ calib_resp->pdata.param_size = sizeof(calib_resp->res_cfg);
+ atomic_set(&this_afe.status, 0);
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *)calib_resp);
+ if (ret < 0) {
+ pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
+ __func__, port, calib_resp->get_param.param_id, ret);
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto fail_cmd;
+ }
+ memcpy(&calib_resp->res_cfg, &this_afe.calib_data.res_cfg,
+ sizeof(this_afe.calib_data.res_cfg));
+ pr_info("%s: state %s resistance %d %d\n", __func__,
+ fbsp_state[calib_resp->res_cfg.th_vi_ca_state],
+ calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_1],
+ calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_2]);
+ ret = 0;
+fail_cmd:
+ return ret;
+}
+
+int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
+ int l_ch, int r_ch, u32 enable)
+{
+ int ret = -EINVAL;
+ union afe_spkr_prot_config prot_config;
+ int index = 0;
+
+ if (!enable) {
+ pr_debug("%s: Disable Feedback tx path", __func__);
+ this_afe.vi_tx_port = -1;
+ this_afe.vi_rx_port = -1;
+ return 0;
+ }
+
+ if ((q6audio_validate_port(src_port) < 0) ||
+ (q6audio_validate_port(dst_port) < 0)) {
+ pr_err("%s: invalid ports src 0x%x dst 0x%x",
+ __func__, src_port, dst_port);
+ goto fail_cmd;
+ }
+ if (!l_ch && !r_ch) {
+ pr_err("%s: error ch values zero\n", __func__);
+ goto fail_cmd;
+ }
+ pr_debug("%s: src_port 0x%x dst_port 0x%x l_ch %d r_ch %d\n",
+ __func__, src_port, dst_port, l_ch, r_ch);
+ memset(&prot_config, 0, sizeof(prot_config));
+ prot_config.feedback_path_cfg.dst_portid =
+ q6audio_get_port_id(dst_port);
+ if (l_ch) {
+ prot_config.feedback_path_cfg.chan_info[index++] = 1;
+ prot_config.feedback_path_cfg.chan_info[index++] = 2;
+ }
+ if (r_ch) {
+ prot_config.feedback_path_cfg.chan_info[index++] = 3;
+ prot_config.feedback_path_cfg.chan_info[index++] = 4;
+ }
+ prot_config.feedback_path_cfg.num_channels = index;
+ pr_debug("%s no of channels: %d\n", __func__, index);
+ prot_config.feedback_path_cfg.minor_version = 1;
+ ret = afe_spk_prot_prepare(src_port, dst_port,
+ AFE_PARAM_ID_FEEDBACK_PATH_CFG, &prot_config);
+fail_cmd:
+ return ret;
+}
+
+static int get_cal_type_index(int32_t cal_type)
+{
+ int ret = -EINVAL;
+
+ switch (cal_type) {
+ case AFE_COMMON_RX_CAL_TYPE:
+ ret = AFE_COMMON_RX_CAL;
+ break;
+ case AFE_COMMON_TX_CAL_TYPE:
+ ret = AFE_COMMON_TX_CAL;
+ break;
+ case AFE_AANC_CAL_TYPE:
+ ret = AFE_AANC_CAL;
+ break;
+ case AFE_HW_DELAY_CAL_TYPE:
+ ret = AFE_HW_DELAY_CAL;
+ break;
+ case AFE_FB_SPKR_PROT_CAL_TYPE:
+ ret = AFE_FB_SPKR_PROT_CAL;
+ break;
+ case AFE_SIDETONE_CAL_TYPE:
+ ret = AFE_SIDETONE_CAL;
+ break;
+ case AFE_TOPOLOGY_CAL_TYPE:
+ ret = AFE_TOPOLOGY_CAL;
+ break;
+ case AFE_CUST_TOPOLOGY_CAL_TYPE:
+ ret = AFE_CUST_TOPOLOGY_CAL;
+ break;
+ default:
+ pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
+ }
+ return ret;
+}
+
+int afe_alloc_cal(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ cal_index = get_cal_type_index(cal_type);
+ pr_debug("%s: cal_type = %d cal_index = %d\n",
+ __func__, cal_type, cal_index);
+
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_alloc_cal(data_size, data,
+ this_afe.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int afe_dealloc_cal(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_dealloc_cal(data_size, data,
+ this_afe.cal_data[cal_index]);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int afe_set_cal(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_set_cal(data_size, data,
+ this_afe.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (cal_index == AFE_CUST_TOPOLOGY_CAL) {
+ mutex_lock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
+ this_afe.set_custom_topology = 1;
+ pr_debug("%s:[AFE_CUSTOM_TOPOLOGY] ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ mutex_unlock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
+ }
+
+done:
+ return ret;
+}
+
+static struct cal_block_data *afe_find_hw_delay_by_path(
+ struct cal_type_data *cal_type, int path)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+
+ pr_debug("%s:\n", __func__);
+
+ list_for_each_safe(ptr, next,
+ &cal_type->cal_blocks) {
+
+ cal_block = list_entry(ptr,
+ struct cal_block_data, list);
+
+ if (((struct audio_cal_info_hw_delay *)cal_block->cal_info)
+ ->path == path) {
+ return cal_block;
+ }
+ }
+ return NULL;
+}
+
+static int afe_get_cal_hw_delay(int32_t path,
+ struct audio_cal_hw_delay_entry *entry)
+{
+ int ret = 0;
+ int i;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_hw_delay_data *hw_delay_info = NULL;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.cal_data[AFE_HW_DELAY_CAL] == NULL) {
+ pr_err("%s: AFE_HW_DELAY_CAL not initialized\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (entry == NULL) {
+ pr_err("%s: entry is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((path >= MAX_PATH_TYPE) || (path < 0)) {
+ pr_err("%s: bad path: %d\n",
+ __func__, path);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&this_afe.cal_data[AFE_HW_DELAY_CAL]->lock);
+ cal_block = afe_find_hw_delay_by_path(
+ this_afe.cal_data[AFE_HW_DELAY_CAL], path);
+ if (cal_block == NULL)
+ goto unlock;
+
+ hw_delay_info = &((struct audio_cal_info_hw_delay *)
+ cal_block->cal_info)->data;
+ if (hw_delay_info->num_entries > MAX_HW_DELAY_ENTRIES) {
+ pr_err("%s: invalid num entries: %d\n",
+ __func__, hw_delay_info->num_entries);
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ for (i = 0; i < hw_delay_info->num_entries; i++) {
+ if (hw_delay_info->entry[i].sample_rate ==
+ entry->sample_rate) {
+ entry->delay_usec = hw_delay_info->entry[i].delay_usec;
+ break;
+ }
+ }
+ if (i == hw_delay_info->num_entries) {
+ pr_err("%s: Unable to find delay for sample rate %d\n",
+ __func__, entry->sample_rate);
+ ret = -EFAULT;
+ goto unlock;
+ }
+ pr_debug("%s: Path = %d samplerate = %u usec = %u status %d\n",
+ __func__, path, entry->sample_rate, entry->delay_usec, ret);
+unlock:
+ mutex_unlock(&this_afe.cal_data[AFE_HW_DELAY_CAL]->lock);
+done:
+ return ret;
+}
+
+static int afe_set_cal_sp_th_vi_ftm_cfg(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int ret = 0;
+ struct audio_cal_type_sp_th_vi_ftm_cfg *cal_data = data;
+
+ if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
+ cal_data == NULL ||
+ data_size != sizeof(*cal_data))
+ goto done;
+
+ pr_debug("%s: cal_type = %d\n", __func__, cal_type);
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+ memcpy(&this_afe.th_ftm_cfg, &cal_data->cal_info,
+ sizeof(this_afe.th_ftm_cfg));
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+done:
+ return ret;
+}
+
+static int afe_set_cal_sp_ex_vi_ftm_cfg(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int ret = 0;
+ struct audio_cal_type_sp_ex_vi_ftm_cfg *cal_data = data;
+
+ if (this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL] == NULL ||
+ cal_data == NULL ||
+ data_size != sizeof(*cal_data))
+ goto done;
+
+ pr_debug("%s: cal_type = %d\n", __func__, cal_type);
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
+ memcpy(&this_afe.ex_ftm_cfg, &cal_data->cal_info,
+ sizeof(this_afe.ex_ftm_cfg));
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
+done:
+ return ret;
+}
+
+static int afe_set_cal_fb_spkr_prot(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int ret = 0;
+ struct audio_cal_type_fb_spk_prot_cfg *cal_data = data;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.cal_data[AFE_FB_SPKR_PROT_CAL] == NULL)
+ goto done;
+ if (cal_data == NULL)
+ goto done;
+ if (data_size != sizeof(*cal_data))
+ goto done;
+
+ if (cal_data->cal_info.mode == MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS)
+ __pm_wakeup_event(&wl.ws, jiffies_to_msecs(WAKELOCK_TIMEOUT));
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
+ memcpy(&this_afe.prot_cfg, &cal_data->cal_info,
+ sizeof(this_afe.prot_cfg));
+ this_afe.th_ftm_cfg.mode = this_afe.prot_cfg.mode;
+ this_afe.ex_ftm_cfg.mode = this_afe.prot_cfg.mode;
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
+done:
+ return ret;
+}
+
+static int afe_get_cal_sp_th_vi_ftm_param(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int i, ret = 0;
+ struct audio_cal_type_sp_th_vi_param *cal_data = data;
+ struct afe_sp_th_vi_get_param th_vi;
+
+ pr_debug("%s: cal_type = %d\n", __func__, cal_type);
+ if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
+ cal_data == NULL ||
+ data_size != sizeof(*cal_data))
+ goto done;
+
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+ for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
+ cal_data->cal_info.status[i] = -EINVAL;
+ cal_data->cal_info.r_dc_q24[i] = -1;
+ cal_data->cal_info.temp_q22[i] = -1;
+ }
+ if (!afe_get_sp_th_vi_ftm_data(&th_vi)) {
+ for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
+ pr_debug("%s: ftm param status = %d\n",
+ __func__, th_vi.param.status[i]);
+ if (th_vi.param.status[i] == FBSP_IN_PROGRESS) {
+ cal_data->cal_info.status[i] = -EAGAIN;
+ } else if (th_vi.param.status[i] == FBSP_SUCCESS) {
+ cal_data->cal_info.status[i] = 0;
+ cal_data->cal_info.r_dc_q24[i] =
+ th_vi.param.dc_res_q24[i];
+ cal_data->cal_info.temp_q22[i] =
+ th_vi.param.temp_q22[i];
+ }
+ }
+ }
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+done:
+ return ret;
+}
+
+static int afe_get_cal_sp_ex_vi_ftm_param(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int i, ret = 0;
+ struct audio_cal_type_sp_ex_vi_param *cal_data = data;
+ struct afe_sp_ex_vi_get_param ex_vi;
+
+ pr_debug("%s: cal_type = %d\n", __func__, cal_type);
+ if (this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL] == NULL ||
+ cal_data == NULL ||
+ data_size != sizeof(*cal_data))
+ goto done;
+
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
+ for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
+ cal_data->cal_info.status[i] = -EINVAL;
+ cal_data->cal_info.freq_q20[i] = -1;
+ cal_data->cal_info.resis_q24[i] = -1;
+ cal_data->cal_info.qmct_q24[i] = -1;
+ }
+ if (!afe_get_sp_ex_vi_ftm_data(&ex_vi)) {
+ for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
+ pr_debug("%s: ftm param status = %d\n",
+ __func__, ex_vi.param.status[i]);
+ if (ex_vi.param.status[i] == FBSP_IN_PROGRESS) {
+ cal_data->cal_info.status[i] = -EAGAIN;
+ } else if (ex_vi.param.status[i] == FBSP_SUCCESS) {
+ cal_data->cal_info.status[i] = 0;
+ cal_data->cal_info.freq_q20[i] =
+ ex_vi.param.freq_q20[i];
+ cal_data->cal_info.resis_q24[i] =
+ ex_vi.param.resis_q24[i];
+ cal_data->cal_info.qmct_q24[i] =
+ ex_vi.param.qmct_q24[i];
+ }
+ }
+ }
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
+done:
+ return ret;
+}
+
+static int afe_get_cal_fb_spkr_prot(int32_t cal_type, size_t data_size,
+ void *data)
+{
+ int ret = 0;
+ struct audio_cal_type_fb_spk_prot_status *cal_data = data;
+ struct afe_spkr_prot_get_vi_calib calib_resp;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.cal_data[AFE_FB_SPKR_PROT_CAL] == NULL)
+ goto done;
+ if (cal_data == NULL)
+ goto done;
+ if (data_size != sizeof(*cal_data))
+ goto done;
+
+ mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
+ if (this_afe.prot_cfg.mode == MSM_SPKR_PROT_CALIBRATED) {
+ cal_data->cal_info.r0[SP_V2_SPKR_1] =
+ this_afe.prot_cfg.r0[SP_V2_SPKR_1];
+ cal_data->cal_info.r0[SP_V2_SPKR_2] =
+ this_afe.prot_cfg.r0[SP_V2_SPKR_2];
+ cal_data->cal_info.status = 0;
+ } else if (this_afe.prot_cfg.mode ==
+ MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS) {
+ /*Call AFE to query the status*/
+ cal_data->cal_info.status = -EINVAL;
+ cal_data->cal_info.r0[SP_V2_SPKR_1] = -1;
+ cal_data->cal_info.r0[SP_V2_SPKR_2] = -1;
+ if (!afe_spk_prot_get_calib_data(&calib_resp)) {
+ if (calib_resp.res_cfg.th_vi_ca_state ==
+ FBSP_IN_PROGRESS)
+ cal_data->cal_info.status = -EAGAIN;
+ else if (calib_resp.res_cfg.th_vi_ca_state ==
+ FBSP_SUCCESS) {
+ cal_data->cal_info.status = 0;
+ cal_data->cal_info.r0[SP_V2_SPKR_1] =
+ calib_resp.res_cfg.r0_cali_q24[SP_V2_SPKR_1];
+ cal_data->cal_info.r0[SP_V2_SPKR_2] =
+ calib_resp.res_cfg.r0_cali_q24[SP_V2_SPKR_2];
+ }
+ }
+ if (!cal_data->cal_info.status) {
+ this_afe.prot_cfg.mode =
+ MSM_SPKR_PROT_CALIBRATED;
+ this_afe.prot_cfg.r0[SP_V2_SPKR_1] =
+ cal_data->cal_info.r0[SP_V2_SPKR_1];
+ this_afe.prot_cfg.r0[SP_V2_SPKR_2] =
+ cal_data->cal_info.r0[SP_V2_SPKR_2];
+ }
+ } else {
+ /*Indicates calibration data is invalid*/
+ cal_data->cal_info.status = -EINVAL;
+ cal_data->cal_info.r0[SP_V2_SPKR_1] = -1;
+ cal_data->cal_info.r0[SP_V2_SPKR_2] = -1;
+ }
+ this_afe.th_ftm_cfg.mode = this_afe.prot_cfg.mode;
+ this_afe.ex_ftm_cfg.mode = this_afe.prot_cfg.mode;
+ mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
+ __pm_relax(&wl.ws);
+done:
+ return ret;
+}
+
+static int afe_map_cal_data(int32_t cal_type,
+ struct cal_block_data *cal_block)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+
+ atomic_set(&this_afe.mem_map_cal_index, cal_index);
+ ret = afe_cmd_memory_map(cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+ atomic_set(&this_afe.mem_map_cal_index, -1);
+ if (ret < 0) {
+ pr_err("%s: mmap did not work! size = %zd ret %d\n",
+ __func__,
+ cal_block->map_data.map_size, ret);
+ pr_debug("%s: mmap did not work! addr = 0x%pK, size = %zd\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+ goto done;
+ }
+ cal_block->map_data.q6map_handle = atomic_read(&this_afe.
+ mem_map_cal_handles[cal_index]);
+done:
+ return ret;
+}
+
+static int afe_unmap_cal_data(int32_t cal_type,
+ struct cal_block_data *cal_block)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block == NULL) {
+ pr_err("%s: Cal block is NULL!\n",
+ __func__);
+ goto done;
+ }
+
+ if (cal_block->map_data.q6map_handle == 0) {
+ pr_err("%s: Map handle is NULL, nothing to unmap\n",
+ __func__);
+ goto done;
+ }
+
+ atomic_set(&this_afe.mem_map_cal_handles[cal_index],
+ cal_block->map_data.q6map_handle);
+ atomic_set(&this_afe.mem_map_cal_index, cal_index);
+ ret = afe_cmd_memory_unmap_nowait(
+ cal_block->map_data.q6map_handle);
+ atomic_set(&this_afe.mem_map_cal_index, -1);
+ if (ret < 0) {
+ pr_err("%s: unmap did not work! cal_type %i ret %d\n",
+ __func__, cal_index, ret);
+ }
+ cal_block->map_data.q6map_handle = 0;
+done:
+ return ret;
+}
+
+static void afe_delete_cal_data(void)
+{
+ pr_debug("%s:\n", __func__);
+
+ cal_utils_destroy_cal_types(MAX_AFE_CAL_TYPES, this_afe.cal_data);
+}
+
+static int afe_init_cal_data(void)
+{
+ int ret = 0;
+ struct cal_type_info cal_type_info[] = {
+ {{AFE_COMMON_RX_CAL_TYPE,
+ {afe_alloc_cal, afe_dealloc_cal, NULL,
+ afe_set_cal, NULL, NULL} },
+ {afe_map_cal_data, afe_unmap_cal_data,
+ cal_utils_match_buf_num} },
+
+ {{AFE_COMMON_TX_CAL_TYPE,
+ {afe_alloc_cal, afe_dealloc_cal, NULL,
+ afe_set_cal, NULL, NULL} },
+ {afe_map_cal_data, afe_unmap_cal_data,
+ cal_utils_match_buf_num} },
+
+ {{AFE_AANC_CAL_TYPE,
+ {afe_alloc_cal, afe_dealloc_cal, NULL,
+ afe_set_cal, NULL, NULL} },
+ {afe_map_cal_data, afe_unmap_cal_data,
+ cal_utils_match_buf_num} },
+
+ {{AFE_FB_SPKR_PROT_CAL_TYPE,
+ {NULL, NULL, NULL, afe_set_cal_fb_spkr_prot,
+ afe_get_cal_fb_spkr_prot, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{AFE_HW_DELAY_CAL_TYPE,
+ {NULL, NULL, NULL,
+ afe_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{AFE_SIDETONE_CAL_TYPE,
+ {NULL, NULL, NULL,
+ afe_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{AFE_TOPOLOGY_CAL_TYPE,
+ {NULL, NULL, NULL,
+ afe_set_cal, NULL, NULL} },
+ {NULL, NULL,
+ cal_utils_match_buf_num} },
+
+ {{AFE_CUST_TOPOLOGY_CAL_TYPE,
+ {afe_alloc_cal, afe_dealloc_cal, NULL,
+ afe_set_cal, NULL, NULL} },
+ {afe_map_cal_data, afe_unmap_cal_data,
+ cal_utils_match_buf_num} },
+
+ {{AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE,
+ {NULL, NULL, NULL, afe_set_cal_sp_th_vi_ftm_cfg,
+ afe_get_cal_sp_th_vi_ftm_param, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE,
+ {NULL, NULL, NULL, afe_set_cal_sp_ex_vi_ftm_cfg,
+ afe_get_cal_sp_ex_vi_ftm_param, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+ };
+ pr_debug("%s:\n", __func__);
+
+ ret = cal_utils_create_cal_types(MAX_AFE_CAL_TYPES, this_afe.cal_data,
+ cal_type_info);
+ if (ret < 0) {
+ pr_err("%s: could not create cal type! %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return ret;
+err:
+ afe_delete_cal_data();
+ return ret;
+}
+
+int afe_map_rtac_block(struct rtac_cal_block_data *cal_block)
+{
+ int result = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("%s: cal_block is NULL!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->cal_data.paddr == 0) {
+ pr_debug("%s: No address to map!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->map_data.map_size == 0) {
+ pr_debug("%s: map size is 0!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ result = afe_cmd_memory_map(cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+ if (result < 0) {
+ pr_err("%s: afe_cmd_memory_map failed for addr = 0x%pK, size = %d, err %d\n",
+ __func__, &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size, result);
+ return result;
+ }
+ cal_block->map_data.map_handle = this_afe.mmap_handle;
+
+done:
+ return result;
+}
+
+int afe_unmap_rtac_block(uint32_t *mem_map_handle)
+{
+ int result = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (mem_map_handle == NULL) {
+ pr_err("%s: Map handle is NULL, nothing to unmap\n",
+ __func__);
+ goto done;
+ }
+
+ if (*mem_map_handle == 0) {
+ pr_debug("%s: Map handle is 0, nothing to unmap\n",
+ __func__);
+ goto done;
+ }
+
+ result = afe_cmd_memory_unmap(*mem_map_handle);
+ if (result) {
+ pr_err("%s: AFE memory unmap failed %d, handle 0x%x\n",
+ __func__, result, *mem_map_handle);
+ goto done;
+ } else {
+ *mem_map_handle = 0;
+ }
+
+done:
+ return result;
+}
+
+static int __init afe_init(void)
+{
+ int i = 0, ret;
+
+ atomic_set(&this_afe.state, 0);
+ atomic_set(&this_afe.status, 0);
+ atomic_set(&this_afe.mem_map_cal_index, -1);
+ this_afe.apr = NULL;
+ this_afe.dtmf_gen_rx_portid = -1;
+ this_afe.mmap_handle = 0;
+ this_afe.vi_tx_port = -1;
+ this_afe.vi_rx_port = -1;
+ this_afe.prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
+ this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
+ this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
+ mutex_init(&this_afe.afe_cmd_lock);
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT;
+ init_waitqueue_head(&this_afe.wait[i]);
+ }
+ wakeup_source_init(&wl.ws, "spkr-prot");
+ ret = afe_init_cal_data();
+ if (ret)
+ pr_err("%s: could not init cal data! %d\n", __func__, ret);
+
+ config_debug_fs_init();
+ return 0;
+}
+
+static void __exit afe_exit(void)
+{
+ afe_delete_cal_data();
+
+ config_debug_fs_exit();
+ mutex_destroy(&this_afe.afe_cmd_lock);
+ wakeup_source_trash(&wl.ws);
+}
+
+device_initcall(afe_init);
+__exitcall(afe_exit);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
new file mode 100644
index 0000000..779bdd5
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -0,0 +1,8578 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+
+#include <linux/debugfs.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/mm.h>
+
+#include <asm/ioctls.h>
+
+#include <linux/memory.h>
+
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/q6audio-v2.h>
+#include <sound/audio_cal_utils.h>
+#include <sound/msm-dts-eagle.h>
+#include <sound/adsp_err.h>
+
+#define TRUE 0x01
+#define FALSE 0x00
+#define SESSION_MAX 8
+
+enum {
+ ASM_TOPOLOGY_CAL = 0,
+ ASM_CUSTOM_TOP_CAL,
+ ASM_AUDSTRM_CAL,
+ ASM_RTAC_APR_CAL,
+ ASM_MAX_CAL_TYPES
+};
+
+union asm_token_struct {
+ struct {
+ u8 stream_id;
+ u8 session_id;
+ u8 buf_index;
+ u8 flags;
+ } _token;
+ u32 token;
+} __packed;
+
+
+enum {
+ ASM_DIRECTION_OFFSET,
+ ASM_CMD_NO_WAIT_OFFSET,
+ /*
+ * Offset is limited to 7 because flags is stored in u8
+ * field in asm_token_structure defined above. The offset
+ * starts from 0.
+ */
+ ASM_MAX_OFFSET = 7,
+};
+
+enum {
+ WAIT_CMD,
+ NO_WAIT_CMD
+};
+
+#define ASM_SET_BIT(n, x) (n |= 1 << x)
+#define ASM_TEST_BIT(n, x) ((n >> x) & 1)
+
+/* TODO, combine them together */
+static DEFINE_MUTEX(session_lock);
+struct asm_mmap {
+ atomic_t ref_cnt;
+ void *apr;
+};
+
+static struct asm_mmap this_mmap;
+/* session id: 0 reserved */
+static struct audio_client *session[ASM_ACTIVE_STREAMS_ALLOWED + 1];
+
+struct asm_buffer_node {
+ struct list_head list;
+ phys_addr_t buf_phys_addr;
+ uint32_t mmap_hdl;
+};
+static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv);
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg);
+static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
+ struct apr_hdr *hdr,
+ uint32_t pkt_size);
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg);
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+ uint32_t bufsz, uint32_t bufcnt,
+ bool is_contiguous);
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir);
+static void q6asm_reset_buf_state(struct audio_client *ac);
+
+static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
+ bool use_back_flavor);
+void *q6asm_mmap_apr_reg(void);
+
+static int q6asm_is_valid_session(struct apr_client_data *data, void *priv);
+static int q6asm_get_asm_topology_cal(void);
+static int q6asm_get_asm_app_type_cal(void);
+
+/* for ASM custom topology */
+static struct cal_type_data *cal_data[ASM_MAX_CAL_TYPES];
+static struct audio_buffer common_buf[2];
+static struct audio_client common_client;
+static int set_custom_topology;
+static int topology_map_handle;
+
+struct generic_get_data_ {
+ int valid;
+ int is_inband;
+ int size_in_ints;
+ int ints[];
+};
+static struct generic_get_data_ *generic_get_data;
+
+#ifdef CONFIG_DEBUG_FS
+#define OUT_BUFFER_SIZE 56
+#define IN_BUFFER_SIZE 24
+
+static struct timeval out_cold_tv;
+static struct timeval out_warm_tv;
+static struct timeval out_cont_tv;
+static struct timeval in_cont_tv;
+static long out_enable_flag;
+static long in_enable_flag;
+static struct dentry *out_dentry;
+static struct dentry *in_dentry;
+static int in_cont_index;
+/*This var is used to keep track of first write done for cold output latency */
+static int out_cold_index;
+static char *out_buffer;
+static char *in_buffer;
+
+static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token,
+ int flag, int flag_offset)
+{
+ if (flag)
+ ASM_SET_BIT(asm_token->_token.flags, flag_offset);
+}
+
+static inline int q6asm_get_flag_from_token(union asm_token_struct *asm_token,
+ int flag_offset)
+{
+ return ASM_TEST_BIT(asm_token->_token.flags, flag_offset);
+}
+
+static inline void q6asm_update_token(u32 *token, u8 session_id, u8 stream_id,
+ u8 buf_index, u8 dir, u8 nowait_flag)
+{
+ union asm_token_struct asm_token;
+
+ asm_token.token = 0;
+ asm_token._token.session_id = session_id;
+ asm_token._token.stream_id = stream_id;
+ asm_token._token.buf_index = buf_index;
+ q6asm_set_flag_in_token(&asm_token, dir, ASM_DIRECTION_OFFSET);
+ q6asm_set_flag_in_token(&asm_token, nowait_flag,
+ ASM_CMD_NO_WAIT_OFFSET);
+ *token = asm_token.token;
+}
+
+static inline uint32_t q6asm_get_pcm_format_id(uint32_t media_format_block_ver)
+{
+ uint32_t pcm_format_id;
+
+ switch (media_format_block_ver) {
+ case PCM_MEDIA_FORMAT_V4:
+ pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4;
+ break;
+ case PCM_MEDIA_FORMAT_V3:
+ pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
+ break;
+ case PCM_MEDIA_FORMAT_V2:
+ default:
+ pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+ break;
+ }
+ return pcm_format_id;
+}
+
+/*
+ * q6asm_get_buf_index_from_token:
+ * Retrieve buffer index from token.
+ *
+ * @token: token value sent to ASM service on q6.
+ * Returns buffer index in the read/write commands.
+ */
+uint8_t q6asm_get_buf_index_from_token(uint32_t token)
+{
+ union asm_token_struct asm_token;
+
+ asm_token.token = token;
+ return asm_token._token.buf_index;
+}
+EXPORT_SYMBOL(q6asm_get_buf_index_from_token);
+
+/*
+ * q6asm_get_stream_id_from_token:
+ * Retrieve stream id from token.
+ *
+ * @token: token value sent to ASM service on q6.
+ * Returns stream id.
+ */
+uint8_t q6asm_get_stream_id_from_token(uint32_t token)
+{
+ union asm_token_struct asm_token;
+
+ asm_token.token = token;
+ return asm_token._token.stream_id;
+}
+EXPORT_SYMBOL(q6asm_get_stream_id_from_token);
+
+static int audio_output_latency_dbgfs_open(struct inode *inode,
+ struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+static ssize_t audio_output_latency_dbgfs_read(struct file *file,
+ char __user *buf, size_t count, loff_t *ppos)
+{
+ if (out_buffer == NULL) {
+ pr_err("%s: out_buffer is null\n", __func__);
+ return 0;
+ }
+ snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",
+ out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,
+ out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
+ return simple_read_from_buffer(buf, OUT_BUFFER_SIZE, ppos,
+ out_buffer, OUT_BUFFER_SIZE);
+}
+static ssize_t audio_output_latency_dbgfs_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ char *temp;
+
+ if (count > 2*sizeof(char)) {
+ pr_err("%s: err count is more %zd\n", __func__, count);
+ return -EINVAL;
+ }
+ temp = kmalloc(2*sizeof(char), GFP_KERNEL);
+
+ out_cold_index = 0;
+
+ if (temp) {
+ if (copy_from_user(temp, buf, 2*sizeof(char))) {
+ pr_err("%s: copy from user failed for size %zd\n",
+ __func__, 2*sizeof(char));
+ kfree(temp);
+ return -EFAULT;
+ }
+ if (!kstrtol(temp, 10, &out_enable_flag)) {
+ kfree(temp);
+ return count;
+ }
+ kfree(temp);
+ }
+ return -EINVAL;
+}
+static const struct file_operations audio_output_latency_debug_fops = {
+ .open = audio_output_latency_dbgfs_open,
+ .read = audio_output_latency_dbgfs_read,
+ .write = audio_output_latency_dbgfs_write
+};
+static int audio_input_latency_dbgfs_open(struct inode *inode,
+ struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+static ssize_t audio_input_latency_dbgfs_read(struct file *file,
+ char __user *buf, size_t count, loff_t *ppos)
+{
+ if (in_buffer == NULL) {
+ pr_err("%s: in_buffer is null\n", __func__);
+ return 0;
+ }
+ snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",
+ in_cont_tv.tv_sec, in_cont_tv.tv_usec);
+ return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
+ in_buffer, IN_BUFFER_SIZE);
+}
+static ssize_t audio_input_latency_dbgfs_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ char *temp;
+
+ if (count > 2*sizeof(char)) {
+ pr_err("%s: err count is more %zd\n", __func__, count);
+ return -EINVAL;
+ }
+ temp = kmalloc(2*sizeof(char), GFP_KERNEL);
+
+ if (temp) {
+ if (copy_from_user(temp, buf, 2*sizeof(char))) {
+ pr_err("%s: copy from user failed for size %zd\n",
+ __func__, 2*sizeof(char));
+ kfree(temp);
+ return -EFAULT;
+ }
+ if (!kstrtol(temp, 10, &in_enable_flag)) {
+ kfree(temp);
+ return count;
+ }
+ kfree(temp);
+ }
+ return -EINVAL;
+}
+static const struct file_operations audio_input_latency_debug_fops = {
+ .open = audio_input_latency_dbgfs_open,
+ .read = audio_input_latency_dbgfs_read,
+ .write = audio_input_latency_dbgfs_write
+};
+
+static void config_debug_fs_write_cb(void)
+{
+ if (out_enable_flag) {
+ /* For first Write done log the time and reset
+ * out_cold_index
+ */
+ if (out_cold_index != 1) {
+ do_gettimeofday(&out_cold_tv);
+ pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",
+ out_cold_tv.tv_sec,
+ out_cold_tv.tv_usec);
+ out_cold_index = 1;
+ }
+ pr_debug("%s: out_enable_flag %ld\n",
+ __func__, out_enable_flag);
+ }
+}
+static void config_debug_fs_read_cb(void)
+{
+ if (in_enable_flag) {
+ /* when in_cont_index == 7, DSP would be
+ * writing into the 8th 512 byte buffer and this
+ * timestamp is tapped here.Once done it then writes
+ * to 9th 512 byte buffer.These two buffers(8th, 9th)
+ * reach the test application in 5th iteration and that
+ * timestamp is tapped at user level. The difference
+ * of these two timestamps gives us the time between
+ * the time at which dsp started filling the sample
+ * required and when it reached the test application.
+ * Hence continuous input latency
+ */
+ if (in_cont_index == 7) {
+ do_gettimeofday(&in_cont_tv);
+ pr_info("%s: read buffer at %ld sec %ld microsec\n",
+ __func__,
+ in_cont_tv.tv_sec, in_cont_tv.tv_usec);
+ }
+ in_cont_index++;
+ }
+}
+
+static void config_debug_fs_reset_index(void)
+{
+ in_cont_index = 0;
+}
+
+static void config_debug_fs_run(void)
+{
+ if (out_enable_flag) {
+ do_gettimeofday(&out_cold_tv);
+ pr_debug("%s: COLD apr_send_pkt at %ld sec %ld microsec\n",
+ __func__, out_cold_tv.tv_sec, out_cold_tv.tv_usec);
+ }
+}
+
+static void config_debug_fs_write(struct audio_buffer *ab)
+{
+ if (out_enable_flag) {
+ char zero_pattern[2] = {0x00, 0x00};
+ /* If First two byte is non zero and last two byte
+ * is zero then it is warm output pattern
+ */
+ if ((strcmp(((char *)ab->data), zero_pattern)) &&
+ (!strcmp(((char *)ab->data + 2), zero_pattern))) {
+ do_gettimeofday(&out_warm_tv);
+ pr_debug("%s: WARM:apr_send_pkt at %ld sec %ld microsec\n",
+ __func__,
+ out_warm_tv.tv_sec,
+ out_warm_tv.tv_usec);
+ pr_debug("%s: Warm Pattern Matched\n", __func__);
+ }
+ /* If First two byte is zero and last two byte is
+ * non zero then it is cont output pattern
+ */
+ else if ((!strcmp(((char *)ab->data), zero_pattern))
+ && (strcmp(((char *)ab->data + 2), zero_pattern))) {
+ do_gettimeofday(&out_cont_tv);
+ pr_debug("%s: CONT:apr_send_pkt at %ld sec %ld microsec\n",
+ __func__,
+ out_cont_tv.tv_sec,
+ out_cont_tv.tv_usec);
+ pr_debug("%s: Cont Pattern Matched\n", __func__);
+ }
+ }
+}
+static void config_debug_fs_init(void)
+{
+ out_buffer = kzalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
+ if (out_buffer == NULL)
+ goto outbuf_fail;
+
+ in_buffer = kzalloc(IN_BUFFER_SIZE, GFP_KERNEL);
+ if (in_buffer == NULL)
+ goto inbuf_fail;
+
+ out_dentry = debugfs_create_file("audio_out_latency_measurement_node",
+ 0664,
+ NULL, NULL, &audio_output_latency_debug_fops);
+ if (IS_ERR(out_dentry)) {
+ pr_err("%s: debugfs_create_file failed\n", __func__);
+ goto file_fail;
+ }
+ in_dentry = debugfs_create_file("audio_in_latency_measurement_node",
+ 0664,
+ NULL, NULL, &audio_input_latency_debug_fops);
+ if (IS_ERR(in_dentry)) {
+ pr_err("%s: debugfs_create_file failed\n", __func__);
+ goto file_fail;
+ }
+ return;
+file_fail:
+ kfree(in_buffer);
+inbuf_fail:
+ kfree(out_buffer);
+outbuf_fail:
+ in_buffer = NULL;
+ out_buffer = NULL;
+}
+#else
+static void config_debug_fs_write(struct audio_buffer *ab)
+{
+}
+static void config_debug_fs_run(void)
+{
+}
+static void config_debug_fs_reset_index(void)
+{
+}
+static void config_debug_fs_read_cb(void)
+{
+}
+static void config_debug_fs_write_cb(void)
+{
+}
+static void config_debug_fs_init(void)
+{
+}
+#endif
+
+int q6asm_mmap_apr_dereg(void)
+{
+ int c;
+
+ c = atomic_sub_return(1, &this_mmap.ref_cnt);
+ if (c == 0) {
+ apr_deregister(this_mmap.apr);
+ common_client.mmap_apr = NULL;
+ pr_debug("%s: APR De-Register common port\n", __func__);
+ } else if (c < 0) {
+ pr_err("%s: APR Common Port Already Closed %d\n",
+ __func__, c);
+ atomic_set(&this_mmap.ref_cnt, 0);
+ }
+
+ return 0;
+}
+
+static int q6asm_session_alloc(struct audio_client *ac)
+{
+ int n;
+
+ for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
+ if (!session[n]) {
+ session[n] = ac;
+ return n;
+ }
+ }
+ pr_err("%s: session not available\n", __func__);
+ return -ENOMEM;
+}
+
+static bool q6asm_is_valid_audio_client(struct audio_client *ac)
+{
+ int n;
+
+ for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
+ if (session[n] == ac)
+ return 1;
+ }
+ return 0;
+}
+
+static void q6asm_session_free(struct audio_client *ac)
+{
+ pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
+ rtac_remove_popp_from_adm_devices(ac->session);
+ session[ac->session] = 0;
+ ac->session = 0;
+ ac->perf_mode = LEGACY_PCM_MODE;
+ ac->fptr_cache_ops = NULL;
+}
+
+static uint32_t q6asm_get_next_buf(struct audio_client *ac,
+ uint32_t curr_buf, uint32_t max_buf_cnt)
+{
+ dev_vdbg(ac->dev, "%s: curr_buf = %d, max_buf_cnt = %d\n",
+ __func__, curr_buf, max_buf_cnt);
+ curr_buf += 1;
+ return (curr_buf >= max_buf_cnt) ? 0 : curr_buf;
+}
+
+static int q6asm_map_cal_memory(int32_t cal_type,
+ struct cal_block_data *cal_block)
+{
+ int result = 0;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+
+ if (cal_block == NULL) {
+ pr_err("%s: cal_block is NULL!\n",
+ __func__);
+ goto done;
+ }
+
+ if (cal_block->cal_data.paddr == 0) {
+ pr_debug("%s: No address to map!\n",
+ __func__);
+ goto done;
+ }
+
+ common_client.mmap_apr = q6asm_mmap_apr_reg();
+ if (common_client.mmap_apr == NULL) {
+ pr_err("%s: q6asm_mmap_apr_reg failed\n",
+ __func__);
+ result = -EPERM;
+ goto done;
+ }
+ common_client.apr = common_client.mmap_apr;
+ if (cal_block->map_data.map_size == 0) {
+ pr_debug("%s: map size is 0!\n",
+ __func__);
+ goto done;
+ }
+
+ /* Use second asm buf to map memory */
+ if (common_client.port[IN].buf == NULL) {
+ pr_err("%s: common buf is NULL\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ common_client.port[IN].buf->phys = cal_block->cal_data.paddr;
+
+ result = q6asm_memory_map_regions(&common_client,
+ IN, cal_block->map_data.map_size, 1, 1);
+ if (result < 0) {
+ pr_err("%s: mmap did not work! size = %zd result %d\n",
+ __func__,
+ cal_block->map_data.map_size, result);
+ pr_debug("%s: mmap did not work! addr = 0x%pK, size = %zd\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+ goto done;
+ }
+
+ list_for_each_safe(ptr, next,
+ &common_client.port[IN].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == cal_block->cal_data.paddr) {
+ cal_block->map_data.q6map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+done:
+ return result;
+}
+
+static int remap_cal_data(int32_t cal_type, struct cal_block_data *cal_block)
+{
+ int ret = 0;
+
+ if (cal_block->map_data.ion_client == NULL) {
+ pr_err("%s: No ION allocation for cal type %d!\n",
+ __func__, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((cal_block->map_data.map_size > 0) &&
+ (cal_block->map_data.q6map_handle == 0)) {
+
+ ret = q6asm_map_cal_memory(cal_type, cal_block);
+ if (ret < 0) {
+ pr_err("%s: mmap did not work! size = %zd ret %d\n",
+ __func__, cal_block->map_data.map_size, ret);
+ goto done;
+ }
+ }
+done:
+ return ret;
+}
+
+static int q6asm_unmap_cal_memory(int32_t cal_type,
+ struct cal_block_data *cal_block)
+{
+ int result = 0;
+ int result2 = 0;
+
+ if (cal_block == NULL) {
+ pr_err("%s: cal_block is NULL!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->map_data.q6map_handle == 0) {
+ pr_debug("%s: No address to unmap!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (common_client.mmap_apr == NULL) {
+ common_client.mmap_apr = q6asm_mmap_apr_reg();
+ if (common_client.mmap_apr == NULL) {
+ pr_err("%s: q6asm_mmap_apr_reg failed\n",
+ __func__);
+ result = -EPERM;
+ goto done;
+ }
+ }
+
+ result2 = q6asm_memory_unmap_regions(&common_client, IN);
+ if (result2 < 0) {
+ pr_err("%s: unmap failed, err %d\n",
+ __func__, result2);
+ result = result2;
+ }
+
+ cal_block->map_data.q6map_handle = 0;
+done:
+ return result;
+}
+
+int q6asm_unmap_cal_data(int cal_type, struct cal_block_data *cal_block)
+{
+ int ret = 0;
+
+ if ((cal_block->map_data.map_size > 0) &&
+ (cal_block->map_data.q6map_handle != 0)) {
+
+ ret = q6asm_unmap_cal_memory(cal_type, cal_block);
+ if (ret < 0) {
+ pr_err("%s: unmap did not work! size = %zd ret %d\n",
+ __func__, cal_block->map_data.map_size, ret);
+ goto done;
+ }
+ }
+done:
+ return ret;
+}
+
+int send_asm_custom_topology(struct audio_client *ac)
+{
+ struct cal_block_data *cal_block = NULL;
+ struct cmd_set_topologies asm_top;
+ int result = 0;
+ int result1 = 0;
+
+ if (cal_data[ASM_CUSTOM_TOP_CAL] == NULL)
+ goto done;
+
+ mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
+ if (!set_custom_topology)
+ goto unlock;
+ set_custom_topology = 0;
+
+ cal_block = cal_utils_get_only_cal_block(cal_data[ASM_CUSTOM_TOP_CAL]);
+ if (cal_block == NULL)
+ goto unlock;
+
+ if (cal_block->cal_data.size == 0) {
+ pr_debug("%s: No cal to send!\n", __func__);
+ goto unlock;
+ }
+
+ pr_debug("%s: Sending cal_index %d\n", __func__, ASM_CUSTOM_TOP_CAL);
+
+ result = remap_cal_data(ASM_CUST_TOPOLOGY_CAL_TYPE, cal_block);
+ if (result) {
+ pr_err("%s: Remap_cal_data failed for cal %d!\n",
+ __func__, ASM_CUSTOM_TOP_CAL);
+ goto unlock;
+ }
+
+ q6asm_add_hdr_custom_topology(ac, &asm_top.hdr, sizeof(asm_top));
+ atomic_set(&ac->mem_state, -1);
+ asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
+ asm_top.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
+ asm_top.payload_addr_msw = msm_audio_populate_upper_32_bits(
+ cal_block->cal_data.paddr);
+ asm_top.mem_map_handle = cal_block->map_data.q6map_handle;
+ asm_top.payload_size = cal_block->cal_data.size;
+
+ pr_debug("%s: Sending ASM_CMD_ADD_TOPOLOGIES payload = %pK, size = %d, map handle = 0x%x\n",
+ __func__, &cal_block->cal_data.paddr,
+ asm_top.payload_size, asm_top.mem_map_handle);
+
+ result = apr_send_pkt(ac->apr, (uint32_t *) &asm_top);
+ if (result < 0) {
+ pr_err("%s: Set topologies failed result %d\n",
+ __func__, result);
+ pr_debug("%s: Set topologies failed payload = 0x%pK\n",
+ __func__, &cal_block->cal_data.paddr);
+ goto unmap;
+
+ }
+
+ result = wait_event_timeout(ac->mem_wait,
+ (atomic_read(&ac->mem_state) >= 0), 5*HZ);
+ if (!result) {
+ pr_err("%s: Set topologies failed timeout\n", __func__);
+ pr_debug("%s: Set topologies failed after timedout payload = 0x%pK\n",
+ __func__, &cal_block->cal_data.paddr);
+ result = -ETIMEDOUT;
+ goto unmap;
+ }
+ if (atomic_read(&ac->mem_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->mem_state)));
+ result = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->mem_state));
+ goto unmap;
+ }
+
+unmap:
+ result1 = q6asm_unmap_cal_memory(ASM_CUST_TOPOLOGY_CAL_TYPE,
+ cal_block);
+ if (result1 < 0) {
+ result = result1;
+ pr_debug("%s: unmap cal failed! %d\n", __func__, result);
+ }
+unlock:
+ mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
+done:
+ return result;
+}
+
+int q6asm_map_rtac_block(struct rtac_cal_block_data *cal_block)
+{
+ int result = 0;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+
+ pr_debug("%s:\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("%s: cal_block is NULL!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->cal_data.paddr == 0) {
+ pr_debug("%s: No address to map!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (common_client.mmap_apr == NULL) {
+ common_client.mmap_apr = q6asm_mmap_apr_reg();
+ if (common_client.mmap_apr == NULL) {
+ pr_err("%s: q6asm_mmap_apr_reg failed\n",
+ __func__);
+ result = -EPERM;
+ goto done;
+ }
+ }
+
+ if (cal_block->map_data.map_size == 0) {
+ pr_debug("%s: map size is 0!\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ /* Use second asm buf to map memory */
+ if (common_client.port[OUT].buf == NULL) {
+ pr_err("%s: common buf is NULL\n",
+ __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ common_client.port[OUT].buf->phys = cal_block->cal_data.paddr;
+
+ result = q6asm_memory_map_regions(&common_client,
+ OUT, cal_block->map_data.map_size, 1, 1);
+ if (result < 0) {
+ pr_err("%s: mmap did not work! size = %d result %d\n",
+ __func__,
+ cal_block->map_data.map_size, result);
+ pr_debug("%s: mmap did not work! addr = 0x%pK, size = %d\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+ goto done;
+ }
+
+ list_for_each_safe(ptr, next,
+ &common_client.port[OUT].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == cal_block->cal_data.paddr) {
+ cal_block->map_data.map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+done:
+ return result;
+}
+
+int q6asm_unmap_rtac_block(uint32_t *mem_map_handle)
+{
+ int result = 0;
+ int result2 = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (mem_map_handle == NULL) {
+ pr_debug("%s: Map handle is NULL, nothing to unmap\n",
+ __func__);
+ goto done;
+ }
+
+ if (*mem_map_handle == 0) {
+ pr_debug("%s: Map handle is 0, nothing to unmap\n",
+ __func__);
+ goto done;
+ }
+
+ if (common_client.mmap_apr == NULL) {
+ common_client.mmap_apr = q6asm_mmap_apr_reg();
+ if (common_client.mmap_apr == NULL) {
+ pr_err("%s: q6asm_mmap_apr_reg failed\n",
+ __func__);
+ result = -EPERM;
+ goto done;
+ }
+ }
+
+
+ result2 = q6asm_memory_unmap_regions(&common_client, OUT);
+ if (result2 < 0) {
+ pr_err("%s: unmap failed, err %d\n",
+ __func__, result2);
+ result = result2;
+ } else {
+ mem_map_handle = 0;
+ }
+
+ result2 = q6asm_mmap_apr_dereg();
+ if (result2 < 0) {
+ pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
+ __func__, result2);
+ result = result2;
+ }
+done:
+ return result;
+}
+
+int q6asm_audio_client_buf_free(unsigned int dir,
+ struct audio_client *ac)
+{
+ struct audio_port_data *port;
+ int cnt = 0;
+ int rc = 0;
+
+ pr_debug("%s: Session id %d\n", __func__, ac->session);
+ mutex_lock(&ac->cmd_lock);
+ if (ac->io_mode & SYNC_IO_MODE) {
+ port = &ac->port[dir];
+ if (!port->buf) {
+ pr_err("%s: buf NULL\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+ }
+ cnt = port->max_buf_cnt - 1;
+
+ if (cnt >= 0) {
+ rc = q6asm_memory_unmap_regions(ac, dir);
+ if (rc < 0)
+ pr_err("%s: Memory_unmap_regions failed %d\n",
+ __func__, rc);
+ }
+
+ while (cnt >= 0) {
+ if (port->buf[cnt].data) {
+ if (!rc || atomic_read(&ac->reset))
+ msm_audio_ion_free(
+ port->buf[cnt].client,
+ port->buf[cnt].handle);
+
+ port->buf[cnt].client = NULL;
+ port->buf[cnt].handle = NULL;
+ port->buf[cnt].data = NULL;
+ port->buf[cnt].phys = 0;
+ --(port->max_buf_cnt);
+ }
+ --cnt;
+ }
+ kfree(port->buf);
+ port->buf = NULL;
+ }
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+}
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+ struct audio_client *ac)
+{
+ struct audio_port_data *port;
+ int cnt = 0;
+ int rc = 0;
+
+ pr_debug("%s: Session id %d\n", __func__, ac->session);
+ mutex_lock(&ac->cmd_lock);
+ port = &ac->port[dir];
+ if (!port->buf) {
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+ }
+ cnt = port->max_buf_cnt - 1;
+
+ if (cnt >= 0) {
+ rc = q6asm_memory_unmap(ac, port->buf[0].phys, dir);
+ if (rc < 0)
+ pr_err("%s: Memory_unmap_regions failed %d\n",
+ __func__, rc);
+ }
+
+ if (port->buf[0].data) {
+ pr_debug("%s: data[%pK]phys[%pK][%pK] , client[%pK] handle[%pK]\n",
+ __func__,
+ port->buf[0].data,
+ &port->buf[0].phys,
+ &port->buf[0].phys,
+ port->buf[0].client,
+ port->buf[0].handle);
+ if (!rc || atomic_read(&ac->reset))
+ msm_audio_ion_free(port->buf[0].client,
+ port->buf[0].handle);
+ port->buf[0].client = NULL;
+ port->buf[0].handle = NULL;
+ }
+
+ while (cnt >= 0) {
+ port->buf[cnt].data = NULL;
+ port->buf[cnt].phys = 0;
+ cnt--;
+ }
+ port->max_buf_cnt = 0;
+ kfree(port->buf);
+ port->buf = NULL;
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+}
+
+void q6asm_audio_client_free(struct audio_client *ac)
+{
+ int loopcnt;
+ struct audio_port_data *port;
+
+ if (!ac) {
+ pr_err("%s: ac %pK\n", __func__, ac);
+ return;
+ }
+ if (!ac->session) {
+ pr_err("%s: ac session invalid\n", __func__);
+ return;
+ }
+
+ mutex_lock(&session_lock);
+
+ pr_debug("%s: Session id %d\n", __func__, ac->session);
+ if (ac->io_mode & SYNC_IO_MODE) {
+ for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+ port = &ac->port[loopcnt];
+ if (!port->buf)
+ continue;
+ pr_debug("%s: loopcnt = %d\n",
+ __func__, loopcnt);
+ q6asm_audio_client_buf_free(loopcnt, ac);
+ }
+ }
+
+ rtac_set_asm_handle(ac->session, NULL);
+ apr_deregister(ac->apr2);
+ apr_deregister(ac->apr);
+ q6asm_mmap_apr_dereg();
+ ac->apr2 = NULL;
+ ac->apr = NULL;
+ ac->mmap_apr = NULL;
+ q6asm_session_free(ac);
+
+ pr_debug("%s: APR De-Register\n", __func__);
+
+/*done:*/
+ kfree(ac);
+ ac = NULL;
+ mutex_unlock(&session_lock);
+}
+
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode1)
+{
+ uint32_t mode;
+ int ret = 0;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ ac->io_mode &= 0xFF00;
+ mode = (mode1 & 0xF);
+
+ pr_debug("%s: ac->mode after anding with FF00:0x%x,\n",
+ __func__, ac->io_mode);
+
+ if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
+ ac->io_mode |= mode1;
+ pr_debug("%s: Set Mode to 0x%x\n", __func__, ac->io_mode);
+ } else {
+ pr_err("%s: Not an valid IO Mode:%d\n", __func__, ac->io_mode);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+void *q6asm_mmap_apr_reg(void)
+{
+ if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
+ (this_mmap.apr == NULL)) {
+ this_mmap.apr = apr_register("ADSP", "ASM",
+ (apr_fn)q6asm_srvc_callback,
+ 0x0FFFFFFFF, &this_mmap);
+ if (this_mmap.apr == NULL) {
+ pr_debug("%s: Unable to register APR ASM common port\n",
+ __func__);
+ goto fail;
+ }
+ }
+ atomic_inc(&this_mmap.ref_cnt);
+
+ return this_mmap.apr;
+fail:
+ return NULL;
+}
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
+{
+ struct audio_client *ac;
+ int n;
+ int lcnt = 0;
+ int rc = 0;
+
+ ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
+ if (!ac)
+ return NULL;
+
+ mutex_lock(&session_lock);
+ n = q6asm_session_alloc(ac);
+ if (n <= 0) {
+ pr_err("%s: ASM Session alloc fail n=%d\n", __func__, n);
+ mutex_unlock(&session_lock);
+ goto fail_session;
+ }
+ ac->session = n;
+ ac->cb = cb;
+ ac->path_delay = UINT_MAX;
+ ac->priv = priv;
+ ac->io_mode = SYNC_IO_MODE;
+ ac->perf_mode = LEGACY_PCM_MODE;
+ ac->fptr_cache_ops = NULL;
+ /* DSP expects stream id from 1 */
+ ac->stream_id = 1;
+ ac->apr = apr_register("ADSP", "ASM",
+ (apr_fn)q6asm_callback,
+ ((ac->session) << 8 | 0x0001),
+ ac);
+
+ if (ac->apr == NULL) {
+ pr_err("%s: Registration with APR failed\n", __func__);
+ mutex_unlock(&session_lock);
+ goto fail_apr1;
+ }
+ ac->apr2 = apr_register("ADSP", "ASM",
+ (apr_fn)q6asm_callback,
+ ((ac->session) << 8 | 0x0002),
+ ac);
+
+ if (ac->apr2 == NULL) {
+ pr_err("%s: Registration with APR-2 failed\n", __func__);
+ mutex_unlock(&session_lock);
+ goto fail_apr2;
+ }
+
+ rtac_set_asm_handle(n, ac->apr);
+
+ pr_debug("%s: Registering the common port with APR\n", __func__);
+ ac->mmap_apr = q6asm_mmap_apr_reg();
+ if (ac->mmap_apr == NULL) {
+ mutex_unlock(&session_lock);
+ goto fail_mmap;
+ }
+
+ init_waitqueue_head(&ac->cmd_wait);
+ init_waitqueue_head(&ac->time_wait);
+ init_waitqueue_head(&ac->mem_wait);
+ atomic_set(&ac->time_flag, 1);
+ atomic_set(&ac->reset, 0);
+ INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
+ INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
+ pr_debug("%s: mem_map_handle list init'ed\n", __func__);
+ mutex_init(&ac->cmd_lock);
+ for (lcnt = 0; lcnt <= OUT; lcnt++) {
+ mutex_init(&ac->port[lcnt].lock);
+ spin_lock_init(&ac->port[lcnt].dsp_lock);
+ }
+ atomic_set(&ac->cmd_state, 0);
+ atomic_set(&ac->mem_state, 0);
+
+ rc = send_asm_custom_topology(ac);
+ if (rc < 0) {
+ mutex_unlock(&session_lock);
+ goto fail_mmap;
+ }
+
+ pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+ mutex_unlock(&session_lock);
+
+ return ac;
+fail_mmap:
+ apr_deregister(ac->apr2);
+fail_apr2:
+ apr_deregister(ac->apr);
+fail_apr1:
+ q6asm_session_free(ac);
+fail_session:
+ kfree(ac);
+ return NULL;
+}
+
+struct audio_client *q6asm_get_audio_client(int session_id)
+{
+ if (session_id == ASM_CONTROL_SESSION)
+ return &common_client;
+
+ if ((session_id <= 0) || (session_id > ASM_ACTIVE_STREAMS_ALLOWED)) {
+ pr_err("%s: invalid session: %d\n", __func__, session_id);
+ goto err;
+ }
+
+ if (!session[session_id]) {
+ pr_err("%s: session not active: %d\n", __func__, session_id);
+ goto err;
+ }
+ return session[session_id];
+err:
+ return NULL;
+}
+
+int q6asm_audio_client_buf_alloc(unsigned int dir,
+ struct audio_client *ac,
+ unsigned int bufsz,
+ uint32_t bufcnt)
+{
+ int cnt = 0;
+ int rc = 0;
+ struct audio_buffer *buf;
+ size_t len;
+
+ if (!(ac) || !(bufsz) || ((dir != IN) && (dir != OUT))) {
+ pr_err("%s: ac %pK bufsz %d dir %d\n", __func__, ac, bufsz,
+ dir);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session,
+ bufsz, bufcnt);
+
+ if (ac->session <= 0 || ac->session > 8) {
+ pr_err("%s: Session ID is invalid, session = %d\n", __func__,
+ ac->session);
+ goto fail;
+ }
+
+ if (ac->io_mode & SYNC_IO_MODE) {
+ if (ac->port[dir].buf) {
+ pr_debug("%s: buffer already allocated\n", __func__);
+ return 0;
+ }
+ mutex_lock(&ac->cmd_lock);
+ if (bufcnt > (U32_MAX/sizeof(struct audio_buffer))) {
+ pr_err("%s: Buffer size overflows", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+ buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+ GFP_KERNEL);
+
+ if (!buf) {
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ ac->port[dir].buf = buf;
+
+ while (cnt < bufcnt) {
+ if (bufsz > 0) {
+ if (!buf[cnt].data) {
+ rc = msm_audio_ion_alloc("asm_client",
+ &buf[cnt].client, &buf[cnt].handle,
+ bufsz,
+ (ion_phys_addr_t *)&buf[cnt].phys,
+ &len,
+ &buf[cnt].data);
+ if (rc) {
+ pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+ __func__, rc);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ buf[cnt].used = 1;
+ buf[cnt].size = bufsz;
+ buf[cnt].actual_size = bufsz;
+ pr_debug("%s: data[%pK]phys[%pK][%pK]\n",
+ __func__,
+ buf[cnt].data,
+ &buf[cnt].phys,
+ &buf[cnt].phys);
+ cnt++;
+ }
+ }
+ }
+ ac->port[dir].max_buf_cnt = cnt;
+
+ mutex_unlock(&ac->cmd_lock);
+ rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 0);
+ if (rc < 0) {
+ pr_err("%s: CMD Memory_map_regions failed %d for size %d\n",
+ __func__, rc, bufsz);
+ goto fail;
+ }
+ }
+ return 0;
+fail:
+ q6asm_audio_client_buf_free(dir, ac);
+ return -EINVAL;
+}
+
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
+ struct audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt)
+{
+ int cnt = 0;
+ int rc = 0;
+ struct audio_buffer *buf;
+ size_t len;
+ int bytes_to_alloc;
+
+ if (!(ac) || ((dir != IN) && (dir != OUT))) {
+ pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n",
+ __func__, ac->session,
+ bufsz, bufcnt);
+
+ if (ac->session <= 0 || ac->session > 8) {
+ pr_err("%s: Session ID is invalid, session = %d\n", __func__,
+ ac->session);
+ goto fail;
+ }
+
+ if (ac->port[dir].buf) {
+ pr_err("%s: buffer already allocated\n", __func__);
+ return 0;
+ }
+ mutex_lock(&ac->cmd_lock);
+ buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+ GFP_KERNEL);
+
+ if (!buf) {
+ pr_err("%s: buffer allocation failed\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ ac->port[dir].buf = buf;
+
+ /* check for integer overflow */
+ if ((bufcnt > 0) && ((INT_MAX / bufcnt) < bufsz)) {
+ pr_err("%s: integer overflow\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+ bytes_to_alloc = bufsz * bufcnt;
+
+ /* The size to allocate should be multiple of 4K bytes */
+ bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
+
+ rc = msm_audio_ion_alloc("asm_client", &buf[0].client, &buf[0].handle,
+ bytes_to_alloc,
+ (ion_phys_addr_t *)&buf[0].phys, &len,
+ &buf[0].data);
+ if (rc) {
+ pr_err("%s: Audio ION alloc is failed, rc = %d\n",
+ __func__, rc);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ buf[0].used = dir ^ 1;
+ buf[0].size = bufsz;
+ buf[0].actual_size = bufsz;
+ cnt = 1;
+ while (cnt < bufcnt) {
+ if (bufsz > 0) {
+ buf[cnt].data = buf[0].data + (cnt * bufsz);
+ buf[cnt].phys = buf[0].phys + (cnt * bufsz);
+ if (!buf[cnt].data) {
+ pr_err("%s: Buf alloc failed\n",
+ __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+ buf[cnt].used = dir ^ 1;
+ buf[cnt].size = bufsz;
+ buf[cnt].actual_size = bufsz;
+ pr_debug("%s: data[%pK]phys[%pK][%pK]\n",
+ __func__,
+ buf[cnt].data,
+ &buf[cnt].phys,
+ &buf[cnt].phys);
+ }
+ cnt++;
+ }
+ ac->port[dir].max_buf_cnt = cnt;
+ mutex_unlock(&ac->cmd_lock);
+ rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 1);
+ if (rc < 0) {
+ pr_err("%s: CMD Memory_map_regions failed %d for size %d\n",
+ __func__, rc, bufsz);
+ goto fail;
+ }
+ return 0;
+fail:
+ q6asm_audio_client_buf_free_contiguous(dir, ac);
+ return -EINVAL;
+}
+
+static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t dir = 0;
+ uint32_t i = IN;
+ uint32_t *payload;
+ unsigned long dsp_flags;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+ union asm_token_struct asm_token;
+
+ struct audio_client *ac = NULL;
+ struct audio_port_data *port;
+
+ if (!data) {
+ pr_err("%s: Invalid CB\n", __func__);
+ return 0;
+ }
+
+ payload = data->payload;
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
+ __func__,
+ data->reset_event,
+ data->reset_proc,
+ this_mmap.apr);
+ atomic_set(&this_mmap.ref_cnt, 0);
+ apr_reset(this_mmap.apr);
+ this_mmap.apr = NULL;
+ for (; i <= OUT; i++) {
+ list_for_each_safe(ptr, next,
+ &common_client.port[i].mem_map_handle) {
+ buf_node = list_entry(ptr,
+ struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr ==
+ common_client.port[i].buf->phys) {
+ list_del(&buf_node->list);
+ kfree(buf_node);
+ }
+ }
+ pr_debug("%s: Clearing custom topology\n", __func__);
+ }
+ this_mmap.apr = NULL;
+
+ cal_utils_clear_cal_block_q6maps(ASM_MAX_CAL_TYPES, cal_data);
+ common_client.mmap_apr = NULL;
+ mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
+ set_custom_topology = 1;
+ mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
+ topology_map_handle = 0;
+ rtac_clear_mapping(ASM_RTAC_CAL);
+ return 0;
+ }
+ asm_token.token = data->token;
+ ac = q6asm_get_audio_client(asm_token._token.session_id);
+ dir = q6asm_get_flag_from_token(&asm_token, ASM_DIRECTION_OFFSET);
+
+ if (!ac) {
+ pr_debug("%s: session[%d] already freed\n",
+ __func__, asm_token._token.session_id);
+ return 0;
+ }
+
+ if (data->payload_size > sizeof(int)) {
+ pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
+ __func__, payload[0], payload[1], data->opcode,
+ data->token, data->payload_size, data->src_port,
+ data->dest_port, asm_token._token.session_id, dir);
+ pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ } else if (data->payload_size == sizeof(int)) {
+ pr_debug("%s:ptr0[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
+ __func__, payload[0], data->opcode,
+ data->token, data->payload_size, data->src_port,
+ data->dest_port, asm_token._token.session_id, dir);
+ pr_debug("%s:Payload = [0x%x]\n",
+ __func__, payload[0]);
+ }
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ switch (payload[0]) {
+ case ASM_CMD_SHARED_MEM_MAP_REGIONS:
+ case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
+ case ASM_CMD_ADD_TOPOLOGIES:
+ if (payload[1] != 0) {
+ pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
+ __func__, payload[0], payload[1],
+ asm_token._token.session_id);
+ if (payload[0] ==
+ ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
+ atomic_set(&ac->unmap_cb_success, 0);
+
+ atomic_set(&ac->mem_state, payload[1]);
+ wake_up(&ac->mem_wait);
+ } else {
+ if (payload[0] ==
+ ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
+ atomic_set(&ac->unmap_cb_success, 1);
+ }
+
+ if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
+ wake_up(&ac->mem_wait);
+ dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ break;
+ default:
+ pr_debug("%s: command[0x%x] not expecting rsp\n",
+ __func__, payload[0]);
+ break;
+ }
+ return 0;
+ }
+
+ port = &ac->port[dir];
+
+ switch (data->opcode) {
+ case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:{
+ pr_debug("%s:PL#0[0x%x] dir=0x%x s_id=0x%x\n",
+ __func__, payload[0], dir, asm_token._token.session_id);
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1) {
+ ac->port[dir].tmp_hdl = payload[0];
+ wake_up(&ac->mem_wait);
+ }
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+ break;
+ }
+ case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:{
+ pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n",
+ __func__, payload[0], payload[1]);
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
+ wake_up(&ac->mem_wait);
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+
+ break;
+ }
+ default:
+ pr_debug("%s: command[0x%x]success [0x%x]\n",
+ __func__, payload[0], payload[1]);
+ }
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ data->payload, ac->priv);
+ return 0;
+}
+
+static void q6asm_process_mtmx_get_param_rsp(struct audio_client *ac,
+ struct asm_mtmx_strtr_get_params_cmdrsp *cmdrsp)
+{
+ struct asm_session_mtmx_strtr_param_session_time_v3_t *time;
+
+ if (cmdrsp->err_code) {
+ dev_err_ratelimited(ac->dev,
+ "%s: err=%x, mod_id=%x, param_id=%x\n",
+ __func__, cmdrsp->err_code,
+ cmdrsp->param_info.module_id,
+ cmdrsp->param_info.param_id);
+ return;
+ }
+ dev_dbg_ratelimited(ac->dev,
+ "%s: mod_id=%x, param_id=%x\n", __func__,
+ cmdrsp->param_info.module_id,
+ cmdrsp->param_info.param_id);
+
+ switch (cmdrsp->param_info.module_id) {
+ case ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC:
+ switch (cmdrsp->param_info.param_id) {
+ case ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3:
+ time = &cmdrsp->param_data.session_time;
+ dev_vdbg(ac->dev, "%s: GET_TIME_V3, time_lsw=%x, time_msw=%x\n",
+ __func__, time->session_time_lsw,
+ time->session_time_msw);
+ ac->time_stamp = (uint64_t)(((uint64_t)
+ time->session_time_msw << 32) |
+ time->session_time_lsw);
+ if (time->flags &
+ ASM_SESSION_MTMX_STRTR_PARAM_STIME_TSTMP_FLG_BMASK)
+ dev_warn_ratelimited(ac->dev,
+ "%s: recv inval tstmp\n",
+ __func__);
+ if (atomic_cmpxchg(&ac->time_flag, 1, 0))
+ wake_up(&ac->time_wait);
+
+ break;
+ default:
+ dev_err(ac->dev, "%s: unexpected param_id %x\n",
+ __func__, cmdrsp->param_info.param_id);
+ break;
+ }
+ break;
+ default:
+ dev_err(ac->dev, "%s: unexpected mod_id %x\n", __func__,
+ cmdrsp->param_info.module_id);
+ break;
+ }
+}
+
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
+{
+ int i = 0;
+ struct audio_client *ac = (struct audio_client *)priv;
+ unsigned long dsp_flags;
+ uint32_t *payload;
+ uint32_t wakeup_flag = 1;
+ int32_t ret = 0;
+ union asm_token_struct asm_token;
+ uint8_t buf_index;
+
+ if (ac == NULL) {
+ pr_err("%s: ac NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (data == NULL) {
+ pr_err("%s: data NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (!q6asm_is_valid_audio_client(ac)) {
+ pr_err("%s: audio client pointer is invalid, ac = %pK\n",
+ __func__, ac);
+ return -EINVAL;
+ }
+
+ if (ac->session <= 0 || ac->session > 8) {
+ pr_err("%s: Session ID is invalid, session = %d\n", __func__,
+ ac->session);
+ return -EINVAL;
+ }
+
+ payload = data->payload;
+ asm_token.token = data->token;
+ if (q6asm_get_flag_from_token(&asm_token, ASM_CMD_NO_WAIT_OFFSET)) {
+ pr_debug("%s: No wait command opcode[0x%x] cmd_opcode:%x\n",
+ __func__, data->opcode, payload ? payload[0] : 0);
+ wakeup_flag = 0;
+ }
+
+ if (data->opcode == RESET_EVENTS) {
+ mutex_lock(&ac->cmd_lock);
+ atomic_set(&ac->reset, 1);
+ if (ac->apr == NULL)
+ ac->apr = ac->apr2;
+ pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
+ __func__,
+ data->reset_event, data->reset_proc, ac->apr);
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ (uint32_t *)data->payload, ac->priv);
+ apr_reset(ac->apr);
+ ac->apr = NULL;
+ atomic_set(&ac->time_flag, 0);
+ atomic_set(&ac->cmd_state, 0);
+ atomic_set(&ac->mem_state, 0);
+ wake_up(&ac->time_wait);
+ wake_up(&ac->cmd_wait);
+ wake_up(&ac->mem_wait);
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+ }
+
+ dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x] token[0x%x]payload_size[%d] src[%d] dest[%d]\n",
+ __func__,
+ ac->session, data->opcode,
+ data->token, data->payload_size, data->src_port,
+ data->dest_port);
+ if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
+ (data->opcode != ASM_DATA_EVENT_EOS) &&
+ (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
+ if (payload == NULL) {
+ pr_err("%s: payload is null\n", __func__);
+ return -EINVAL;
+ }
+ dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
+ __func__, payload[0], payload[1], data->opcode);
+ }
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ switch (payload[0]) {
+ case ASM_STREAM_CMD_SET_PP_PARAMS_V2:
+ if (rtac_make_asm_callback(ac->session, payload,
+ data->payload_size))
+ break;
+ case ASM_SESSION_CMD_PAUSE:
+ case ASM_SESSION_CMD_SUSPEND:
+ case ASM_DATA_CMD_EOS:
+ case ASM_STREAM_CMD_CLOSE:
+ case ASM_STREAM_CMD_FLUSH:
+ case ASM_SESSION_CMD_RUN_V2:
+ case ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS:
+ case ASM_STREAM_CMD_FLUSH_READBUFS:
+ pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] src %d dest %d\n",
+ __func__, ac->session, data->opcode, data->token,
+ payload[0], data->src_port, data->dest_port);
+ ret = q6asm_is_valid_session(data, priv);
+ if (ret != 0) {
+ pr_err("%s: session invalid %d\n", __func__, ret);
+ return ret;
+ }
+ case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2:
+ case ASM_STREAM_CMD_OPEN_READ_V3:
+ case ASM_STREAM_CMD_OPEN_WRITE_V3:
+ case ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE:
+ case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ:
+ case ASM_STREAM_CMD_OPEN_READWRITE_V2:
+ case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
+ case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+ case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+ case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+ case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
+ case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
+ case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
+ pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n",
+ __func__, ac->session,
+ data->opcode, data->token,
+ payload[0], payload[1],
+ data->src_port, data->dest_port);
+ if (payload[1] != 0) {
+ pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+ __func__, payload[0], payload[1]);
+ if (wakeup_flag) {
+ atomic_set(&ac->cmd_state, payload[1]);
+ wake_up(&ac->cmd_wait);
+ }
+ return 0;
+ }
+ if (atomic_read(&ac->cmd_state) && wakeup_flag) {
+ atomic_set(&ac->cmd_state, 0);
+ wake_up(&ac->cmd_wait);
+ }
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ (uint32_t *)data->payload, ac->priv);
+ break;
+ case ASM_CMD_ADD_TOPOLOGIES:
+ pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ if (payload[1] != 0) {
+ pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+ __func__, payload[0], payload[1]);
+ if (wakeup_flag) {
+ atomic_set(&ac->mem_state, payload[1]);
+ wake_up(&ac->mem_wait);
+ }
+ return 0;
+ }
+ if (atomic_read(&ac->mem_state) && wakeup_flag) {
+ atomic_set(&ac->mem_state, 0);
+ wake_up(&ac->mem_wait);
+ }
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ (uint32_t *)data->payload, ac->priv);
+ break;
+ case ASM_DATA_EVENT_WATERMARK: {
+ pr_debug("%s: Watermark opcode[0x%x] status[0x%x]",
+ __func__, payload[0], payload[1]);
+ break;
+ }
+ case ASM_STREAM_CMD_GET_PP_PARAMS_V2:
+ pr_debug("%s: ASM_STREAM_CMD_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
+ __func__, ac->session,
+ data->opcode, data->token,
+ data->src_port, data->dest_port);
+ /* Should only come here if there is an APR */
+ /* error or malformed APR packet. Otherwise */
+ /* response will be returned as */
+ /* ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 */
+ if (payload[1] != 0) {
+ pr_err("%s: ASM get param error = %d, resuming\n",
+ __func__, payload[1]);
+ rtac_make_asm_callback(ac->session, payload,
+ data->payload_size);
+ }
+ break;
+ default:
+ pr_debug("%s: command[0x%x] not expecting rsp\n",
+ __func__, payload[0]);
+ break;
+ }
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE_V2:{
+ struct audio_port_data *port = &ac->port[IN];
+
+ dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
+ __func__, payload[0], payload[1],
+ data->token);
+ if (ac->io_mode & SYNC_IO_MODE) {
+ if (port->buf == NULL) {
+ pr_err("%s: Unexpected Write Done\n",
+ __func__);
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ buf_index = asm_token._token.buf_index;
+ if (lower_32_bits(port->buf[buf_index].phys) !=
+ payload[0] ||
+ msm_audio_populate_upper_32_bits(
+ port->buf[buf_index].phys) != payload[1]) {
+ pr_debug("%s: Expected addr %pK\n",
+ __func__, &port->buf[buf_index].phys);
+ pr_err("%s: rxedl[0x%x] rxedu [0x%x]\n",
+ __func__, payload[0], payload[1]);
+ spin_unlock_irqrestore(&port->dsp_lock,
+ dsp_flags);
+ return -EINVAL;
+ }
+ port->buf[buf_index].used = 1;
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+
+ config_debug_fs_write_cb();
+
+ for (i = 0; i < port->max_buf_cnt; i++)
+ dev_vdbg(ac->dev, "%s %d\n",
+ __func__, port->buf[i].used);
+
+ }
+ break;
+ }
+ case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
+ pr_debug("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
+ __func__, ac->session, data->opcode,
+ data->token,
+ data->src_port, data->dest_port);
+ if (payload[0] != 0) {
+ pr_err("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 returned error = 0x%x\n",
+ __func__, payload[0]);
+ } else if (generic_get_data) {
+ generic_get_data->valid = 1;
+ if (generic_get_data->is_inband) {
+ pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n",
+ __func__, payload[1], payload[2], payload[3]);
+ generic_get_data->size_in_ints = payload[3]>>2;
+ for (i = 0; i < payload[3]>>2; i++) {
+ generic_get_data->ints[i] =
+ payload[4+i];
+ pr_debug("%s: ASM callback val %i = %i\n",
+ __func__, i, payload[4+i]);
+ }
+ pr_debug("%s: callback size in ints = %i\n",
+ __func__,
+ generic_get_data->size_in_ints);
+ }
+ if (atomic_read(&ac->cmd_state) && wakeup_flag) {
+ atomic_set(&ac->cmd_state, 0);
+ wake_up(&ac->cmd_wait);
+ }
+ break;
+ }
+ rtac_make_asm_callback(ac->session, payload,
+ data->payload_size);
+ break;
+ case ASM_DATA_EVENT_READ_DONE_V2:{
+
+ struct audio_port_data *port = &ac->port[OUT];
+
+ config_debug_fs_read_cb();
+
+ dev_vdbg(ac->dev, "%s: ReadDone: status=%d buff_add=0x%x act_size=%d offset=%d\n",
+ __func__, payload[READDONE_IDX_STATUS],
+ payload[READDONE_IDX_BUFADD_LSW],
+ payload[READDONE_IDX_SIZE],
+ payload[READDONE_IDX_OFFSET]);
+
+ dev_vdbg(ac->dev, "%s: ReadDone:msw_ts=%d lsw_ts=%d memmap_hdl=0x%x flags=%d id=%d num=%d\n",
+ __func__, payload[READDONE_IDX_MSW_TS],
+ payload[READDONE_IDX_LSW_TS],
+ payload[READDONE_IDX_MEMMAP_HDL],
+ payload[READDONE_IDX_FLAGS],
+ payload[READDONE_IDX_SEQ_ID],
+ payload[READDONE_IDX_NUMFRAMES]);
+
+ if (ac->io_mode & SYNC_IO_MODE) {
+ if (port->buf == NULL) {
+ pr_err("%s: Unexpected Write Done\n", __func__);
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ buf_index = asm_token._token.buf_index;
+ port->buf[buf_index].used = 0;
+ if (lower_32_bits(port->buf[buf_index].phys) !=
+ payload[READDONE_IDX_BUFADD_LSW] ||
+ msm_audio_populate_upper_32_bits(
+ port->buf[buf_index].phys) !=
+ payload[READDONE_IDX_BUFADD_MSW]) {
+ dev_vdbg(ac->dev, "%s: Expected addr %pK\n",
+ __func__, &port->buf[buf_index].phys);
+ pr_err("%s: rxedl[0x%x] rxedu[0x%x]\n",
+ __func__,
+ payload[READDONE_IDX_BUFADD_LSW],
+ payload[READDONE_IDX_BUFADD_MSW]);
+ spin_unlock_irqrestore(&port->dsp_lock,
+ dsp_flags);
+ break;
+ }
+ port->buf[buf_index].actual_size =
+ payload[READDONE_IDX_SIZE];
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+ }
+ break;
+ }
+ case ASM_DATA_EVENT_EOS:
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ pr_debug("%s: EOS ACK received: rxed session %d opcode 0x%x token 0x%x src %d dest %d\n",
+ __func__, ac->session,
+ data->opcode, data->token,
+ data->src_port, data->dest_port);
+ break;
+ case ASM_SESSION_EVENTX_OVERFLOW:
+ pr_debug("%s: ASM_SESSION_EVENTX_OVERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
+ __func__, ac->session,
+ data->opcode, data->token,
+ data->src_port, data->dest_port);
+ break;
+ case ASM_SESSION_EVENT_RX_UNDERFLOW:
+ pr_debug("%s: ASM_SESSION_EVENT_RX_UNDERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
+ __func__, ac->session,
+ data->opcode, data->token,
+ data->src_port, data->dest_port);
+ break;
+ case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
+ dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
+ __func__,
+ payload[0], payload[1], payload[2]);
+ ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) |
+ payload[1]);
+ if (atomic_cmpxchg(&ac->time_flag, 1, 0))
+ wake_up(&ac->time_wait);
+ break;
+ case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+ case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+ pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY session %d opcode 0x%x token 0x%x src %d dest %d\n",
+ __func__, ac->session,
+ data->opcode, data->token,
+ data->src_port, data->dest_port);
+ pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
+ __func__,
+ payload[0], payload[1], payload[2],
+ payload[3]);
+ break;
+ case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
+ q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
+ break;
+ case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
+ pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
+ __func__, ac->session, payload[0], payload[2],
+ payload[1]);
+ if (payload[0] == 0) {
+ atomic_set(&ac->cmd_state, 0);
+ /* ignore msw, as a delay that large shouldn't happen */
+ ac->path_delay = payload[1];
+ } else {
+ atomic_set(&ac->cmd_state, payload[0]);
+ ac->path_delay = UINT_MAX;
+ }
+ wake_up(&ac->cmd_wait);
+ break;
+ }
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ data->payload, ac->priv);
+
+ return 0;
+}
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
+ uint32_t *index)
+{
+ void *data;
+ unsigned char idx;
+ struct audio_port_data *port;
+
+ if (!ac || ((dir != IN) && (dir != OUT))) {
+ pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
+ return NULL;
+ }
+
+ if (ac->io_mode & SYNC_IO_MODE) {
+ port = &ac->port[dir];
+
+ mutex_lock(&port->lock);
+ idx = port->cpu_buf;
+ if (port->buf == NULL) {
+ pr_err("%s: Buffer pointer null\n", __func__);
+ mutex_unlock(&port->lock);
+ return NULL;
+ }
+ /* dir 0: used = 0 means buf in use
+ * dir 1: used = 1 means buf in use
+ */
+ if (port->buf[idx].used == dir) {
+ /* To make it more robust, we could loop and get the
+ * next avail buf, its risky though
+ */
+ pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
+ __func__, idx, dir);
+ mutex_unlock(&port->lock);
+ return NULL;
+ }
+ *size = port->buf[idx].actual_size;
+ *index = port->cpu_buf;
+ data = port->buf[idx].data;
+ dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
+ __func__,
+ ac->session,
+ port->cpu_buf,
+ data, *size);
+ /* By default increase the cpu_buf cnt
+ * user accesses this function,increase cpu
+ * buf(to avoid another api)
+ */
+ port->buf[idx].used = dir;
+ port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
+ port->max_buf_cnt);
+ mutex_unlock(&port->lock);
+ return data;
+ }
+ return NULL;
+}
+
+int q6asm_cpu_buf_release(int dir, struct audio_client *ac)
+{
+ struct audio_port_data *port;
+ int ret = 0;
+ int idx;
+
+ if (!ac || ((dir != IN) && (dir != OUT))) {
+ pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (ac->io_mode & SYNC_IO_MODE) {
+ port = &ac->port[dir];
+ mutex_lock(&port->lock);
+ idx = port->cpu_buf;
+ if (port->cpu_buf == 0) {
+ port->cpu_buf = port->max_buf_cnt - 1;
+ } else if (port->cpu_buf < port->max_buf_cnt) {
+ port->cpu_buf = port->cpu_buf - 1;
+ } else {
+ pr_err("%s: buffer index(%d) out of range\n",
+ __func__, port->cpu_buf);
+ ret = -EINVAL;
+ mutex_unlock(&port->lock);
+ goto exit;
+ }
+ port->buf[port->cpu_buf].used = dir ^ 1;
+ mutex_unlock(&port->lock);
+ }
+exit:
+ return ret;
+}
+
+void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
+ uint32_t *size, uint32_t *index)
+{
+ void *data;
+ unsigned char idx;
+ struct audio_port_data *port;
+
+ if (!ac || ((dir != IN) && (dir != OUT))) {
+ pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
+ return NULL;
+ }
+
+ port = &ac->port[dir];
+
+ idx = port->cpu_buf;
+ if (port->buf == NULL) {
+ pr_err("%s: Buffer pointer null\n", __func__);
+ return NULL;
+ }
+ /*
+ * dir 0: used = 0 means buf in use
+ * dir 1: used = 1 means buf in use
+ */
+ if (port->buf[idx].used == dir) {
+ /*
+ * To make it more robust, we could loop and get the
+ * next avail buf, its risky though
+ */
+ pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
+ __func__, idx, dir);
+ return NULL;
+ }
+ *size = port->buf[idx].actual_size;
+ *index = port->cpu_buf;
+ data = port->buf[idx].data;
+ dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
+ __func__, ac->session, port->cpu_buf,
+ data, *size);
+ /*
+ * By default increase the cpu_buf cnt
+ * user accesses this function,increase cpu
+ * buf(to avoid another api)
+ */
+ port->buf[idx].used = dir;
+ port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
+ port->max_buf_cnt);
+ return data;
+}
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
+{
+ int ret = -1;
+ struct audio_port_data *port;
+ uint32_t idx;
+
+ if (!ac || (dir != OUT)) {
+ pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
+ return ret;
+ }
+
+ if (ac->io_mode & SYNC_IO_MODE) {
+ port = &ac->port[dir];
+
+ mutex_lock(&port->lock);
+ idx = port->dsp_buf;
+
+ if (port->buf[idx].used == (dir ^ 1)) {
+ /* To make it more robust, we could loop and get the
+ * next avail buf, its risky though
+ */
+ pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
+ __func__, idx, dir);
+ mutex_unlock(&port->lock);
+ return ret;
+ }
+ dev_vdbg(ac->dev, "%s: session[%d]dsp_buf=%d cpu_buf=%d\n",
+ __func__,
+ ac->session, port->dsp_buf, port->cpu_buf);
+ ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
+ mutex_unlock(&port->lock);
+ }
+ return ret;
+}
+
+static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
+{
+ dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
+ __func__, pkt_size, cmd_flg, ac->session, stream_id);
+ mutex_lock(&ac->cmd_lock);
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ return;
+ }
+
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+ hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_ASM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
+ hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
+ if (cmd_flg)
+ q6asm_update_token(&hdr->token,
+ ac->session,
+ 0, /* Stream ID is NA */
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+
+ hdr->pkt_size = pkt_size;
+ mutex_unlock(&ac->cmd_lock);
+}
+
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg)
+{
+ __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
+}
+
+static void q6asm_stream_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg, int32_t stream_id)
+{
+ __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, stream_id);
+}
+
+static void __q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg,
+ uint32_t stream_id, u8 no_wait_flag)
+{
+ dev_vdbg(ac->dev, "%s: pkt_size = %d, cmd_flg = %d, session = %d stream_id=%d\n",
+ __func__, pkt_size, cmd_flg, ac->session, stream_id);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR is NULL", __func__);
+ return;
+ }
+ hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_ASM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
+ hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
+ if (cmd_flg) {
+ q6asm_update_token(&hdr->token,
+ ac->session,
+ 0, /* Stream ID is NA */
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ no_wait_flag);
+
+ }
+ hdr->pkt_size = pkt_size;
+}
+
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg)
+{
+ __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
+ ac->stream_id, WAIT_CMD);
+}
+
+static void q6asm_stream_add_hdr_async(struct audio_client *ac,
+ struct apr_hdr *hdr, uint32_t pkt_size,
+ uint32_t cmd_flg, int32_t stream_id)
+{
+ __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
+ stream_id, NO_WAIT_CMD);
+}
+
+static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
+ struct apr_hdr *hdr,
+ uint32_t pkt_size)
+{
+ pr_debug("%s: pkt_size=%d session=%d\n",
+ __func__, pkt_size, ac->session);
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return;
+ }
+
+ mutex_lock(&ac->cmd_lock);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+ hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_ASM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+ hdr->dest_port = 0;
+ q6asm_update_token(&hdr->token,
+ ac->session,
+ 0, /* Stream ID is NA */
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+ hdr->pkt_size = pkt_size;
+ mutex_unlock(&ac->cmd_lock);
+}
+
+static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
+ u32 pkt_size, int dir)
+{
+ pr_debug("%s: pkt size=%d\n",
+ __func__, pkt_size);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr->src_port = 0;
+ hdr->dest_port = 0;
+ q6asm_update_token(&hdr->token,
+ ac->session,
+ 0, /* Stream ID is NA */
+ 0, /* Buffer index is NA */
+ dir,
+ WAIT_CMD);
+ hdr->pkt_size = pkt_size;
+}
+
+static int __q6asm_open_read(struct audio_client *ac,
+ uint32_t format, uint16_t bits_per_sample,
+ uint32_t pcm_format_block_ver,
+ bool ts_mode)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_read_v3 open;
+
+ config_debug_fs_reset_index();
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
+ /* Stream prio : High, provide meta info with encoded frames */
+ open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
+
+ open.preprocopo_id = q6asm_get_asm_topology_cal();
+ if ((open.preprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
+ (open.preprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS))
+ open.preprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
+ open.bits_per_sample = bits_per_sample;
+ open.mode_flags = 0x0;
+
+ ac->topology = open.preprocopo_id;
+ ac->app_type = q6asm_get_asm_app_type_cal();
+ if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
+ open.mode_flags |= ASM_LOW_LATENCY_TX_STREAM_SESSION <<
+ ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
+ } else {
+ open.mode_flags |= ASM_LEGACY_STREAM_SESSION <<
+ ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
+ }
+
+ switch (format) {
+ case FORMAT_LINEAR_PCM:
+ open.mode_flags |= 0x00;
+ open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
+ if (ts_mode)
+ open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE;
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
+ break;
+ case FORMAT_G711_ALAW_FS:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
+ break;
+ case FORMAT_G711_MLAW_FS:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
+ break;
+ case FORMAT_V13K:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
+ break;
+ case FORMAT_EVRC:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
+ break;
+ case FORMAT_AMRNB:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
+ break;
+ case FORMAT_AMRWB:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
+ break;
+ default:
+ pr_err("%s: Invalid format 0x%x\n",
+ __func__, format);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s: open failed op[0x%x]rc[%d]\n",
+ __func__, open.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for open read\n",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+
+ ac->io_mode |= TUN_READ_IO_MODE;
+
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_open_read(struct audio_client *ac,
+ uint32_t format)
+{
+ return __q6asm_open_read(ac, format, 16,
+ PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
+ false/*ts_mode*/);
+}
+
+int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_read(ac, format, bits_per_sample,
+ PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
+ false/*ts_mode*/);
+}
+
+/*
+ * asm_open_read_v3 - Opens audio capture session
+ *
+ * @ac: Client session handle
+ * @format: encoder format
+ * @bits_per_sample: bit width of capture session
+ */
+int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_read(ac, format, bits_per_sample,
+ PCM_MEDIA_FORMAT_V3/*media fmt block ver*/,
+ false/*ts_mode*/);
+}
+EXPORT_SYMBOL(q6asm_open_read_v3);
+
+/*
+ * asm_open_read_v4 - Opens audio capture session
+ *
+ * @ac: Client session handle
+ * @format: encoder format
+ * @bits_per_sample: bit width of capture session
+ */
+int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_read(ac, format, bits_per_sample,
+ PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
+ true/*ts_mode*/);
+}
+EXPORT_SYMBOL(q6asm_open_read_v4);
+
+int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
+ uint32_t passthrough_flag)
+{
+ int rc = 0;
+ struct asm_stream_cmd_open_write_compressed open;
+
+ if (ac == NULL) {
+ pr_err("%s: ac[%pK] NULL\n", __func__, ac);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (ac->apr == NULL) {
+ pr_err("%s: APR handle[%pK] NULL\n", __func__, ac->apr);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
+ format);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED;
+ atomic_set(&ac->cmd_state, -1);
+
+ switch (format) {
+ case FORMAT_AC3:
+ open.fmt_id = ASM_MEDIA_FMT_AC3;
+ break;
+ case FORMAT_EAC3:
+ open.fmt_id = ASM_MEDIA_FMT_EAC3;
+ break;
+ case FORMAT_DTS:
+ open.fmt_id = ASM_MEDIA_FMT_DTS;
+ break;
+ case FORMAT_DSD:
+ open.fmt_id = ASM_MEDIA_FMT_DSD;
+ break;
+ default:
+ pr_err("%s: Invalid format[%d]\n", __func__, format);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Below flag indicates the DSP that Compressed audio input
+ * stream is not IEC 61937 or IEC 60958 packetizied
+ */
+ if (passthrough_flag == COMPRESSED_PASSTHROUGH ||
+ passthrough_flag == COMPRESSED_PASSTHROUGH_DSD) {
+ open.flags = 0x0;
+ pr_debug("%s: Flag 0 COMPRESSED_PASSTHROUGH\n", __func__);
+ } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_CONVERT) {
+ open.flags = 0x8;
+ pr_debug("%s: Flag 8 - COMPRESSED_PASSTHROUGH_CONVERT\n",
+ __func__);
+ } else {
+ pr_err("%s: Invalid passthrough type[%d]\n",
+ __func__, passthrough_flag);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s: open failed op[0x%x]rc[%d]\n",
+ __func__, open.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for OPEN_WRITE_COMPR rc[%d]\n",
+ __func__, rc);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+
+ return 0;
+
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, uint32_t stream_id,
+ bool is_gapless_mode,
+ uint32_t pcm_format_block_ver)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_write_v3 open;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_vdbg(ac->dev, "%s: session[%d] wr_format[0x%x]\n",
+ __func__, ac->session, format);
+
+ q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ q6asm_update_token(&open.hdr.token,
+ ac->session,
+ stream_id,
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+
+ dev_vdbg(ac->dev, "%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, open.hdr.token, stream_id, ac->session);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
+ open.mode_flags = 0x00;
+ if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
+ open.mode_flags |= ASM_ULL_POST_PROCESSING_STREAM_SESSION;
+ else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
+ open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
+ else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+ open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
+ else {
+ open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
+ if (is_gapless_mode)
+ open.mode_flags |= 1 << ASM_SHIFT_GAPLESS_MODE_FLAG;
+ }
+
+ /* source endpoint : matrix */
+ open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
+ open.bits_per_sample = bits_per_sample;
+
+ open.postprocopo_id = q6asm_get_asm_topology_cal();
+ if ((ac->perf_mode != LEGACY_PCM_MODE) &&
+ ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
+ (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS)))
+ open.postprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
+
+ /* For DTS EAGLE only, force 24 bit */
+ if ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
+ (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS))
+ open.bits_per_sample = 24;
+
+ pr_debug("%s: perf_mode %d asm_topology 0x%x bps %d\n", __func__,
+ ac->perf_mode, open.postprocopo_id, open.bits_per_sample);
+
+ /*
+ * For Gapless playback it will use the same session for next stream,
+ * So use the same topology
+ */
+ if (!ac->topology) {
+ ac->topology = open.postprocopo_id;
+ ac->app_type = q6asm_get_asm_app_type_cal();
+ }
+ switch (format) {
+ case FORMAT_LINEAR_PCM:
+ open.dec_fmt_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
+ break;
+ case FORMAT_MPEG4_MULTI_AAC:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
+ break;
+ case FORMAT_WMA_V9:
+ open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
+ break;
+ case FORMAT_WMA_V10PRO:
+ open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
+ break;
+ case FORMAT_MP3:
+ open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
+ break;
+ case FORMAT_AC3:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AC3;
+ break;
+ case FORMAT_EAC3:
+ open.dec_fmt_id = ASM_MEDIA_FMT_EAC3;
+ break;
+ case FORMAT_MP2:
+ open.dec_fmt_id = ASM_MEDIA_FMT_MP2;
+ break;
+ case FORMAT_FLAC:
+ open.dec_fmt_id = ASM_MEDIA_FMT_FLAC;
+ break;
+ case FORMAT_ALAC:
+ open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
+ break;
+ case FORMAT_VORBIS:
+ open.dec_fmt_id = ASM_MEDIA_FMT_VORBIS;
+ break;
+ case FORMAT_APE:
+ open.dec_fmt_id = ASM_MEDIA_FMT_APE;
+ break;
+ case FORMAT_DSD:
+ open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
+ break;
+ default:
+ pr_err("%s: Invalid format 0x%x\n", __func__, format);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s: open failed op[0x%x]rc[%d]\n",
+ __func__, open.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for open write\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ ac->io_mode |= TUN_WRITE_IO_MODE;
+
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_open_write(struct audio_client *ac, uint32_t format)
+{
+ return __q6asm_open_write(ac, format, 16, ac->stream_id,
+ false /*gapless*/,
+ PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
+}
+
+int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ ac->stream_id, false /*gapless*/,
+ PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
+}
+
+/*
+ * q6asm_open_write_v3 - Opens audio playback session
+ *
+ * @ac: Client session handle
+ * @format: decoder format
+ * @bits_per_sample: bit width of playback session
+ */
+int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ ac->stream_id, false /*gapless*/,
+ PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
+}
+EXPORT_SYMBOL(q6asm_open_write_v3);
+
+/*
+ * q6asm_open_write_v4 - Opens audio playback session
+ *
+ * @ac: Client session handle
+ * @format: decoder format
+ * @bits_per_sample: bit width of playback session
+ */
+int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ ac->stream_id, false /*gapless*/,
+ PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
+}
+EXPORT_SYMBOL(q6asm_open_write_v4);
+
+int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ stream_id, is_gapless_mode,
+ PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
+}
+
+/*
+ * q6asm_stream_open_write_v3 - Creates audio stream for playback
+ *
+ * @ac: Client session handle
+ * @format: asm playback format
+ * @bits_per_sample: bit width of requested stream
+ * @stream_id: stream id of stream to be associated with this session
+ * @is_gapless_mode: true if gapless mode needs to be enabled
+ */
+int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ stream_id, is_gapless_mode,
+ PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
+}
+EXPORT_SYMBOL(q6asm_stream_open_write_v3);
+
+/*
+ * q6asm_stream_open_write_v4 - Creates audio stream for playback
+ *
+ * @ac: Client session handle
+ * @format: asm playback format
+ * @bits_per_sample: bit width of requested stream
+ * @stream_id: stream id of stream to be associated with this session
+ * @is_gapless_mode: true if gapless mode needs to be enabled
+ */
+int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ stream_id, is_gapless_mode,
+ PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
+}
+EXPORT_SYMBOL(q6asm_stream_open_write_v4);
+
+static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
+ uint32_t wr_format, bool is_meta_data_mode,
+ uint32_t bits_per_sample,
+ bool overwrite_topology, int topology)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_readwrite_v2 open;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]\n", __func__, ac->session);
+ pr_debug("%s: wr_format[0x%x]rd_format[0x%x]\n",
+ __func__, wr_format, rd_format);
+
+ ac->io_mode |= NT_MODE;
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
+
+ open.mode_flags = is_meta_data_mode ? BUFFER_META_ENABLE : 0;
+ open.bits_per_sample = bits_per_sample;
+ /* source endpoint : matrix */
+ open.postprocopo_id = q6asm_get_asm_topology_cal();
+
+ open.postprocopo_id = overwrite_topology ?
+ topology : open.postprocopo_id;
+ ac->topology = open.postprocopo_id;
+ ac->app_type = q6asm_get_asm_app_type_cal();
+
+ /* For DTS EAGLE only, force 24 bit */
+ if ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
+ (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER))
+ open.bits_per_sample = 24;
+
+ switch (wr_format) {
+ case FORMAT_LINEAR_PCM:
+ case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+ open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
+ break;
+ case FORMAT_MPEG4_MULTI_AAC:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
+ break;
+ case FORMAT_WMA_V9:
+ open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
+ break;
+ case FORMAT_WMA_V10PRO:
+ open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
+ break;
+ case FORMAT_AMRNB:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AMRNB_FS;
+ break;
+ case FORMAT_AMRWB:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AMRWB_FS;
+ break;
+ case FORMAT_AMR_WB_PLUS:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AMR_WB_PLUS_V2;
+ break;
+ case FORMAT_V13K:
+ open.dec_fmt_id = ASM_MEDIA_FMT_V13K_FS;
+ break;
+ case FORMAT_EVRC:
+ open.dec_fmt_id = ASM_MEDIA_FMT_EVRC_FS;
+ break;
+ case FORMAT_EVRCB:
+ open.dec_fmt_id = ASM_MEDIA_FMT_EVRCB_FS;
+ break;
+ case FORMAT_EVRCWB:
+ open.dec_fmt_id = ASM_MEDIA_FMT_EVRCWB_FS;
+ break;
+ case FORMAT_MP3:
+ open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
+ break;
+ case FORMAT_ALAC:
+ open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
+ break;
+ case FORMAT_APE:
+ open.dec_fmt_id = ASM_MEDIA_FMT_APE;
+ break;
+ case FORMAT_DSD:
+ open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
+ case FORMAT_G711_ALAW_FS:
+ open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS;
+ break;
+ case FORMAT_G711_MLAW_FS:
+ open.dec_fmt_id = ASM_MEDIA_FMT_G711_MLAW_FS;
+ break;
+ default:
+ pr_err("%s: Invalid format 0x%x\n",
+ __func__, wr_format);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ switch (rd_format) {
+ case FORMAT_LINEAR_PCM:
+ case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+ open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
+ break;
+ case FORMAT_G711_ALAW_FS:
+ open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
+ break;
+ case FORMAT_G711_MLAW_FS:
+ open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
+ break;
+ case FORMAT_V13K:
+ open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
+ break;
+ case FORMAT_EVRC:
+ open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
+ break;
+ case FORMAT_AMRNB:
+ open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
+ break;
+ case FORMAT_AMRWB:
+ open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
+ break;
+ case FORMAT_ALAC:
+ open.enc_cfg_id = ASM_MEDIA_FMT_ALAC;
+ break;
+ case FORMAT_APE:
+ open.enc_cfg_id = ASM_MEDIA_FMT_APE;
+ break;
+ default:
+ pr_err("%s: Invalid format 0x%x\n",
+ __func__, rd_format);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ dev_vdbg(ac->dev, "%s: rdformat[0x%x]wrformat[0x%x]\n", __func__,
+ open.enc_cfg_id, open.dec_fmt_id);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s: open failed op[0x%x]rc[%d]\n",
+ __func__, open.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for open read-write\n",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
+ uint32_t wr_format)
+{
+ return __q6asm_open_read_write(ac, rd_format, wr_format,
+ true/*meta data mode*/,
+ 16 /*bits_per_sample*/,
+ false /*overwrite_topology*/, 0);
+}
+
+int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format,
+ uint32_t wr_format, bool is_meta_data_mode,
+ uint32_t bits_per_sample, bool overwrite_topology,
+ int topology)
+{
+ return __q6asm_open_read_write(ac, rd_format, wr_format,
+ is_meta_data_mode, bits_per_sample,
+ overwrite_topology, topology);
+}
+
+int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_loopback_v2 open;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
+
+ open.mode_flags = 0;
+ open.src_endpointype = 0;
+ open.sink_endpointype = 0;
+ /* source endpoint : matrix */
+ open.postprocopo_id = q6asm_get_asm_topology_cal();
+
+ ac->app_type = q6asm_get_asm_app_type_cal();
+ ac->topology = open.postprocopo_id;
+ open.bits_per_sample = bits_per_sample;
+ open.reserved = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s: open failed op[0x%x]rc[%d]\n", __func__,
+ open.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for open_loopback\n",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+static
+int q6asm_set_shared_circ_buff(struct audio_client *ac,
+ struct asm_stream_cmd_open_shared_io *open,
+ int bufsz, int bufcnt,
+ int dir)
+{
+ struct audio_buffer *buf_circ;
+ int bytes_to_alloc, rc;
+ size_t len;
+
+ buf_circ = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
+
+ if (!buf_circ) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ mutex_lock(&ac->cmd_lock);
+
+ ac->port[dir].buf = buf_circ;
+
+ bytes_to_alloc = bufsz * bufcnt;
+ bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
+
+ rc = msm_audio_ion_alloc("audio_client", &buf_circ->client,
+ &buf_circ->handle, bytes_to_alloc,
+ (ion_phys_addr_t *)&buf_circ->phys,
+ &len, &buf_circ->data);
+
+ if (rc) {
+ pr_err("%s: Audio ION alloc is failed, rc = %d\n", __func__,
+ rc);
+ mutex_unlock(&ac->cmd_lock);
+ kfree(buf_circ);
+ goto done;
+ }
+
+ buf_circ->used = dir ^ 1;
+ buf_circ->size = bytes_to_alloc;
+ buf_circ->actual_size = bytes_to_alloc;
+ memset(buf_circ->data, 0, buf_circ->actual_size);
+
+ ac->port[dir].max_buf_cnt = 1;
+
+ open->shared_circ_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ open->shared_circ_buf_num_regions = 1;
+ open->shared_circ_buf_property_flag = 0x00;
+ open->shared_circ_buf_start_phy_addr_lsw =
+ lower_32_bits(buf_circ->phys);
+ open->shared_circ_buf_start_phy_addr_msw =
+ upper_32_bits(buf_circ->phys);
+ open->shared_circ_buf_size = bufsz * bufcnt;
+
+ open->map_region_circ_buf.shm_addr_lsw = lower_32_bits(buf_circ->phys);
+ open->map_region_circ_buf.shm_addr_msw = upper_32_bits(buf_circ->phys);
+ open->map_region_circ_buf.mem_size_bytes = bytes_to_alloc;
+
+ mutex_unlock(&ac->cmd_lock);
+done:
+ return rc;
+}
+
+
+static
+int q6asm_set_shared_pos_buff(struct audio_client *ac,
+ struct asm_stream_cmd_open_shared_io *open,
+ int dir)
+{
+ struct audio_buffer *buf_pos = &ac->shared_pos_buf;
+ int rc;
+ size_t len;
+ int bytes_to_alloc = sizeof(struct asm_shared_position_buffer);
+
+ mutex_lock(&ac->cmd_lock);
+
+ bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
+
+ rc = msm_audio_ion_alloc("audio_client", &buf_pos->client,
+ &buf_pos->handle, bytes_to_alloc,
+ (ion_phys_addr_t *)&buf_pos->phys, &len,
+ &buf_pos->data);
+
+ if (rc) {
+ pr_err("%s: Audio pos buf ION alloc is failed, rc = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ buf_pos->used = dir ^ 1;
+ buf_pos->size = bytes_to_alloc;
+ buf_pos->actual_size = bytes_to_alloc;
+
+ open->shared_pos_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ open->shared_pos_buf_num_regions = 1;
+ open->shared_pos_buf_property_flag = 0x00;
+ open->shared_pos_buf_phy_addr_lsw = lower_32_bits(buf_pos->phys);
+ open->shared_pos_buf_phy_addr_msw = upper_32_bits(buf_pos->phys);
+
+ open->map_region_pos_buf.shm_addr_lsw = lower_32_bits(buf_pos->phys);
+ open->map_region_pos_buf.shm_addr_msw = upper_32_bits(buf_pos->phys);
+ open->map_region_pos_buf.mem_size_bytes = bytes_to_alloc;
+
+done:
+ mutex_unlock(&ac->cmd_lock);
+ return rc;
+}
+
+/*
+ * q6asm_open_shared_io: Open an ASM session for pull mode (playback)
+ * or push mode (capture).
+ * parameters
+ * config - session parameters (channels, bits_per_sample, sr)
+ * dir - stream direction (IN for playback, OUT for capture)
+ * returns 0 if successful, error code otherwise
+ */
+int q6asm_open_shared_io(struct audio_client *ac,
+ struct shared_io_config *config,
+ int dir)
+{
+ struct asm_stream_cmd_open_shared_io *open;
+ u8 *channel_mapping;
+ int i, size_of_open, num_watermarks, bufsz, bufcnt, rc, flags = 0;
+
+ if (!ac || !config)
+ return -EINVAL;
+
+ bufsz = config->bufsz;
+ bufcnt = config->bufcnt;
+ num_watermarks = 0;
+
+ ac->config = *config;
+
+ if (ac->session <= 0 || ac->session > SESSION_MAX) {
+ pr_err("%s: Session %d is out of bounds\n",
+ __func__, ac->session);
+ return -EINVAL;
+ }
+
+ size_of_open = sizeof(struct asm_stream_cmd_open_shared_io) +
+ (sizeof(struct asm_shared_watermark_level) * num_watermarks);
+
+ open = kzalloc(PAGE_ALIGN(size_of_open), GFP_KERNEL);
+ if (!open)
+ return -ENOMEM;
+
+ q6asm_stream_add_hdr(ac, &open->hdr, size_of_open, TRUE,
+ ac->stream_id);
+
+ atomic_set(&ac->cmd_state, 1);
+
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x, perf %d\n",
+ __func__, open->hdr.token, ac->stream_id, ac->session,
+ ac->perf_mode);
+
+ open->hdr.opcode =
+ dir == IN ? ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE :
+ ASM_STREAM_CMD_OPEN_PUSH_MODE_READ;
+
+ pr_debug("%s perf_mode %d\n", __func__, ac->perf_mode);
+ if (dir == IN)
+ if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
+ flags = 4 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
+ else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
+ flags = 2 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
+ else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+ flags = 1 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
+ else
+ pr_err("Invalid perf mode for pull write\n");
+ else
+ if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+ flags = ASM_LOW_LATENCY_TX_STREAM_SESSION <<
+ ASM_SHIFT_STREAM_PERF_FLAG_PUSH_MODE_READ;
+ else
+ pr_err("Invalid perf mode for push read\n");
+
+ if (flags == 0) {
+ pr_err("%s: Invalid mode[%d]\n", __func__,
+ ac->perf_mode);
+ kfree(open);
+ return -EINVAL;
+
+ }
+
+ pr_debug("open.mode_flags = 0x%x\n", flags);
+ open->mode_flags = flags;
+ open->endpoint_type = ASM_END_POINT_DEVICE_MATRIX;
+ open->topo_bits_per_sample = config->bits_per_sample;
+
+ open->topo_id = q6asm_get_asm_topology_cal();
+
+ if (config->format == FORMAT_LINEAR_PCM)
+ open->fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
+ else {
+ pr_err("%s: Invalid format[%d]\n", __func__, config->format);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (ac->port[dir].buf) {
+ pr_err("%s: Buffer already allocated\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ rc = q6asm_set_shared_circ_buff(ac, open, bufsz, bufcnt, dir);
+
+ if (rc)
+ goto done;
+
+ ac->port[dir].tmp_hdl = 0;
+
+ rc = q6asm_set_shared_pos_buff(ac, open, dir);
+
+ if (rc)
+ goto done;
+
+ /* asm_multi_channel_pcm_fmt_blk_v3 */
+ open->fmt.num_channels = config->channels;
+ open->fmt.bits_per_sample = config->bits_per_sample;
+ open->fmt.sample_rate = config->rate;
+ open->fmt.is_signed = 1;
+ open->fmt.sample_word_size = config->sample_word_size;
+
+ channel_mapping = open->fmt.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ rc = q6asm_map_channels(channel_mapping, config->channels, false);
+ if (rc) {
+ pr_err("%s: Map channels failed, ret: %d\n", __func__, rc);
+ goto done;
+ }
+
+ open->num_watermark_levels = num_watermarks;
+ for (i = 0; i < num_watermarks; i++) {
+ open->watermark[i].watermark_level_bytes = i *
+ ((bufsz * bufcnt) / num_watermarks);
+ pr_debug("%s: Watermark level set for %i\n",
+ __func__,
+ open->watermark[i].watermark_level_bytes);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) open);
+ if (rc < 0) {
+ pr_err("%s: Open failed op[0x%x]rc[%d]\n",
+ __func__, open->hdr.opcode, rc);
+ goto done;
+ }
+
+ pr_debug("%s: sent open apr pkt\n", __func__);
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) <= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: Timeout. Waited for open write apr pkt rc[%d]\n",
+ __func__, rc);
+ rc = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (atomic_read(&ac->cmd_state) < 0) {
+ pr_err("%s: DSP returned error [%d]\n", __func__,
+ atomic_read(&ac->cmd_state));
+ rc = -EINVAL;
+ goto done;
+ }
+
+ ac->io_mode |= TUN_WRITE_IO_MODE;
+ rc = 0;
+done:
+ kfree(open);
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_open_shared_io);
+
+/*
+ * q6asm_shared_io_buf: Returns handle to the shared circular buffer being
+ * used for pull/push mode.
+ * parameters
+ * dir - used to identify input/output port
+ * returns buffer handle
+ */
+struct audio_buffer *q6asm_shared_io_buf(struct audio_client *ac,
+ int dir)
+{
+ struct audio_port_data *port;
+
+ if (!ac) {
+ pr_err("%s: ac is null\n", __func__);
+ return NULL;
+ }
+ port = &ac->port[dir];
+ return port->buf;
+}
+EXPORT_SYMBOL(q6asm_shared_io_buf);
+
+/*
+ * q6asm_shared_io_free: Frees memory allocated for a pull/push session
+ * parameters
+ * dir - port direction
+ * returns 0 if successful, error otherwise
+ */
+int q6asm_shared_io_free(struct audio_client *ac, int dir)
+{
+ struct audio_port_data *port;
+
+ if (!ac) {
+ pr_err("%s: audio client is null\n", __func__);
+ return -EINVAL;
+ }
+ port = &ac->port[dir];
+ mutex_lock(&ac->cmd_lock);
+ if (port->buf && port->buf->data) {
+ msm_audio_ion_free(port->buf->client, port->buf->handle);
+ port->buf->client = NULL;
+ port->buf->handle = NULL;
+ port->max_buf_cnt = 0;
+ kfree(port->buf);
+ port->buf = NULL;
+ }
+ if (ac->shared_pos_buf.data) {
+ msm_audio_ion_free(ac->shared_pos_buf.client,
+ ac->shared_pos_buf.handle);
+ ac->shared_pos_buf.client = NULL;
+ ac->shared_pos_buf.handle = NULL;
+ }
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+}
+EXPORT_SYMBOL(q6asm_shared_io_free);
+
+/*
+ * q6asm_get_shared_pos: Returns current read index/write index as observed
+ * by the DSP. Note that this is an offset and iterates from [0,BUF_SIZE - 1]
+ * parameters - (all output)
+ * read_index - offset
+ * wall_clk_msw1 - ADSP wallclock msw
+ * wall_clk_lsw1 - ADSP wallclock lsw
+ * returns 0 if successful, -EAGAIN if DSP failed to update after some
+ * retries
+ */
+int q6asm_get_shared_pos(struct audio_client *ac, uint32_t *read_index,
+ uint32_t *wall_clk_msw1, uint32_t *wall_clk_lsw1)
+{
+ struct asm_shared_position_buffer *pos_buf;
+ uint32_t frame_cnt1, frame_cnt2;
+ int i, j;
+
+ if (!ac) {
+ pr_err("%s: audio client is null\n", __func__);
+ return -EINVAL;
+ }
+
+ pos_buf = ac->shared_pos_buf.data;
+
+ /* always try to get the latest update in the shared pos buffer */
+ for (i = 0; i < 2; i++) {
+ /* retry until there is an update from DSP */
+ for (j = 0; j < 5; j++) {
+ frame_cnt1 = pos_buf->frame_counter;
+ if (frame_cnt1 != 0)
+ break;
+ }
+
+ *wall_clk_msw1 = pos_buf->wall_clock_us_msw;
+ *wall_clk_lsw1 = pos_buf->wall_clock_us_lsw;
+ *read_index = pos_buf->index;
+ frame_cnt2 = pos_buf->frame_counter;
+
+ if (frame_cnt1 != frame_cnt2)
+ continue;
+ return 0;
+ }
+ pr_err("%s out of tries trying to get a good read, try again\n",
+ __func__);
+ return -EAGAIN;
+}
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts)
+{
+ struct asm_session_cmd_run_v2 run;
+ int rc;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
+ run.flags = flags;
+ run.time_lsw = lsw_ts;
+ run.time_msw = msw_ts;
+
+ config_debug_fs_run();
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+ if (rc < 0) {
+ pr_err("%s: Commmand run failed[%d]",
+ __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for run success",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
+{
+ struct asm_session_cmd_run_v2 run;
+ int rc;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+ q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, 1);
+ run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
+ run.flags = flags;
+ run.time_lsw = lsw_ts;
+ run.time_msw = msw_ts;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+ if (rc < 0) {
+ pr_err("%s: Commmand run failed[%d]", __func__, rc);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts)
+{
+ return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, ac->stream_id);
+}
+
+int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
+{
+ return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
+}
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+ uint32_t frames_per_buf,
+ uint32_t sample_rate, uint32_t channels,
+ uint32_t bit_rate, uint32_t mode, uint32_t format)
+{
+ struct asm_aac_enc_cfg_v2 enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d] format[%d]\n",
+ __func__, ac->session, frames_per_buf,
+ sample_rate, channels, bit_rate, mode, format);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
+ sizeof(struct asm_stream_cmd_set_encdec_param);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+ enc_cfg.bit_rate = bit_rate;
+ enc_cfg.enc_mode = mode;
+ enc_cfg.aac_fmt_flag = format;
+ enc_cfg.channel_cfg = channels;
+ enc_cfg.sample_rate = sample_rate;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd %d failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_enc_cfg_blk_g711(struct audio_client *ac,
+ uint32_t frames_per_buf,
+ uint32_t sample_rate)
+{
+ struct asm_g711_enc_cfg_v2 enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]frames[%d]SR[%d]\n",
+ __func__, ac->session, frames_per_buf,
+ sample_rate);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(struct asm_g711_enc_cfg_v2) -
+ sizeof(struct asm_stream_cmd_set_encdec_param);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+ enc_cfg.sample_rate = sample_rate;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd %d failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+ uint32_t num_channels)
+{
+ struct asm_dec_out_chan_map_param chan_map;
+ u8 *channel_mapping;
+ int rc = 0;
+
+ pr_debug("%s: Session %d, num_channels = %d\n",
+ __func__, ac->session, num_channels);
+ q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ chan_map.encdec.param_id = ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP;
+ chan_map.encdec.param_size = sizeof(struct asm_dec_out_chan_map_param) -
+ (sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_encdec_param));
+ chan_map.num_channels = num_channels;
+ channel_mapping = chan_map.channel_mapping;
+ memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
+
+ if (q6asm_map_channels(channel_mapping, num_channels, false)) {
+ pr_err("%s: map channels failed %d\n", __func__, num_channels);
+ return -EINVAL;
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
+ if (rc < 0) {
+ pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n", __func__,
+ chan_map.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+/*
+ * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @use_default_chmap: true if default channel map to be used
+ * @use_back_flavor: to configure back left and right channel
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, bool use_default_chmap,
+ bool use_back_flavor, u8 *channel_map,
+ uint16_t sample_word_size, uint16_t endianness,
+ uint16_t mode)
+{
+ struct asm_multi_channel_pcm_enc_cfg_v4 enc_cfg;
+ struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
+ u8 *channel_mapping;
+ u32 frames_per_buf = 0;
+ int rc;
+
+ if (!use_default_chmap && (channel_map == NULL)) {
+ pr_err("%s: No valid chan map and can't use default\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&enc_cfg, 0, sizeof(enc_cfg));
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
+ sizeof(enc_cfg.encdec);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(enc_fg_blk);
+ enc_cfg.num_channels = channels;
+ enc_cfg.bits_per_sample = bits_per_sample;
+ enc_cfg.sample_rate = rate;
+ enc_cfg.is_signed = 1;
+ enc_cfg.sample_word_size = sample_word_size;
+ enc_cfg.endianness = endianness;
+ enc_cfg.mode = mode;
+ channel_mapping = enc_cfg.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ pr_debug("%s: setting default channel map for %d channels",
+ __func__, channels);
+ if (q6asm_map_channels(channel_mapping, channels,
+ use_back_flavor)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ pr_debug("%s: Using pre-defined channel map", __func__);
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Command open failed %d\n", __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, enc_cfg.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v4);
+
+/*
+ * q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @use_default_chmap: true if default channel map to be used
+ * @use_back_flavor: to configure back left and right channel
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ */
+int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, bool use_default_chmap,
+ bool use_back_flavor, u8 *channel_map,
+ uint16_t sample_word_size)
+{
+ struct asm_multi_channel_pcm_enc_cfg_v3 enc_cfg;
+ struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
+ u8 *channel_mapping;
+ u32 frames_per_buf = 0;
+ int rc;
+
+ if (!use_default_chmap && (channel_map == NULL)) {
+ pr_err("%s: No valid chan map and can't use default\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&enc_cfg, 0, sizeof(enc_cfg));
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
+ sizeof(enc_cfg.encdec);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(enc_fg_blk);
+ enc_cfg.num_channels = channels;
+ enc_cfg.bits_per_sample = bits_per_sample;
+ enc_cfg.sample_rate = rate;
+ enc_cfg.is_signed = 1;
+ enc_cfg.sample_word_size = sample_word_size;
+ channel_mapping = enc_cfg.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ pr_debug("%s: setting default channel map for %d channels",
+ __func__, channels);
+ if (q6asm_map_channels(channel_mapping, channels,
+ use_back_flavor)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ pr_debug("%s: Using pre-defined channel map", __func__);
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, enc_cfg.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v3);
+
+int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac,
+ uint32_t rate, uint32_t channels, uint16_t bits_per_sample,
+ bool use_default_chmap, bool use_back_flavor, u8 *channel_map)
+{
+ struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
+ u8 *channel_mapping;
+ u32 frames_per_buf = 0;
+
+ int rc = 0;
+
+ if (!use_default_chmap && (channel_map == NULL)) {
+ pr_err("%s: No valid chan map and can't use default\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+ ac->session, rate, channels);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
+ sizeof(enc_cfg.encdec);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+
+ enc_cfg.num_channels = channels;
+ enc_cfg.bits_per_sample = bits_per_sample;
+ enc_cfg.sample_rate = rate;
+ enc_cfg.is_signed = 1;
+ channel_mapping = enc_cfg.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ pr_debug("%s: setting default channel map for %d channels",
+ __func__, channels);
+ if (q6asm_map_channels(channel_mapping, channels,
+ use_back_flavor)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ } else {
+ pr_debug("%s: Using pre-defined channel map", __func__);
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, enc_cfg.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ return q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
+ bits_per_sample, true, false, NULL,
+ sample_word_size, endianness, mode);
+}
+
+static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size)
+{
+ return q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
+ bits_per_sample, true, false, NULL,
+ sample_word_size);
+}
+
+static int __q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
+{
+ return q6asm_enc_cfg_blk_pcm_v2(ac, rate, channels,
+ bits_per_sample, true, false, NULL);
+}
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, 16);
+}
+
+int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
+ uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
+{
+ return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, bits_per_sample);
+}
+
+/*
+ * q6asm_enc_cfg_blk_pcm_format_support_v3 - sends encoder configuration
+ * parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ */
+int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size)
+{
+ return __q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
+ bits_per_sample, sample_word_size);
+}
+EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3);
+
+/*
+ * q6asm_enc_cfg_blk_pcm_format_support_v4 - sends encoder configuration
+ * parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ return __q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
+ bits_per_sample, sample_word_size,
+ endianness, mode);
+}
+EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4);
+
+int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
+ u8 *channel_mapping;
+ u32 frames_per_buf = 0;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+ ac->session, rate, channels);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
+ sizeof(enc_cfg.encdec);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+
+ enc_cfg.num_channels = 0;/*channels;*/
+ enc_cfg.bits_per_sample = 16;
+ enc_cfg.sample_rate = 0;/*rate;*/
+ enc_cfg.is_signed = 1;
+ channel_mapping = enc_cfg.channel_mapping;
+
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n", __func__, channels);
+ return -EINVAL;
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, enc_cfg.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
+ bool use_back_flavor)
+{
+ u8 *lchannel_mapping;
+
+ lchannel_mapping = channel_mapping;
+ pr_debug("%s: channels passed: %d\n", __func__, channels);
+ if (channels == 1) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channels == 3) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
+ } else if (channels == 4) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = use_back_flavor ?
+ PCM_CHANNEL_LB : PCM_CHANNEL_LS;
+ lchannel_mapping[3] = use_back_flavor ?
+ PCM_CHANNEL_RB : PCM_CHANNEL_RS;
+ } else if (channels == 5) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
+ lchannel_mapping[3] = use_back_flavor ?
+ PCM_CHANNEL_LB : PCM_CHANNEL_LS;
+ lchannel_mapping[4] = use_back_flavor ?
+ PCM_CHANNEL_RB : PCM_CHANNEL_RS;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
+ lchannel_mapping[3] = PCM_CHANNEL_LFE;
+ lchannel_mapping[4] = use_back_flavor ?
+ PCM_CHANNEL_LB : PCM_CHANNEL_LS;
+ lchannel_mapping[5] = use_back_flavor ?
+ PCM_CHANNEL_RB : PCM_CHANNEL_RS;
+ } else if (channels == 8) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
+ lchannel_mapping[3] = PCM_CHANNEL_LFE;
+ lchannel_mapping[4] = PCM_CHANNEL_LB;
+ lchannel_mapping[5] = PCM_CHANNEL_RB;
+ lchannel_mapping[6] = PCM_CHANNEL_LS;
+ lchannel_mapping[7] = PCM_CHANNEL_RS;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+ uint32_t sbr_ps_enable)
+{
+ struct asm_aac_sbr_ps_flag_param sbrps;
+ u32 frames_per_buf = 0;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d\n", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ sbrps.encdec.param_id = ASM_PARAM_ID_AAC_SBR_PS_FLAG;
+ sbrps.encdec.param_size = sizeof(struct asm_aac_sbr_ps_flag_param) -
+ sizeof(struct asm_stream_cmd_set_encdec_param);
+ sbrps.encblk.frames_per_buf = frames_per_buf;
+ sbrps.encblk.enc_cfg_blk_size = sbrps.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+
+ sbrps.sbr_ps_flag = sbr_ps_enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
+ if (rc < 0) {
+ pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
+ __func__,
+ ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_PARAM_ID_AAC_SBR_PS_FLAG, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x] ", __func__, sbrps.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
+ uint16_t sce_left, uint16_t sce_right)
+{
+ struct asm_aac_dual_mono_mapping_param dual_mono;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d, sce_left = %d, sce_right = %d\n",
+ __func__, ac->session, sce_left, sce_right);
+
+ q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
+ dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
+ sizeof(dual_mono.right_channel_sce);
+ dual_mono.left_channel_sce = sce_left;
+ dual_mono.right_channel_sce = sce_right;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &dual_mono);
+ if (rc < 0) {
+ pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n", __func__,
+ dual_mono.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+/* Support for selecting stereo mixing coefficients for B family not done */
+int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
+{
+ struct asm_aac_stereo_mix_coeff_selection_param_v2 aac_mix_coeff;
+ int rc = 0;
+
+ q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ aac_mix_coeff.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ aac_mix_coeff.param_id =
+ ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2;
+ aac_mix_coeff.param_size =
+ sizeof(struct asm_aac_stereo_mix_coeff_selection_param_v2);
+ aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
+ pr_debug("%s: mix_coeff = %u\n", __func__, mix_coeff);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
+ if (rc < 0) {
+ pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2,
+ rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, aac_mix_coeff.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t min_rate, uint16_t max_rate,
+ uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
+{
+ struct asm_v13k_enc_cfg enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]\n",
+ __func__,
+ ac->session, frames_per_buf, min_rate, max_rate,
+ reduced_rate_level, rate_modulation_cmd);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(struct asm_v13k_enc_cfg) -
+ sizeof(struct asm_stream_cmd_set_encdec_param);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+
+ enc_cfg.min_rate = min_rate;
+ enc_cfg.max_rate = max_rate;
+ enc_cfg.reduced_rate_cmd = reduced_rate_level;
+ enc_cfg.rate_mod_cmd = rate_modulation_cmd;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd %d failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for setencdec v13k resp\n",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t min_rate, uint16_t max_rate,
+ uint16_t rate_modulation_cmd)
+{
+ struct asm_evrc_enc_cfg enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] rate_modulation_cmd[0x%4x]\n",
+ __func__, ac->session,
+ frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(struct asm_evrc_enc_cfg) -
+ sizeof(struct asm_stream_cmd_set_encdec_param);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+
+ enc_cfg.min_rate = min_rate;
+ enc_cfg.max_rate = max_rate;
+ enc_cfg.rate_mod_cmd = rate_modulation_cmd;
+ enc_cfg.reserved = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd %d failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for encdec evrc\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t band_mode, uint16_t dtx_enable)
+{
+ struct asm_amrnb_enc_cfg enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
+ __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(struct asm_amrnb_enc_cfg) -
+ sizeof(struct asm_stream_cmd_set_encdec_param);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+
+ enc_cfg.enc_mode = band_mode;
+ enc_cfg.dtx_mode = dtx_enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd %d failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for set encdec amrnb\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t band_mode, uint16_t dtx_enable)
+{
+ struct asm_amrwb_enc_cfg enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
+ __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(struct asm_amrwb_enc_cfg) -
+ sizeof(struct asm_stream_cmd_set_encdec_param);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+
+ enc_cfg.enc_mode = band_mode;
+ enc_cfg.dtx_mode = dtx_enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd %d failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+
+static int __q6asm_media_format_block_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, int stream_id,
+ bool use_default_chmap, char *channel_map)
+{
+ struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
+ u8 *channel_mapping;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
+ channels);
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ q6asm_update_token(&fmt.hdr.token,
+ ac->session,
+ stream_id,
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, fmt.hdr.token, stream_id, ac->session);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.num_channels = channels;
+ fmt.bits_per_sample = bits_per_sample;
+ fmt.sample_rate = rate;
+ fmt.is_signed = 1;
+
+ channel_mapping = fmt.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_media_format_block_pcm_v3(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size)
+{
+ struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
+ u8 *channel_mapping;
+ int rc;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
+ (stream_id & 0xFF);
+
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, fmt.hdr.token, stream_id, ac->session);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.param.num_channels = channels;
+ fmt.param.bits_per_sample = bits_per_sample;
+ fmt.param.sample_rate = rate;
+ fmt.param.is_signed = 1;
+ fmt.param.sample_word_size = sample_word_size;
+ channel_mapping = fmt.param.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_media_format_block_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
+ u8 *channel_mapping;
+ int rc;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
+ (stream_id & 0xFF);
+
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, fmt.hdr.token, stream_id, ac->session);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.param.num_channels = channels;
+ fmt.param.bits_per_sample = bits_per_sample;
+ fmt.param.sample_rate = rate;
+ fmt.param.is_signed = 1;
+ fmt.param.sample_word_size = sample_word_size;
+ fmt.param.endianness = endianness;
+ fmt.param.mode = mode;
+ channel_mapping = fmt.param.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ return __q6asm_media_format_block_pcm(ac, rate,
+ channels, 16, ac->stream_id,
+ true, NULL);
+}
+
+int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_media_format_block_pcm(ac, rate,
+ channels, bits_per_sample, ac->stream_id,
+ true, NULL);
+}
+
+int q6asm_media_format_block_pcm_format_support_v2(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample, int stream_id,
+ bool use_default_chmap, char *channel_map)
+{
+ if (!use_default_chmap && (channel_map == NULL)) {
+ pr_err("%s: No valid chan map and can't use default\n",
+ __func__);
+ return -EINVAL;
+ }
+ return __q6asm_media_format_block_pcm(ac, rate,
+ channels, bits_per_sample, stream_id,
+ use_default_chmap, channel_map);
+}
+
+/*
+ * q6asm_media_format_block_pcm_format_support_v3- sends pcm decoder
+ * configuration parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @stream_id: stream id of stream to be associated with this session
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ */
+int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size)
+{
+ if (!use_default_chmap && (channel_map == NULL)) {
+ pr_err("%s: No valid chan map and can't use default\n",
+ __func__);
+ return -EINVAL;
+ }
+ return __q6asm_media_format_block_pcm_v3(ac, rate,
+ channels, bits_per_sample, stream_id,
+ use_default_chmap, channel_map,
+ sample_word_size);
+
+}
+EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3);
+
+/*
+ * q6asm_media_format_block_pcm_format_support_v4- sends pcm decoder
+ * configuration parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @stream_id: stream id of stream to be associated with this session
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ uint16_t bits_per_sample,
+ int stream_id,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ if (!use_default_chmap && (channel_map == NULL)) {
+ pr_err("%s: No valid chan map and can't use default\n",
+ __func__);
+ return -EINVAL;
+ }
+ return __q6asm_media_format_block_pcm_v4(ac, rate,
+ channels, bits_per_sample, stream_id,
+ use_default_chmap, channel_map,
+ sample_word_size, endianness,
+ mode);
+
+}
+EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v4);
+
+
+static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample)
+{
+ struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
+ u8 *channel_mapping;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
+ channels);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.num_channels = channels;
+ fmt.bits_per_sample = bits_per_sample;
+ fmt.sample_rate = rate;
+ fmt.is_signed = 1;
+
+ channel_mapping = fmt.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size)
+{
+ struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
+ u8 *channel_mapping;
+ int rc;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.param.num_channels = channels;
+ fmt.param.bits_per_sample = bits_per_sample;
+ fmt.param.sample_rate = rate;
+ fmt.param.is_signed = 1;
+ fmt.param.sample_word_size = sample_word_size;
+ channel_mapping = fmt.param.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
+ uint32_t rate,
+ uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
+ u8 *channel_mapping;
+ int rc;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
+ ac->session, rate, channels,
+ bits_per_sample, sample_word_size);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.param.num_channels = channels;
+ fmt.param.bits_per_sample = bits_per_sample;
+ fmt.param.sample_rate = rate;
+ fmt.param.is_signed = 1;
+ fmt.param.sample_word_size = sample_word_size;
+ fmt.param.endianness = endianness;
+ fmt.param.mode = mode;
+ channel_mapping = fmt.param.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map)
+{
+ return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
+ channels, use_default_chmap, channel_map, 16);
+}
+
+int q6asm_media_format_block_multi_ch_pcm_v2(
+ struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
+ channels, use_default_chmap, channel_map,
+ bits_per_sample);
+}
+
+/*
+ * q6asm_media_format_block_multi_ch_pcm_v3 - sends pcm decoder configuration
+ * parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ */
+int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size)
+{
+ return __q6asm_media_format_block_multi_ch_pcm_v3(ac, rate, channels,
+ use_default_chmap,
+ channel_map,
+ bits_per_sample,
+ sample_word_size);
+}
+EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3);
+
+/*
+ * q6asm_media_format_block_multi_ch_pcm_v4 - sends pcm decoder configuration
+ * parameters
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @bits_per_sample: bit width of encoder session
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @sample_word_size: Size in bits of the word that holds a sample of a channel
+ * @endianness: endianness of the pcm data
+ * @mode: Mode to provide additional info about the pcm input data
+ */
+int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap,
+ char *channel_map,
+ uint16_t bits_per_sample,
+ uint16_t sample_word_size,
+ uint16_t endianness,
+ uint16_t mode)
+{
+ return __q6asm_media_format_block_multi_ch_pcm_v4(ac, rate, channels,
+ use_default_chmap,
+ channel_map,
+ bits_per_sample,
+ sample_word_size,
+ endianness,
+ mode);
+}
+EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
+
+static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id)
+{
+ struct asm_aac_fmt_blk_v2 fmt;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
+ cfg->sample_rate, cfg->ch_cfg);
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ q6asm_update_token(&fmt.hdr.token,
+ ac->session,
+ stream_id,
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, fmt.hdr.token, stream_id, ac->session);
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.aac_fmt_flag = cfg->format;
+ fmt.audio_objype = cfg->aot;
+ /* If zero, PCE is assumed to be available in bitstream*/
+ fmt.total_size_of_PCE_bits = 0;
+ fmt.channel_config = cfg->ch_cfg;
+ fmt.sample_rate = cfg->sample_rate;
+
+ pr_debug("%s: format=0x%x cfg_size=%d aac-cfg=0x%x aot=%d ch=%d sr=%d\n",
+ __func__, fmt.aac_fmt_flag, fmt.fmt_blk.fmt_blk_size,
+ fmt.aac_fmt_flag,
+ fmt.audio_objype,
+ fmt.channel_config,
+ fmt.sample_rate);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
+}
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
+}
+
+int q6asm_stream_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, stream_id);
+}
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+ void *cfg, int stream_id)
+{
+ struct asm_wmastdv9_fmt_blk_v2 fmt;
+ struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
+ int rc = 0;
+
+ pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
+ ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
+ wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
+ wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
+ wma_cfg->ch_mask, wma_cfg->encode_opt);
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+ fmt.fmtag = wma_cfg->format_tag;
+ fmt.num_channels = wma_cfg->ch_cfg;
+ fmt.sample_rate = wma_cfg->sample_rate;
+ fmt.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
+ fmt.blk_align = wma_cfg->block_align;
+ fmt.bits_per_sample =
+ wma_cfg->valid_bits_per_sample;
+ fmt.channel_mask = wma_cfg->ch_mask;
+ fmt.enc_options = wma_cfg->encode_opt;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+ void *cfg, int stream_id)
+{
+ struct asm_wmaprov10_fmt_blk_v2 fmt;
+ struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x], adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
+ __func__,
+ ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
+ wmapro_cfg->ch_cfg, wmapro_cfg->avg_bytes_per_sec,
+ wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
+ wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
+ wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+
+ fmt.fmtag = wmapro_cfg->format_tag;
+ fmt.num_channels = wmapro_cfg->ch_cfg;
+ fmt.sample_rate = wmapro_cfg->sample_rate;
+ fmt.avg_bytes_per_sec =
+ wmapro_cfg->avg_bytes_per_sec;
+ fmt.blk_align = wmapro_cfg->block_align;
+ fmt.bits_per_sample = wmapro_cfg->valid_bits_per_sample;
+ fmt.channel_mask = wmapro_cfg->ch_mask;
+ fmt.enc_options = wmapro_cfg->encode_opt;
+ fmt.usAdvancedEncodeOpt = wmapro_cfg->adv_encode_opt;
+ fmt.advanced_enc_options2 = wmapro_cfg->adv_encode_opt2;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+ struct asm_amrwbplus_cfg *cfg)
+{
+ struct asm_amrwbplus_fmt_blk_v2 fmt;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
+ __func__,
+ ac->session,
+ cfg->amr_band_mode,
+ cfg->amr_frame_fmt,
+ cfg->num_channels);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+ fmt.amr_frame_fmt = cfg->amr_frame_fmt;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd media format update failed.. %d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_stream_media_format_block_flac(struct audio_client *ac,
+ struct asm_flac_cfg *cfg, int stream_id)
+{
+ struct asm_flac_fmt_blk_v2 fmt;
+ int rc = 0;
+
+ pr_debug("%s :session[%d] rate[%d] ch[%d] size[%d] stream_id[%d]\n",
+ __func__, ac->session, cfg->sample_rate, cfg->ch_cfg,
+ cfg->sample_size, stream_id);
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+
+ fmt.is_stream_info_present = cfg->stream_info_present;
+ fmt.num_channels = cfg->ch_cfg;
+ fmt.min_blk_size = cfg->min_blk_size;
+ fmt.max_blk_size = cfg->max_blk_size;
+ fmt.sample_rate = cfg->sample_rate;
+ fmt.min_frame_size = cfg->min_frame_size;
+ fmt.max_frame_size = cfg->max_frame_size;
+ fmt.sample_size = cfg->sample_size;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s :Comamnd media format update failed %d\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_media_format_block_alac(struct audio_client *ac,
+ struct asm_alac_cfg *cfg, int stream_id)
+{
+ struct asm_alac_fmt_blk_v2 fmt;
+ int rc = 0;
+
+ pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
+ ac->session, cfg->sample_rate, cfg->num_channels);
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+
+ fmt.frame_length = cfg->frame_length;
+ fmt.compatible_version = cfg->compatible_version;
+ fmt.bit_depth = cfg->bit_depth;
+ fmt.pb = cfg->pb;
+ fmt.mb = cfg->mb;
+ fmt.kb = cfg->kb;
+ fmt.num_channels = cfg->num_channels;
+ fmt.max_run = cfg->max_run;
+ fmt.max_frame_bytes = cfg->max_frame_bytes;
+ fmt.avg_bit_rate = cfg->avg_bit_rate;
+ fmt.sample_rate = cfg->sample_rate;
+ fmt.channel_layout_tag = cfg->channel_layout_tag;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s :Comamnd media format update failed %d\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+/*
+ * q6asm_media_format_block_g711 - sends g711 decoder configuration
+ * parameters
+ * @ac: Client session handle
+ * @cfg: Audio stream manager configuration parameters
+ * @stream_id: Stream id
+ */
+int q6asm_media_format_block_g711(struct audio_client *ac,
+ struct asm_g711_dec_cfg *cfg, int stream_id)
+{
+ struct asm_g711_dec_fmt_blk_v2 fmt;
+ int rc = 0;
+
+ if (!ac) {
+ pr_err("%s: audio client is null\n", __func__);
+ return -EINVAL;
+ }
+ if (!cfg) {
+ pr_err("%s: Invalid ASM config\n", __func__);
+ return -EINVAL;
+ }
+
+ if (stream_id <= 0) {
+ pr_err("%s: Invalid stream id\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s :session[%d]rate[%d]\n", __func__,
+ ac->session, cfg->sample_rate);
+
+ memset(&fmt, 0, sizeof(struct asm_g711_dec_fmt_blk_v2));
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+
+ fmt.sample_rate = cfg->sample_rate;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s :Command media format update failed %d\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_media_format_block_g711);
+
+int q6asm_stream_media_format_block_vorbis(struct audio_client *ac,
+ struct asm_vorbis_cfg *cfg, int stream_id)
+{
+ struct asm_vorbis_fmt_blk_v2 fmt;
+ int rc = 0;
+
+ pr_debug("%s :session[%d] bit_stream_fmt[%d] stream_id[%d]\n",
+ __func__, ac->session, cfg->bit_stream_fmt, stream_id);
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+
+ fmt.bit_stream_fmt = cfg->bit_stream_fmt;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s :Comamnd media format update failed %d\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_media_format_block_ape(struct audio_client *ac,
+ struct asm_ape_cfg *cfg, int stream_id)
+{
+ struct asm_ape_fmt_blk_v2 fmt;
+ int rc = 0;
+
+ pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
+ ac->session, cfg->sample_rate, cfg->num_channels);
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+
+ fmt.compatible_version = cfg->compatible_version;
+ fmt.compression_level = cfg->compression_level;
+ fmt.format_flags = cfg->format_flags;
+ fmt.blocks_per_frame = cfg->blocks_per_frame;
+ fmt.final_frame_blocks = cfg->final_frame_blocks;
+ fmt.total_frames = cfg->total_frames;
+ fmt.bits_per_sample = cfg->bits_per_sample;
+ fmt.num_channels = cfg->num_channels;
+ fmt.sample_rate = cfg->sample_rate;
+ fmt.seek_table_present = cfg->seek_table_present;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s :Comamnd media format update failed %d\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+/*
+ * q6asm_media_format_block_dsd- Sends DSD Decoder
+ * configuration parameters
+ *
+ * @ac: Client session handle
+ * @cfg: DSD Media Format Configuration.
+ * @stream_id: stream id of stream to be associated with this session
+ *
+ * Return 0 on success or negative error code on failure
+ */
+int q6asm_media_format_block_dsd(struct audio_client *ac,
+ struct asm_dsd_cfg *cfg, int stream_id)
+{
+ struct asm_dsd_fmt_blk_v2 fmt;
+ int rc;
+
+ pr_debug("%s: session[%d] data_rate[%d] ch[%d]\n", __func__,
+ ac->session, cfg->dsd_data_rate, cfg->num_channels);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+
+ fmt.num_version = cfg->num_version;
+ fmt.is_bitwise_big_endian = cfg->is_bitwise_big_endian;
+ fmt.dsd_channel_block_size = cfg->dsd_channel_block_size;
+ fmt.num_channels = cfg->num_channels;
+ fmt.dsd_data_rate = cfg->dsd_data_rate;
+ atomic_set(&ac->cmd_state, -1);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Command DSD media format update failed, err: %d\n",
+ __func__, rc);
+ goto done;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for DSD FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto done;
+ }
+ return 0;
+done:
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_media_format_block_dsd);
+
+static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id,
+ int param_value, int stream_id)
+{
+ struct asm_dec_ddp_endp_param_v2 ddp_cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d] stream[%d],param_id[%d]param_value[%d]",
+ __func__, ac->session, stream_id, param_id, param_value);
+
+ q6asm_stream_add_hdr(ac, &ddp_cfg.hdr, sizeof(ddp_cfg), TRUE,
+ stream_id);
+ atomic_set(&ac->cmd_state, -1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ q6asm_update_token(&ddp_cfg.hdr.token,
+ ac->session,
+ stream_id,
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+ ddp_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ ddp_cfg.encdec.param_id = param_id;
+ ddp_cfg.encdec.param_size = sizeof(struct asm_dec_ddp_endp_param_v2) -
+ (sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_encdec_param));
+ ddp_cfg.endp_param_value = param_value;
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &ddp_cfg);
+ if (rc < 0) {
+ pr_err("%s: Command opcode[0x%x] failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout opcode[0x%x]\n", __func__,
+ ddp_cfg.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_ds1_set_endp_params(struct audio_client *ac,
+ int param_id, int param_value)
+{
+ return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
+ ac->stream_id);
+}
+
+int q6asm_ds1_set_stream_endp_params(struct audio_client *ac,
+ int param_id, int param_value,
+ int stream_id)
+{
+ return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
+ stream_id);
+}
+
+int q6asm_memory_map(struct audio_client *ac, phys_addr_t buf_add, int dir,
+ uint32_t bufsz, uint32_t bufcnt)
+{
+ struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+ struct avs_shared_map_region_payload *mregions = NULL;
+ struct audio_port_data *port = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ struct asm_buffer_node *buffer_node = NULL;
+ int rc = 0;
+ int cmd_size = 0;
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->mmap_apr == NULL) {
+ pr_err("%s: mmap APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+ buffer_node = kmalloc(sizeof(struct asm_buffer_node), GFP_KERNEL);
+ if (!buffer_node)
+ return -ENOMEM;
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
+ + sizeof(struct avs_shared_map_region_payload) * bufcnt;
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (mmap_region_cmd == NULL) {
+ rc = -EINVAL;
+ kfree(buffer_node);
+ return rc;
+ }
+ mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
+ mmap_region_cmd;
+ q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
+ atomic_set(&ac->mem_state, -1);
+ mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ mmap_regions->num_regions = bufcnt & 0x00ff;
+ mmap_regions->property_flag = 0x00;
+ payload = ((u8 *) mmap_region_cmd +
+ sizeof(struct avs_cmd_shared_mem_map_regions));
+ mregions = (struct avs_shared_map_region_payload *)payload;
+
+ ac->port[dir].tmp_hdl = 0;
+ port = &ac->port[dir];
+ pr_debug("%s: buf_add 0x%pK, bufsz: %d\n", __func__,
+ &buf_add, bufsz);
+ mregions->shm_addr_lsw = lower_32_bits(buf_add);
+ mregions->shm_addr_msw = msm_audio_populate_upper_32_bits(buf_add);
+ mregions->mem_size_bytes = bufsz;
+ ++mregions;
+
+ rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
+ if (rc < 0) {
+ pr_err("%s: mmap op[0x%x]rc[%d]\n", __func__,
+ mmap_regions->hdr.opcode, rc);
+ rc = -EINVAL;
+ kfree(buffer_node);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->mem_wait,
+ (atomic_read(&ac->mem_state) >= 0 &&
+ ac->port[dir].tmp_hdl), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for memory_map\n", __func__);
+ rc = -ETIMEDOUT;
+ kfree(buffer_node);
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->mem_state) > 0) {
+ pr_err("%s: DSP returned error[%s] for memory_map\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->mem_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->mem_state));
+ kfree(buffer_node);
+ goto fail_cmd;
+ }
+ buffer_node->buf_phys_addr = buf_add;
+ buffer_node->mmap_hdl = ac->port[dir].tmp_hdl;
+ list_add_tail(&buffer_node->list, &ac->port[dir].mem_map_handle);
+ ac->port[dir].tmp_hdl = 0;
+ rc = 0;
+
+fail_cmd:
+ kfree(mmap_region_cmd);
+ return rc;
+}
+
+int q6asm_memory_unmap(struct audio_client *ac, phys_addr_t buf_add, int dir)
+{
+ struct avs_cmd_shared_mem_unmap_regions mem_unmap;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+
+ int rc = 0;
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (this_mmap.apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+ q6asm_add_mmaphdr(ac, &mem_unmap.hdr,
+ sizeof(struct avs_cmd_shared_mem_unmap_regions),
+ dir);
+ atomic_set(&ac->mem_state, -1);
+ mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+ mem_unmap.mem_map_handle = 0;
+ list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == buf_add) {
+ pr_debug("%s: Found the element\n", __func__);
+ mem_unmap.mem_map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+ pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+
+ if (mem_unmap.mem_map_handle == 0) {
+ pr_err("%s: Do not send null mem handle to DSP\n", __func__);
+ rc = 0;
+ goto fail_cmd;
+ }
+ rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
+ if (rc < 0) {
+ pr_err("%s: mem_unmap op[0x%x]rc[%d]\n", __func__,
+ mem_unmap.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->mem_wait,
+ (atomic_read(&ac->mem_state) >= 0), 5 * HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ } else if (atomic_read(&ac->mem_state) > 0) {
+ pr_err("%s DSP returned error [%s] map handle 0x%x\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->mem_state)),
+ mem_unmap.mem_map_handle);
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->mem_state));
+ goto fail_cmd;
+ } else if (atomic_read(&ac->unmap_cb_success) == 0) {
+ pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = 0;
+fail_cmd:
+ list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == buf_add) {
+ list_del(&buf_node->list);
+ kfree(buf_node);
+ break;
+ }
+ }
+ return rc;
+}
+
+
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+ uint32_t bufsz, uint32_t bufcnt,
+ bool is_contiguous)
+{
+ struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+ struct avs_shared_map_region_payload *mregions = NULL;
+ struct audio_port_data *port = NULL;
+ struct audio_buffer *ab = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ struct asm_buffer_node *buffer_node = NULL;
+ int rc = 0;
+ int i = 0;
+ uint32_t cmd_size = 0;
+ uint32_t bufcnt_t;
+ uint32_t bufsz_t;
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->mmap_apr == NULL) {
+ pr_err("%s: mmap APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+ bufcnt_t = (is_contiguous) ? 1 : bufcnt;
+ bufsz_t = (is_contiguous) ? (bufsz * bufcnt) : bufsz;
+
+ if (is_contiguous) {
+ /* The size to memory map should be multiple of 4K bytes */
+ bufsz_t = PAGE_ALIGN(bufsz_t);
+ }
+
+ if (bufcnt_t > (UINT_MAX
+ - sizeof(struct avs_cmd_shared_mem_map_regions))
+ / sizeof(struct avs_shared_map_region_payload)) {
+ pr_err("%s: Unsigned Integer Overflow. bufcnt_t = %u\n",
+ __func__, bufcnt_t);
+ return -EINVAL;
+ }
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
+ + (sizeof(struct avs_shared_map_region_payload)
+ * bufcnt_t);
+
+
+ if (bufcnt > (UINT_MAX / sizeof(struct asm_buffer_node))) {
+ pr_err("%s: Unsigned Integer Overflow. bufcnt = %u\n",
+ __func__, bufcnt);
+ return -EINVAL;
+ }
+
+ buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt,
+ GFP_KERNEL);
+ if (!buffer_node)
+ return -ENOMEM;
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (mmap_region_cmd == NULL) {
+ rc = -EINVAL;
+ kfree(buffer_node);
+ return rc;
+ }
+ mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
+ mmap_region_cmd;
+ q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
+ atomic_set(&ac->mem_state, -1);
+ pr_debug("%s: mmap_region=0x%pK token=0x%x\n", __func__,
+ mmap_regions, ((ac->session << 8) | dir));
+
+ mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ mmap_regions->num_regions = bufcnt_t; /*bufcnt & 0x00ff; */
+ mmap_regions->property_flag = 0x00;
+ pr_debug("%s: map_regions->nregions = %d\n", __func__,
+ mmap_regions->num_regions);
+ payload = ((u8 *) mmap_region_cmd +
+ sizeof(struct avs_cmd_shared_mem_map_regions));
+ mregions = (struct avs_shared_map_region_payload *)payload;
+
+ ac->port[dir].tmp_hdl = 0;
+ port = &ac->port[dir];
+ for (i = 0; i < bufcnt_t; i++) {
+ ab = &port->buf[i];
+ mregions->shm_addr_lsw = lower_32_bits(ab->phys);
+ mregions->shm_addr_msw =
+ msm_audio_populate_upper_32_bits(ab->phys);
+ mregions->mem_size_bytes = bufsz_t;
+ ++mregions;
+ }
+
+ rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
+ if (rc < 0) {
+ pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+ mmap_regions->hdr.opcode, rc);
+ rc = -EINVAL;
+ kfree(buffer_node);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->mem_wait,
+ (atomic_read(&ac->mem_state) >= 0)
+ , 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for memory_map\n", __func__);
+ rc = -ETIMEDOUT;
+ kfree(buffer_node);
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->mem_state) > 0) {
+ pr_err("%s DSP returned error for memory_map [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->mem_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->mem_state));
+ kfree(buffer_node);
+ goto fail_cmd;
+ }
+ mutex_lock(&ac->cmd_lock);
+
+ for (i = 0; i < bufcnt; i++) {
+ ab = &port->buf[i];
+ buffer_node[i].buf_phys_addr = ab->phys;
+ buffer_node[i].mmap_hdl = ac->port[dir].tmp_hdl;
+ list_add_tail(&buffer_node[i].list,
+ &ac->port[dir].mem_map_handle);
+ pr_debug("%s: i=%d, bufadd[i] = 0x%pK, maphdl[i] = 0x%x\n",
+ __func__, i, &buffer_node[i].buf_phys_addr,
+ buffer_node[i].mmap_hdl);
+ }
+ ac->port[dir].tmp_hdl = 0;
+ mutex_unlock(&ac->cmd_lock);
+ rc = 0;
+fail_cmd:
+ kfree(mmap_region_cmd);
+ return rc;
+}
+
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir)
+{
+ struct avs_cmd_shared_mem_unmap_regions mem_unmap;
+ struct audio_port_data *port = NULL;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+ phys_addr_t buf_add;
+ int rc = 0;
+ int cmd_size = 0;
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->mmap_apr == NULL) {
+ pr_err("%s: mmap APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+ q6asm_add_mmaphdr(ac, &mem_unmap.hdr, cmd_size, dir);
+ atomic_set(&ac->mem_state, -1);
+ port = &ac->port[dir];
+ buf_add = port->buf->phys;
+ mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+ mem_unmap.mem_map_handle = 0;
+ list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == buf_add) {
+ pr_debug("%s: Found the element\n", __func__);
+ mem_unmap.mem_map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+
+ pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+
+ if (mem_unmap.mem_map_handle == 0) {
+ pr_err("%s: Do not send null mem handle to DSP\n", __func__);
+ rc = 0;
+ goto fail_cmd;
+ }
+ rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
+ if (rc < 0) {
+ pr_err("mmap_regions op[0x%x]rc[%d]\n",
+ mem_unmap.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->mem_wait,
+ (atomic_read(&ac->mem_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ } else if (atomic_read(&ac->mem_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->mem_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->mem_state));
+ goto fail_cmd;
+ } else if (atomic_read(&ac->unmap_cb_success) == 0) {
+ pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+
+fail_cmd:
+ list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == buf_add) {
+ list_del(&buf_node->list);
+ kfree(buf_node);
+ break;
+ }
+ }
+ return rc;
+}
+
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
+{
+ struct asm_volume_ctrl_multichannel_gain multi_ch_gain;
+ int sz = 0;
+ int rc = 0;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ memset(&multi_ch_gain, 0, sizeof(multi_ch_gain));
+ sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
+ q6asm_add_hdr_async(ac, &multi_ch_gain.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ multi_ch_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ multi_ch_gain.param.data_payload_addr_lsw = 0;
+ multi_ch_gain.param.data_payload_addr_msw = 0;
+ multi_ch_gain.param.mem_map_handle = 0;
+ multi_ch_gain.param.data_payload_size = sizeof(multi_ch_gain) -
+ sizeof(multi_ch_gain.hdr) - sizeof(multi_ch_gain.param);
+ multi_ch_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+ multi_ch_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
+ multi_ch_gain.data.param_size = multi_ch_gain.param.data_payload_size -
+ sizeof(multi_ch_gain.data);
+ multi_ch_gain.data.reserved = 0;
+ multi_ch_gain.gain_data[0].channeltype = PCM_CHANNEL_FL;
+ multi_ch_gain.gain_data[0].gain = left_gain << 15;
+ multi_ch_gain.gain_data[1].channeltype = PCM_CHANNEL_FR;
+ multi_ch_gain.gain_data[1].gain = right_gain << 15;
+ multi_ch_gain.num_channels = 2;
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &multi_ch_gain);
+ if (rc < 0) {
+ pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+ __func__, multi_ch_gain.data.param_id, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+ multi_ch_gain.data.param_id);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s] , set-params paramid[0x%x]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)),
+ multi_ch_gain.data.param_id);
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+/*
+ * q6asm_set_multich_gain: set multiple channel gains on an ASM session
+ * @ac: audio client handle
+ * @channels: number of channels caller intends to set gains
+ * @gains: list of gains of audio channels
+ * @ch_map: list of channel mapping. Only valid if use_default is false
+ * @use_default: flag to indicate whether to use default mapping
+ */
+int q6asm_set_multich_gain(struct audio_client *ac, uint32_t channels,
+ uint32_t *gains, uint8_t *ch_map, bool use_default)
+{
+ struct asm_volume_ctrl_multichannel_gain multich_gain;
+ int sz = 0;
+ int rc = 0;
+ int i;
+ u8 default_chmap[VOLUME_CONTROL_MAX_CHANNELS];
+
+ if (ac == NULL) {
+ pr_err("%s: ac is NULL\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+ if (ac->apr == NULL) {
+ dev_err(ac->dev, "%s: AC APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+ if (gains == NULL) {
+ dev_err(ac->dev, "%s: gain_list is NULL\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+ if (channels > VOLUME_CONTROL_MAX_CHANNELS) {
+ dev_err(ac->dev, "%s: Invalid channel count %d\n",
+ __func__, channels);
+ rc = -EINVAL;
+ goto done;
+ }
+ if (!use_default && ch_map == NULL) {
+ dev_err(ac->dev, "%s: NULL channel map\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ memset(&multich_gain, 0, sizeof(multich_gain));
+ sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
+ q6asm_add_hdr_async(ac, &multich_gain.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, 1);
+ multich_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ multich_gain.param.data_payload_addr_lsw = 0;
+ multich_gain.param.data_payload_addr_msw = 0;
+ multich_gain.param.mem_map_handle = 0;
+ multich_gain.param.data_payload_size = sizeof(multich_gain) -
+ sizeof(multich_gain.hdr) - sizeof(multich_gain.param);
+ multich_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+ multich_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
+ multich_gain.data.param_size = multich_gain.param.data_payload_size -
+ sizeof(multich_gain.data);
+ multich_gain.data.reserved = 0;
+
+ if (use_default) {
+ rc = q6asm_map_channels(default_chmap, channels, false);
+ if (rc < 0)
+ goto done;
+ for (i = 0; i < channels; i++) {
+ multich_gain.gain_data[i].channeltype =
+ default_chmap[i];
+ multich_gain.gain_data[i].gain = gains[i] << 15;
+ }
+ } else {
+ for (i = 0; i < channels; i++) {
+ multich_gain.gain_data[i].channeltype = ch_map[i];
+ multich_gain.gain_data[i].gain = gains[i] << 15;
+ }
+ }
+ multich_gain.num_channels = channels;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &multich_gain);
+ if (rc < 0) {
+ pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+ __func__, multich_gain.data.param_id, rc);
+ goto done;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) <= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+ multich_gain.data.param_id);
+ rc = -EINVAL;
+ goto done;
+ }
+ if (atomic_read(&ac->cmd_state) < 0) {
+ pr_err("%s: DSP returned error[%d] , set-params paramid[0x%x]\n",
+ __func__, atomic_read(&ac->cmd_state),
+ multich_gain.data.param_id);
+ rc = -EINVAL;
+ goto done;
+ }
+ rc = 0;
+done:
+ return rc;
+}
+
+int q6asm_set_mute(struct audio_client *ac, int muteflag)
+{
+ struct asm_volume_ctrl_mute_config mute;
+ int sz = 0;
+ int rc = 0;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ sz = sizeof(struct asm_volume_ctrl_mute_config);
+ q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ mute.param.data_payload_addr_lsw = 0;
+ mute.param.data_payload_addr_msw = 0;
+ mute.param.mem_map_handle = 0;
+ mute.param.data_payload_size = sizeof(mute) -
+ sizeof(mute.hdr) - sizeof(mute.param);
+ mute.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+ mute.data.param_id = ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG;
+ mute.data.param_size = mute.param.data_payload_size - sizeof(mute.data);
+ mute.data.reserved = 0;
+ mute.mute_flag = muteflag;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &mute);
+ if (rc < 0) {
+ pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+ __func__, mute.data.param_id, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+ mute.data.param_id);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)),
+ mute.data.param_id);
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_dts_eagle_set(struct audio_client *ac, int param_id, uint32_t size,
+ void *data, struct param_outband *po, int m_id)
+{
+ int rc = 0, *ob_params = NULL;
+ uint32_t sz = sizeof(struct asm_dts_eagle_param) + (po ? 0 : size);
+ struct asm_dts_eagle_param *ad;
+
+ if (!ac || ac->apr == NULL || (size == 0) || !data) {
+ pr_err("DTS_EAGLE_ASM - %s: APR handle NULL, invalid size %u or pointer %pK.\n",
+ __func__, size, data);
+ return -EINVAL;
+ }
+
+ ad = kzalloc(sz, GFP_KERNEL);
+ if (!ad)
+ return -ENOMEM;
+
+ pr_debug("DTS_EAGLE_ASM - %s: ac %pK param_id 0x%x size %u data %pK m_id 0x%x\n",
+ __func__, ac, param_id, size, data, m_id);
+ q6asm_add_hdr_async(ac, &ad->hdr, sz, 1);
+ ad->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ ad->param.data_payload_addr_lsw = 0;
+ ad->param.data_payload_addr_msw = 0;
+
+ ad->param.mem_map_handle = 0;
+ ad->param.data_payload_size = size +
+ sizeof(struct asm_stream_param_data_v2);
+ ad->data.module_id = m_id;
+ ad->data.param_id = param_id;
+ ad->data.param_size = size;
+ ad->data.reserved = 0;
+ atomic_set(&ac->cmd_state, -1);
+
+ if (po) {
+ struct list_head *ptr, *next;
+ struct asm_buffer_node *node;
+
+ pr_debug("DTS_EAGLE_ASM - %s: using out of band memory (virtual %pK, physical %lu)\n",
+ __func__, po->kvaddr, (long)po->paddr);
+ ad->param.data_payload_addr_lsw = lower_32_bits(po->paddr);
+ ad->param.data_payload_addr_msw =
+ msm_audio_populate_upper_32_bits(po->paddr);
+ list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+ node = list_entry(ptr, struct asm_buffer_node, list);
+ if (node->buf_phys_addr == po->paddr) {
+ ad->param.mem_map_handle = node->mmap_hdl;
+ break;
+ }
+ }
+ if (ad->param.mem_map_handle == 0) {
+ pr_err("DTS_EAGLE_ASM - %s: mem map handle not found\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ /* check for integer overflow */
+ if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
+ rc = -EINVAL;
+ if ((rc < 0) || (size + APR_CMD_OB_HDR_SZ > po->size)) {
+ pr_err("DTS_EAGLE_ASM - %s: ion alloc of size %zu too small for size requested %u\n",
+ __func__, po->size, size + APR_CMD_OB_HDR_SZ);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ ob_params = (int *)po->kvaddr;
+ *ob_params++ = m_id;
+ *ob_params++ = param_id;
+ *ob_params++ = size;
+ memcpy(ob_params, data, size);
+ } else {
+ pr_debug("DTS_EAGLE_ASM - %s: using in band\n", __func__);
+ memcpy(((char *)ad) + sizeof(struct asm_dts_eagle_param),
+ data, size);
+ }
+ rc = apr_send_pkt(ac->apr, (uint32_t *)ad);
+ if (rc < 0) {
+ pr_err("DTS_EAGLE_ASM - %s: set-params send failed paramid[0x%x]\n",
+ __func__, ad->data.param_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
+ if (!rc) {
+ pr_err("DTS_EAGLE_ASM - %s: timeout, set-params paramid[0x%x]\n",
+ __func__, ad->data.param_id);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ kfree(ad);
+ return rc;
+}
+
+int q6asm_dts_eagle_get(struct audio_client *ac, int param_id, uint32_t size,
+ void *data, struct param_outband *po, int m_id)
+{
+ struct asm_dts_eagle_param_get *ad;
+ int rc = 0, *ob_params = NULL;
+ uint32_t sz = sizeof(struct asm_dts_eagle_param) + APR_CMD_GET_HDR_SZ +
+ (po ? 0 : size);
+
+ if (!ac || ac->apr == NULL || (size == 0) || !data) {
+ pr_err("DTS_EAGLE_ASM - %s: APR handle NULL, invalid size %u or pointer %pK\n",
+ __func__, size, data);
+ return -EINVAL;
+ }
+ ad = kzalloc(sz, GFP_KERNEL);
+ if (!ad)
+ return -ENOMEM;
+
+ pr_debug("DTS_EAGLE_ASM - %s: ac %pK param_id 0x%x size %u data %pK m_id 0x%x\n",
+ __func__, ac, param_id, size, data, m_id);
+ q6asm_add_hdr(ac, &ad->hdr, sz, TRUE);
+ ad->hdr.opcode = ASM_STREAM_CMD_GET_PP_PARAMS_V2;
+ ad->param.data_payload_addr_lsw = 0;
+ ad->param.data_payload_addr_msw = 0;
+ ad->param.mem_map_handle = 0;
+ ad->param.module_id = m_id;
+ ad->param.param_id = param_id;
+ ad->param.param_max_size = size + APR_CMD_GET_HDR_SZ;
+ ad->param.reserved = 0;
+ atomic_set(&ac->cmd_state, -1);
+
+ generic_get_data = kzalloc(size + sizeof(struct generic_get_data_),
+ GFP_KERNEL);
+ if (!generic_get_data) {
+ rc = -ENOMEM;
+ goto fail_cmd;
+ }
+
+ if (po) {
+ struct list_head *ptr, *next;
+ struct asm_buffer_node *node;
+
+ pr_debug("DTS_EAGLE_ASM - %s: using out of band memory (virtual %pK, physical %lu)\n",
+ __func__, po->kvaddr, (long)po->paddr);
+ ad->param.data_payload_addr_lsw = lower_32_bits(po->paddr);
+ ad->param.data_payload_addr_msw =
+ msm_audio_populate_upper_32_bits(po->paddr);
+ list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+ node = list_entry(ptr, struct asm_buffer_node, list);
+ if (node->buf_phys_addr == po->paddr) {
+ ad->param.mem_map_handle = node->mmap_hdl;
+ break;
+ }
+ }
+ if (ad->param.mem_map_handle == 0) {
+ pr_err("DTS_EAGLE_ASM - %s: mem map handle not found\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ /* check for integer overflow */
+ if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
+ rc = -EINVAL;
+ if ((rc < 0) || (size + APR_CMD_OB_HDR_SZ > po->size)) {
+ pr_err("DTS_EAGLE_ASM - %s: ion alloc of size %zu too small for size requested %u\n",
+ __func__, po->size, size + APR_CMD_OB_HDR_SZ);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ ob_params = (int *)po->kvaddr;
+ *ob_params++ = m_id;
+ *ob_params++ = param_id;
+ *ob_params++ = size;
+ generic_get_data->is_inband = 0;
+ } else {
+ pr_debug("DTS_EAGLE_ASM - %s: using in band\n", __func__);
+ generic_get_data->is_inband = 1;
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *)ad);
+ if (rc < 0) {
+ pr_err("DTS_EAGLE_ASM - %s: Commmand 0x%x failed\n", __func__,
+ ad->hdr.opcode);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
+ if (!rc) {
+ pr_err("DTS_EAGLE_ASM - %s: timeout in get\n",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+
+ if (generic_get_data->valid) {
+ rc = 0;
+ memcpy(data, po ? ob_params : generic_get_data->ints, size);
+ } else {
+ rc = -EINVAL;
+ pr_err("DTS_EAGLE_ASM - %s: EAGLE get params problem getting data - check callback error value\n",
+ __func__);
+ }
+fail_cmd:
+ kfree(ad);
+ kfree(generic_get_data);
+ generic_get_data = NULL;
+ return rc;
+}
+
+static int __q6asm_set_volume(struct audio_client *ac, int volume, int instance)
+{
+ struct asm_volume_ctrl_master_gain vol;
+ int sz = 0;
+ int rc = 0;
+ int module_id;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ switch (instance) {
+ case SOFT_VOLUME_INSTANCE_2:
+ module_id = ASM_MODULE_ID_VOL_CTRL2;
+ break;
+ case SOFT_VOLUME_INSTANCE_1:
+ default:
+ module_id = ASM_MODULE_ID_VOL_CTRL;
+ break;
+ }
+
+ sz = sizeof(struct asm_volume_ctrl_master_gain);
+ q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ vol.param.data_payload_addr_lsw = 0;
+ vol.param.data_payload_addr_msw = 0;
+ vol.param.mem_map_handle = 0;
+ vol.param.data_payload_size = sizeof(vol) -
+ sizeof(vol.hdr) - sizeof(vol.param);
+ vol.data.module_id = module_id;
+ vol.data.param_id = ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN;
+ vol.data.param_size = vol.param.data_payload_size - sizeof(vol.data);
+ vol.data.reserved = 0;
+ vol.master_gain = volume;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &vol);
+ if (rc < 0) {
+ pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+ __func__, vol.data.param_id, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+ vol.data.param_id);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)),
+ vol.data.param_id);
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_set_volume(struct audio_client *ac, int volume)
+{
+ return __q6asm_set_volume(ac, volume, SOFT_VOLUME_INSTANCE_1);
+}
+
+int q6asm_set_volume_v2(struct audio_client *ac, int volume, int instance)
+{
+ return __q6asm_set_volume(ac, volume, instance);
+}
+
+int q6asm_set_softpause(struct audio_client *ac,
+ struct asm_softpause_params *pause_param)
+{
+ struct asm_soft_pause_params softpause;
+ int sz = 0;
+ int rc = 0;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ sz = sizeof(struct asm_soft_pause_params);
+ q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+
+ softpause.param.data_payload_addr_lsw = 0;
+ softpause.param.data_payload_addr_msw = 0;
+ softpause.param.mem_map_handle = 0;
+ softpause.param.data_payload_size = sizeof(softpause) -
+ sizeof(softpause.hdr) - sizeof(softpause.param);
+ softpause.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+ softpause.data.param_id = ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS;
+ softpause.data.param_size = softpause.param.data_payload_size -
+ sizeof(softpause.data);
+ softpause.data.reserved = 0;
+ softpause.enable_flag = pause_param->enable;
+ softpause.period = pause_param->period;
+ softpause.step = pause_param->step;
+ softpause.ramping_curve = pause_param->rampingcurve;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &softpause);
+ if (rc < 0) {
+ pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+ __func__, softpause.data.param_id, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+ softpause.data.param_id);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)),
+ softpause.data.param_id);
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_set_softvolume(struct audio_client *ac,
+ struct asm_softvolume_params *softvol_param,
+ int instance)
+{
+ struct asm_soft_step_volume_params softvol;
+ int sz = 0;
+ int rc = 0;
+ int module_id;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ switch (instance) {
+ case SOFT_VOLUME_INSTANCE_2:
+ module_id = ASM_MODULE_ID_VOL_CTRL2;
+ break;
+ case SOFT_VOLUME_INSTANCE_1:
+ default:
+ module_id = ASM_MODULE_ID_VOL_CTRL;
+ break;
+ }
+
+ sz = sizeof(struct asm_soft_step_volume_params);
+ q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ softvol.param.data_payload_addr_lsw = 0;
+ softvol.param.data_payload_addr_msw = 0;
+ softvol.param.mem_map_handle = 0;
+ softvol.param.data_payload_size = sizeof(softvol) -
+ sizeof(softvol.hdr) - sizeof(softvol.param);
+ softvol.data.module_id = module_id;
+ softvol.data.param_id = ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
+ softvol.data.param_size = softvol.param.data_payload_size -
+ sizeof(softvol.data);
+ softvol.data.reserved = 0;
+ softvol.period = softvol_param->period;
+ softvol.step = softvol_param->step;
+ softvol.ramping_curve = softvol_param->rampingcurve;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &softvol);
+ if (rc < 0) {
+ pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+ __func__, softvol.data.param_id, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+ softvol.data.param_id);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)),
+ softvol.data.param_id);
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_set_softvolume(struct audio_client *ac,
+ struct asm_softvolume_params *softvol_param)
+{
+ return __q6asm_set_softvolume(ac, softvol_param,
+ SOFT_VOLUME_INSTANCE_1);
+}
+
+int q6asm_set_softvolume_v2(struct audio_client *ac,
+ struct asm_softvolume_params *softvol_param,
+ int instance)
+{
+ return __q6asm_set_softvolume(ac, softvol_param, instance);
+}
+
+int q6asm_equalizer(struct audio_client *ac, void *eq_p)
+{
+ struct asm_eq_params eq;
+ struct msm_audio_eq_stream_config *eq_params = NULL;
+ int i = 0;
+ int sz = 0;
+ int rc = 0;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (eq_p == NULL) {
+ pr_err("%s: [%d]: Invalid Eq param\n", __func__, ac->session);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ sz = sizeof(struct asm_eq_params);
+ eq_params = (struct msm_audio_eq_stream_config *) eq_p;
+ q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ eq.param.data_payload_addr_lsw = 0;
+ eq.param.data_payload_addr_msw = 0;
+ eq.param.mem_map_handle = 0;
+ eq.param.data_payload_size = sizeof(eq) -
+ sizeof(eq.hdr) - sizeof(eq.param);
+ eq.data.module_id = ASM_MODULE_ID_EQUALIZER;
+ eq.data.param_id = ASM_PARAM_ID_EQUALIZER_PARAMETERS;
+ eq.data.param_size = eq.param.data_payload_size - sizeof(eq.data);
+ eq.enable_flag = eq_params->enable;
+ eq.num_bands = eq_params->num_bands;
+
+ pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
+ eq_params->num_bands);
+ for (i = 0; i < eq_params->num_bands; i++) {
+ eq.eq_bands[i].band_idx =
+ eq_params->eq_bands[i].band_idx;
+ eq.eq_bands[i].filterype =
+ eq_params->eq_bands[i].filter_type;
+ eq.eq_bands[i].center_freq_hz =
+ eq_params->eq_bands[i].center_freq_hz;
+ eq.eq_bands[i].filter_gain =
+ eq_params->eq_bands[i].filter_gain;
+ eq.eq_bands[i].q_factor =
+ eq_params->eq_bands[i].q_factor;
+ pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
+ eq_params->eq_bands[i].filter_type, i);
+ pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
+ eq_params->eq_bands[i].center_freq_hz, i);
+ pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
+ eq_params->eq_bands[i].filter_gain, i);
+ pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
+ eq_params->eq_bands[i].q_factor, i);
+ }
+ rc = apr_send_pkt(ac->apr, (uint32_t *)&eq);
+ if (rc < 0) {
+ pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+ __func__, eq.data.param_id, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+ eq.data.param_id);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)),
+ eq.data.param_id);
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+static int __q6asm_read(struct audio_client *ac, bool is_custom_len_reqd,
+ int len)
+{
+ struct asm_data_cmd_read_v2 read;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+ struct audio_buffer *ab;
+ int dsp_buf;
+ struct audio_port_data *port;
+ int rc;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ac->io_mode & SYNC_IO_MODE) {
+ port = &ac->port[OUT];
+
+ q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
+
+ mutex_lock(&port->lock);
+
+ dsp_buf = port->dsp_buf;
+ if (port->buf == NULL) {
+ pr_err("%s: buf is NULL\n", __func__);
+ mutex_unlock(&port->lock);
+ return -EINVAL;
+ }
+ ab = &port->buf[dsp_buf];
+
+ dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
+ __func__,
+ ac->session,
+ dsp_buf,
+ port->buf[dsp_buf].data,
+ port->cpu_buf,
+ &port->buf[port->cpu_buf].phys);
+
+ read.hdr.opcode = ASM_DATA_CMD_READ_V2;
+ read.buf_addr_lsw = lower_32_bits(ab->phys);
+ read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
+
+ list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == ab->phys)
+ read.mem_map_handle = buf_node->mmap_hdl;
+ }
+ dev_vdbg(ac->dev, "memory_map handle in q6asm_read: [%0x]:",
+ read.mem_map_handle);
+ read.buf_size = is_custom_len_reqd ? len : ab->size;
+ read.seq_id = port->dsp_buf;
+ q6asm_update_token(&read.hdr.token,
+ 0, /* Session ID is NA */
+ 0, /* Stream ID is NA */
+ port->dsp_buf,
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+ port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
+ port->max_buf_cnt);
+ mutex_unlock(&port->lock);
+ dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
+ __func__, &ab->phys, read.hdr.token,
+ read.seq_id);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+ if (rc < 0) {
+ pr_err("%s: read op[0x%x]rc[%d]\n",
+ __func__, read.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+ }
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_read(struct audio_client *ac)
+{
+ return __q6asm_read(ac, false/*is_custom_len_reqd*/, 0);
+}
+int q6asm_read_v2(struct audio_client *ac, uint32_t len)
+{
+ return __q6asm_read(ac, true /*is_custom_len_reqd*/, len);
+}
+
+int q6asm_read_nolock(struct audio_client *ac)
+{
+ struct asm_data_cmd_read_v2 read;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+ struct audio_buffer *ab;
+ int dsp_buf;
+ struct audio_port_data *port;
+ int rc;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ac->io_mode & SYNC_IO_MODE) {
+ port = &ac->port[OUT];
+
+ q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+
+ dsp_buf = port->dsp_buf;
+ ab = &port->buf[dsp_buf];
+
+ dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
+ __func__,
+ ac->session,
+ dsp_buf,
+ port->buf[dsp_buf].data,
+ port->cpu_buf,
+ &port->buf[port->cpu_buf].phys);
+
+ read.hdr.opcode = ASM_DATA_CMD_READ_V2;
+ read.buf_addr_lsw = lower_32_bits(ab->phys);
+ read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
+ read.buf_size = ab->size;
+ read.seq_id = port->dsp_buf;
+ q6asm_update_token(&read.hdr.token,
+ 0, /* Session ID is NA */
+ 0, /* Stream ID is NA */
+ port->dsp_buf,
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+
+ list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == ab->phys) {
+ read.mem_map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+
+ port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
+ port->max_buf_cnt);
+ dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
+ __func__, &ab->phys, read.hdr.token,
+ read.seq_id);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+ if (rc < 0) {
+ pr_err("%s: read op[0x%x]rc[%d]\n",
+ __func__, read.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+ }
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_async_write(struct audio_client *ac,
+ struct audio_aio_write_param *param)
+{
+ int rc = 0;
+ struct asm_data_cmd_write_v2 write;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+ struct audio_buffer *ab;
+ struct audio_port_data *port;
+ phys_addr_t lbuf_phys_addr;
+ u32 liomode;
+ u32 io_compressed;
+ u32 io_compressed_stream;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6asm_stream_add_hdr_async(
+ ac, &write.hdr, sizeof(write), FALSE, ac->stream_id);
+ port = &ac->port[IN];
+ ab = &port->buf[port->dsp_buf];
+
+ /* Pass session id as token for AIO scheme */
+ write.hdr.token = param->uid;
+ write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
+ write.buf_addr_lsw = lower_32_bits(param->paddr);
+ write.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
+ write.buf_size = param->len;
+ write.timestamp_msw = param->msw_ts;
+ write.timestamp_lsw = param->lsw_ts;
+ liomode = (ASYNC_IO_MODE | NT_MODE);
+ io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
+ io_compressed_stream = (ASYNC_IO_MODE | COMPRESSED_STREAM_IO);
+
+ if (ac->io_mode == liomode)
+ lbuf_phys_addr = (param->paddr - 32);
+ else if (ac->io_mode == io_compressed ||
+ ac->io_mode == io_compressed_stream)
+ lbuf_phys_addr = (param->paddr - param->metadata_len);
+ else
+ lbuf_phys_addr = param->paddr;
+
+ dev_vdbg(ac->dev, "%s: token[0x%x], buf_addr[%pK], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_phys_addr: 0x[%pK]\n",
+ __func__,
+ write.hdr.token, ¶m->paddr,
+ write.buf_size, write.timestamp_msw,
+ write.timestamp_lsw, &lbuf_phys_addr);
+
+ /* Use 0xFF00 for disabling timestamps */
+ if (param->flags == 0xFF00)
+ write.flags = (0x00000000 | (param->flags & 0x800000FF));
+ else
+ write.flags = (0x80000000 | param->flags);
+ write.flags |= param->last_buffer << ASM_SHIFT_LAST_BUFFER_FLAG;
+ write.seq_id = param->uid;
+ list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == lbuf_phys_addr) {
+ write.mem_map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+ if (rc < 0) {
+ pr_err("%s: write op[0x%x]rc[%d]\n", __func__,
+ write.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_async_read(struct audio_client *ac,
+ struct audio_aio_read_param *param)
+{
+ int rc = 0;
+ struct asm_data_cmd_read_v2 read;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+ phys_addr_t lbuf_phys_addr;
+ u32 liomode;
+ u32 io_compressed;
+ int dir = 0;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+ /* Pass session id as token for AIO scheme */
+ read.hdr.token = param->uid;
+ read.hdr.opcode = ASM_DATA_CMD_READ_V2;
+ read.buf_addr_lsw = lower_32_bits(param->paddr);
+ read.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
+ read.buf_size = param->len;
+ read.seq_id = param->uid;
+ liomode = (NT_MODE | ASYNC_IO_MODE);
+ io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
+ if (ac->io_mode == liomode) {
+ lbuf_phys_addr = (param->paddr - 32);
+ /*legacy wma driver case*/
+ dir = IN;
+ } else if (ac->io_mode == io_compressed) {
+ lbuf_phys_addr = (param->paddr - 64);
+ dir = OUT;
+ } else {
+ if (param->flags & COMPRESSED_TIMESTAMP_FLAG)
+ lbuf_phys_addr = param->paddr -
+ sizeof(struct snd_codec_metadata);
+ else
+ lbuf_phys_addr = param->paddr;
+ dir = OUT;
+ }
+
+ list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_phys_addr == lbuf_phys_addr) {
+ read.mem_map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+ if (rc < 0) {
+ pr_err("%s: read op[0x%x]rc[%d]\n", __func__,
+ read.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t flags)
+{
+ int rc = 0;
+ struct asm_data_cmd_write_v2 write;
+ struct asm_buffer_node *buf_node = NULL;
+ struct audio_port_data *port;
+ struct audio_buffer *ab;
+ int dsp_buf = 0;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
+ __func__, ac->session, len);
+ if (ac->io_mode & SYNC_IO_MODE) {
+ port = &ac->port[IN];
+
+ q6asm_add_hdr(ac, &write.hdr, sizeof(write),
+ FALSE);
+ mutex_lock(&port->lock);
+
+ dsp_buf = port->dsp_buf;
+ ab = &port->buf[dsp_buf];
+
+ q6asm_update_token(&write.hdr.token,
+ 0, /* Session ID is NA */
+ 0, /* Stream ID is NA */
+ port->dsp_buf,
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+ write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
+ write.buf_addr_lsw = lower_32_bits(ab->phys);
+ write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
+ write.buf_size = len;
+ write.seq_id = port->dsp_buf;
+ write.timestamp_lsw = lsw_ts;
+ write.timestamp_msw = msw_ts;
+ /* Use 0xFF00 for disabling timestamps */
+ if (flags == 0xFF00)
+ write.flags = (0x00000000 | (flags & 0x800000FF));
+ else
+ write.flags = (0x80000000 | flags);
+ port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
+ port->max_buf_cnt);
+ buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
+ struct asm_buffer_node,
+ list);
+ write.mem_map_handle = buf_node->mmap_hdl;
+
+ dev_vdbg(ac->dev, "%s: ab->phys[%pK]bufadd[0x%x] token[0x%x]buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
+ , __func__,
+ &ab->phys,
+ write.buf_addr_lsw,
+ write.hdr.token,
+ write.seq_id,
+ write.buf_size,
+ write.mem_map_handle);
+ mutex_unlock(&port->lock);
+
+ config_debug_fs_write(ab);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+ if (rc < 0) {
+ pr_err("%s: write op[0x%x]rc[%d]\n",
+ __func__, write.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+ }
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t flags)
+{
+ int rc = 0;
+ struct asm_data_cmd_write_v2 write;
+ struct asm_buffer_node *buf_node = NULL;
+ struct audio_port_data *port;
+ struct audio_buffer *ab;
+ int dsp_buf = 0;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
+ __func__, ac->session, len);
+ if (ac->io_mode & SYNC_IO_MODE) {
+ port = &ac->port[IN];
+
+ q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
+ FALSE);
+
+ dsp_buf = port->dsp_buf;
+ ab = &port->buf[dsp_buf];
+
+ q6asm_update_token(&write.hdr.token,
+ 0, /* Session ID is NA */
+ 0, /* Stream ID is NA */
+ port->dsp_buf,
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+
+ write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
+ write.buf_addr_lsw = lower_32_bits(ab->phys);
+ write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
+ write.buf_size = len;
+ write.seq_id = port->dsp_buf;
+ write.timestamp_lsw = lsw_ts;
+ write.timestamp_msw = msw_ts;
+ buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
+ struct asm_buffer_node,
+ list);
+ write.mem_map_handle = buf_node->mmap_hdl;
+ /* Use 0xFF00 for disabling timestamps */
+ if (flags == 0xFF00)
+ write.flags = (0x00000000 | (flags & 0x800000FF));
+ else
+ write.flags = (0x80000000 | flags);
+ port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
+ port->max_buf_cnt);
+
+ dev_vdbg(ac->dev, "%s: ab->phys[%pK]bufadd[0x%x]token[0x%x] buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
+ , __func__,
+ &ab->phys,
+ write.buf_addr_lsw,
+ write.hdr.token,
+ write.seq_id,
+ write.buf_size,
+ write.mem_map_handle);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+ if (rc < 0) {
+ pr_err("%s: write op[0x%x]rc[%d]\n",
+ __func__, write.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+ }
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp)
+{
+ struct asm_mtmx_strtr_get_params mtmx_params;
+ int rc;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (tstamp == NULL) {
+ pr_err("%s: tstamp NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6asm_add_hdr(ac, &mtmx_params.hdr, sizeof(mtmx_params), TRUE);
+ mtmx_params.hdr.opcode = ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2;
+ mtmx_params.param_info.data_payload_addr_lsw = 0;
+ mtmx_params.param_info.data_payload_addr_msw = 0;
+ mtmx_params.param_info.mem_map_handle = 0;
+ mtmx_params.param_info.direction = (ac->io_mode & TUN_READ_IO_MODE
+ ? 1 : 0);
+ mtmx_params.param_info.module_id =
+ ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
+ mtmx_params.param_info.param_id =
+ ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3;
+ mtmx_params.param_info.param_max_size =
+ sizeof(struct asm_stream_param_data_v2) +
+ sizeof(struct asm_session_mtmx_strtr_param_session_time_v3_t);
+ atomic_set(&ac->time_flag, 1);
+
+ dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
+ ac->session, mtmx_params.hdr.opcode);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &mtmx_params);
+ if (rc < 0) {
+ pr_err("%s: Commmand 0x%x failed %d\n", __func__,
+ mtmx_params.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->time_wait,
+ (atomic_read(&ac->time_flag) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout in getting session time from DSP\n",
+ __func__);
+ goto fail_cmd;
+ }
+
+ *tstamp = ac->time_stamp;
+ return 0;
+
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp)
+{
+ struct apr_hdr hdr;
+ int rc;
+
+ if (ac == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (tstamp == NULL) {
+ pr_err("%s: tstamp NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+ hdr.opcode = ASM_SESSION_CMD_GET_SESSIONTIME_V3;
+ atomic_set(&ac->time_flag, 1);
+
+ dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
+ ac->session,
+ hdr.opcode);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("%s: Commmand 0x%x failed %d\n",
+ __func__, hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->time_wait,
+ (atomic_read(&ac->time_flag) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout in getting session time from DSP\n",
+ __func__);
+ goto fail_cmd;
+ }
+
+ *tstamp = ac->time_stamp;
+ return 0;
+
+fail_cmd:
+ return -EINVAL;
+}
+
+
+int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
+ uint32_t params_length)
+{
+ char *asm_params = NULL;
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 payload_params;
+ int sz, rc;
+
+ pr_debug("%s:\n", __func__);
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (params == NULL) {
+ pr_err("%s: params NULL\n", __func__);
+ return -EINVAL;
+ }
+ sz = sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_pp_params_v2) +
+ params_length;
+ asm_params = kzalloc(sz, GFP_KERNEL);
+ if (!asm_params) {
+ pr_err("%s, asm params memory alloc failed", __func__);
+ return -ENOMEM;
+ }
+ q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_pp_params_v2) +
+ params_length), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ payload_params.data_payload_addr_lsw = 0;
+ payload_params.data_payload_addr_msw = 0;
+ payload_params.mem_map_handle = 0;
+ payload_params.data_payload_size = params_length;
+ memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
+ memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
+ sizeof(struct asm_stream_cmd_set_pp_params_v2));
+ memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_pp_params_v2)),
+ params, params_length);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
+ if (rc < 0) {
+ pr_err("%s: audio effects set-params send failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_send_param;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, audio effects set-params\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_send_param;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s] set-params\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_send_param;
+ }
+
+ rc = 0;
+fail_send_param:
+ kfree(asm_params);
+ return rc;
+}
+
+int q6asm_send_mtmx_strtr_window(struct audio_client *ac,
+ struct asm_session_mtmx_strtr_param_window_v2_t *window_param,
+ uint32_t param_id)
+{
+ struct asm_mtmx_strtr_params matrix;
+ int sz = 0;
+ int rc = 0;
+
+ pr_debug("%s: Window lsw is %d, window msw is %d\n", __func__,
+ window_param->window_lsw, window_param->window_msw);
+
+ if (!ac) {
+ pr_err("%s: audio client handle is NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (ac->apr == NULL) {
+ pr_err("%s: ac->apr is NULL", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ sz = sizeof(struct asm_mtmx_strtr_params);
+ q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
+
+ matrix.param.data_payload_addr_lsw = 0;
+ matrix.param.data_payload_addr_msw = 0;
+ matrix.param.mem_map_handle = 0;
+ matrix.param.data_payload_size = sizeof(matrix) -
+ sizeof(matrix.hdr) - sizeof(matrix.param);
+ matrix.param.direction = 0; /* RX */
+ matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
+ matrix.data.param_id = param_id;
+ matrix.data.param_size = matrix.param.data_payload_size -
+ sizeof(matrix.data);
+ matrix.data.reserved = 0;
+ matrix.window_lsw = window_param->window_lsw;
+ matrix.window_msw = window_param->window_msw;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
+ if (rc < 0) {
+ pr_err("%s: Render window start send failed paramid [0x%x]\n",
+ __func__, matrix.data.param_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, Render window start paramid[0x%x]\n",
+ __func__, matrix.data.param_id);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+};
+
+static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
+{
+ struct apr_hdr hdr;
+ int rc;
+ atomic_t *state;
+ int cnt = 0;
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ q6asm_update_token(&hdr.token,
+ ac->session,
+ stream_id,
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, hdr.token, stream_id, ac->session);
+ switch (cmd) {
+ case CMD_PAUSE:
+ pr_debug("%s: CMD_PAUSE\n", __func__);
+ hdr.opcode = ASM_SESSION_CMD_PAUSE;
+ state = &ac->cmd_state;
+ break;
+ case CMD_SUSPEND:
+ pr_debug("%s: CMD_SUSPEND\n", __func__);
+ hdr.opcode = ASM_SESSION_CMD_SUSPEND;
+ state = &ac->cmd_state;
+ break;
+ case CMD_FLUSH:
+ pr_debug("%s: CMD_FLUSH\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_FLUSH;
+ state = &ac->cmd_state;
+ break;
+ case CMD_OUT_FLUSH:
+ pr_debug("%s: CMD_OUT_FLUSH\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
+ state = &ac->cmd_state;
+ break;
+ case CMD_EOS:
+ pr_debug("%s: CMD_EOS\n", __func__);
+ hdr.opcode = ASM_DATA_CMD_EOS;
+ atomic_set(&ac->cmd_state, 0);
+ state = &ac->cmd_state;
+ break;
+ case CMD_CLOSE:
+ pr_debug("%s: CMD_CLOSE\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_CLOSE;
+ state = &ac->cmd_state;
+ break;
+ default:
+ pr_err("%s: Invalid format[%d]\n", __func__, cmd);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
+ ac->session,
+ hdr.opcode);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("%s: Commmand 0x%x failed %d\n",
+ __func__, hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for response opcode[0x%x]\n",
+ __func__, hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(state) > 0) {
+ pr_err("%s: DSP returned error[%s] opcode %d\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(state)),
+ hdr.opcode);
+ rc = adsp_err_get_lnx_err_code(atomic_read(state));
+ goto fail_cmd;
+ }
+
+ if (cmd == CMD_FLUSH)
+ q6asm_reset_buf_state(ac);
+ if (cmd == CMD_CLOSE) {
+ /* check if DSP return all buffers */
+ if (ac->port[IN].buf) {
+ for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
+ cnt++) {
+ if (ac->port[IN].buf[cnt].used == IN) {
+ dev_vdbg(ac->dev, "Write Buf[%d] not returned\n",
+ cnt);
+ }
+ }
+ }
+ if (ac->port[OUT].buf) {
+ for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
+ if (ac->port[OUT].buf[cnt].used == OUT) {
+ dev_vdbg(ac->dev, "Read Buf[%d] not returned\n",
+ cnt);
+ }
+ }
+ }
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+ return __q6asm_cmd(ac, cmd, ac->stream_id);
+}
+
+int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
+{
+ return __q6asm_cmd(ac, cmd, stream_id);
+}
+
+static int __q6asm_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id)
+{
+ struct apr_hdr hdr;
+ int rc;
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, 1);
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ q6asm_update_token(&hdr.token,
+ ac->session,
+ stream_id,
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, hdr.token, stream_id, ac->session);
+ switch (cmd) {
+ case CMD_PAUSE:
+ pr_debug("%s: CMD_PAUSE\n", __func__);
+ hdr.opcode = ASM_SESSION_CMD_PAUSE;
+ break;
+ case CMD_EOS:
+ pr_debug("%s: CMD_EOS\n", __func__);
+ hdr.opcode = ASM_DATA_CMD_EOS;
+ break;
+ case CMD_CLOSE:
+ pr_debug("%s: CMD_CLOSE\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_CLOSE;
+ break;
+ default:
+ pr_err("%s: Invalid format[%d]\n", __func__, cmd);
+ goto fail_cmd;
+ }
+ pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
+ ac->session,
+ hdr.opcode);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("%s: Commmand 0x%x failed %d\n",
+ __func__, hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+ pr_debug("%s: stream_id: %d\n", __func__, ac->stream_id);
+ return __q6asm_cmd_nowait(ac, cmd, ac->stream_id);
+}
+
+int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id)
+{
+ pr_debug("%s: stream_id: %d\n", __func__, stream_id);
+ return __q6asm_cmd_nowait(ac, cmd, stream_id);
+}
+
+int __q6asm_send_meta_data(struct audio_client *ac, uint32_t stream_id,
+ uint32_t initial_samples, uint32_t trailing_samples)
+{
+ struct asm_data_cmd_remove_silence silence;
+ int rc = 0;
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]\n", __func__, ac->session);
+ q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), FALSE,
+ stream_id);
+
+ /*
+ * Updated the token field with stream/session for compressed playback
+ * Platform driver must know the the stream with which the command is
+ * associated
+ */
+ if (ac->io_mode & COMPRESSED_STREAM_IO)
+ q6asm_update_token(&silence.hdr.token,
+ ac->session,
+ stream_id,
+ 0, /* Buffer index is NA */
+ 0, /* Direction flag is NA */
+ WAIT_CMD);
+ pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
+ __func__, silence.hdr.token, stream_id, ac->session);
+
+ silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
+ silence.num_samples_to_remove = initial_samples;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
+ if (rc < 0) {
+ pr_err("%s: Commmand silence failed[%d]", __func__, rc);
+
+ goto fail_cmd;
+ }
+
+ silence.hdr.opcode = ASM_DATA_CMD_REMOVE_TRAILING_SILENCE;
+ silence.num_samples_to_remove = trailing_samples;
+
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
+ if (rc < 0) {
+ pr_err("%s: Commmand silence failed[%d]", __func__, rc);
+ goto fail_cmd;
+ }
+
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id,
+ uint32_t initial_samples, uint32_t trailing_samples)
+{
+ return __q6asm_send_meta_data(ac, stream_id, initial_samples,
+ trailing_samples);
+}
+
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+ uint32_t trailing_samples)
+{
+ return __q6asm_send_meta_data(ac, ac->stream_id, initial_samples,
+ trailing_samples);
+}
+
+static void q6asm_reset_buf_state(struct audio_client *ac)
+{
+ int cnt = 0;
+ int loopcnt = 0;
+ int used;
+ struct audio_port_data *port = NULL;
+
+ if (ac->io_mode & SYNC_IO_MODE) {
+ used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
+ mutex_lock(&ac->cmd_lock);
+ for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+ port = &ac->port[loopcnt];
+ cnt = port->max_buf_cnt - 1;
+ port->dsp_buf = 0;
+ port->cpu_buf = 0;
+ while (cnt >= 0) {
+ if (!port->buf)
+ continue;
+ port->buf[cnt].used = used;
+ cnt--;
+ }
+ }
+ mutex_unlock(&ac->cmd_lock);
+ }
+}
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
+{
+ struct asm_session_cmd_regx_overflow tx_overflow;
+ int rc;
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]enable[%d]\n", __func__,
+ ac->session, enable);
+ q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ tx_overflow.hdr.opcode =
+ ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS;
+ /* tx overflow event: enable */
+ tx_overflow.enable_flag = enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
+ if (rc < 0) {
+ pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
+ __func__, tx_overflow.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for tx overflow\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+
+ return 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
+{
+ struct asm_session_cmd_rgstr_rx_underflow rx_underflow;
+ int rc;
+
+ if (!ac) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]enable[%d]\n", __func__,
+ ac->session, enable);
+ q6asm_add_hdr_async(ac, &rx_underflow.hdr, sizeof(rx_underflow), FALSE);
+
+ rx_underflow.hdr.opcode =
+ ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS;
+ /* tx overflow event: enable */
+ rx_underflow.enable_flag = enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &rx_underflow);
+ if (rc < 0) {
+ pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
+ __func__, rx_underflow.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+/*
+ * q6asm_get_path_delay() - get the path delay for an audio session
+ * @ac: audio client handle
+ *
+ * Retrieves the current audio DSP path delay for the given audio session.
+ *
+ * Return: 0 on success, error code otherwise
+ */
+int q6asm_get_path_delay(struct audio_client *ac)
+{
+ int rc = 0;
+ struct apr_hdr hdr;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: invalid audio client\n", __func__);
+ return -EINVAL;
+ }
+
+ hdr.opcode = ASM_SESSION_CMD_GET_PATH_DELAY_V2;
+ q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("%s: Commmand 0x%x failed %d\n", __func__,
+ hdr.opcode, rc);
+ return rc;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5 * HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for response opcode[0x%x]\n",
+ __func__, hdr.opcode);
+ return -ETIMEDOUT;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ return rc;
+ }
+
+ return 0;
+}
+
+int q6asm_get_apr_service_id(int session_id)
+{
+ pr_debug("%s:\n", __func__);
+
+ if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
+ pr_err("%s: invalid session_id = %d\n", __func__, session_id);
+ return -EINVAL;
+ }
+
+ return ((struct apr_svc *)session[session_id]->apr)->id;
+}
+
+int q6asm_get_asm_topology(int session_id)
+{
+ int topology;
+
+ if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
+ pr_err("%s: invalid session_id = %d\n", __func__, session_id);
+ topology = -EINVAL;
+ goto done;
+ }
+
+ topology = session[session_id]->topology;
+done:
+ return topology;
+}
+
+int q6asm_get_asm_app_type(int session_id)
+{
+ int app_type;
+
+ if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
+ pr_err("%s: invalid session_id = %d\n", __func__, session_id);
+ app_type = -EINVAL;
+ goto done;
+ }
+
+ app_type = session[session_id]->app_type;
+done:
+ return app_type;
+}
+
+static int q6asm_get_asm_topology_cal(void)
+{
+ int topology = DEFAULT_POPP_TOPOLOGY;
+ struct cal_block_data *cal_block = NULL;
+
+ if (cal_data[ASM_TOPOLOGY_CAL] == NULL)
+ goto done;
+
+ mutex_lock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
+ cal_block = cal_utils_get_only_cal_block(cal_data[ASM_TOPOLOGY_CAL]);
+ if (cal_block == NULL)
+ goto unlock;
+
+ topology = ((struct audio_cal_info_asm_top *)
+ cal_block->cal_info)->topology;
+unlock:
+ mutex_unlock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
+done:
+ pr_debug("%s: Using topology %d\n", __func__, topology);
+ return topology;
+}
+
+static int q6asm_get_asm_app_type_cal(void)
+{
+ int app_type = DEFAULT_APP_TYPE;
+ struct cal_block_data *cal_block = NULL;
+
+ if (cal_data[ASM_TOPOLOGY_CAL] == NULL)
+ goto done;
+
+ mutex_lock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
+ cal_block = cal_utils_get_only_cal_block(cal_data[ASM_TOPOLOGY_CAL]);
+ if (cal_block == NULL)
+ goto unlock;
+
+ app_type = ((struct audio_cal_info_asm_top *)
+ cal_block->cal_info)->app_type;
+
+ if (app_type == 0)
+ app_type = DEFAULT_APP_TYPE;
+unlock:
+ mutex_unlock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
+done:
+ pr_debug("%s: Using app_type %d\n", __func__, app_type);
+ return app_type;
+}
+
+int q6asm_send_cal(struct audio_client *ac)
+{
+ struct cal_block_data *cal_block = NULL;
+ struct apr_hdr hdr;
+ char *asm_params = NULL;
+ struct asm_stream_cmd_set_pp_params_v2 payload_params;
+ int sz, rc = -EINVAL;
+
+ pr_debug("%s:\n", __func__);
+
+ if (!ac) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ goto done;
+ }
+ if (ac->apr == NULL) {
+ pr_err("%s: AC APR handle NULL\n", __func__);
+ goto done;
+ }
+ if (ac->io_mode & NT_MODE) {
+ pr_debug("%s: called for NT MODE, exiting\n", __func__);
+ goto done;
+ }
+
+ if (cal_data[ASM_AUDSTRM_CAL] == NULL)
+ goto done;
+
+ if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
+ rc = 0; /* no cal is required, not error case */
+ goto done;
+ }
+
+ mutex_lock(&cal_data[ASM_AUDSTRM_CAL]->lock);
+ cal_block = cal_utils_get_only_cal_block(cal_data[ASM_AUDSTRM_CAL]);
+ if (cal_block == NULL) {
+ pr_err("%s: cal_block is NULL\n",
+ __func__);
+ goto unlock;
+ }
+
+ if (cal_block->cal_data.size == 0) {
+ rc = 0; /* not error case */
+ pr_debug("%s: cal_data.size is 0, don't send cal data\n",
+ __func__);
+ goto unlock;
+ }
+
+ rc = remap_cal_data(ASM_AUDSTRM_CAL_TYPE, cal_block);
+ if (rc) {
+ pr_err("%s: Remap_cal_data failed for cal %d!\n",
+ __func__, ASM_AUDSTRM_CAL);
+ goto unlock;
+ }
+
+ sz = sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_pp_params_v2);
+ asm_params = kzalloc(sz, GFP_KERNEL);
+ if (!asm_params) {
+ pr_err("%s, asm params memory alloc failed", __func__);
+ rc = -ENOMEM;
+ goto unlock;
+ }
+
+ /* asm_stream_cmd_set_pp_params_v2 has no APR header in it */
+ q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_pp_params_v2)), TRUE);
+
+ atomic_set(&ac->cmd_state, 1);
+ hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ payload_params.data_payload_addr_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ payload_params.data_payload_addr_msw =
+ msm_audio_populate_upper_32_bits(
+ cal_block->cal_data.paddr);
+ payload_params.mem_map_handle = cal_block->map_data.q6map_handle;
+ payload_params.data_payload_size = cal_block->cal_data.size;
+ memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
+ memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
+ sizeof(struct asm_stream_cmd_set_pp_params_v2));
+
+ pr_debug("%s: phyaddr lsw = %x msw = %x, maphdl = %x calsize = %d\n",
+ __func__, payload_params.data_payload_addr_lsw,
+ payload_params.data_payload_addr_msw,
+ payload_params.mem_map_handle,
+ payload_params.data_payload_size);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
+ if (rc < 0) {
+ pr_err("%s: audio audstrm cal send failed\n", __func__);
+ rc = -EINVAL;
+ goto free;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) <= 0), 5 * HZ);
+ if (!rc) {
+ pr_err("%s: timeout, audio audstrm cal send\n", __func__);
+ rc = -ETIMEDOUT;
+ goto free;
+ }
+ if (atomic_read(&ac->cmd_state) < 0) {
+ pr_err("%s: DSP returned error[%d] audio audstrm cal send\n",
+ __func__, atomic_read(&ac->cmd_state));
+ rc = -EINVAL;
+ goto free;
+ }
+
+ rc = 0;
+
+free:
+ kfree(asm_params);
+unlock:
+ mutex_unlock(&cal_data[ASM_AUDSTRM_CAL]->lock);
+done:
+ return rc;
+}
+
+static int get_cal_type_index(int32_t cal_type)
+{
+ int ret = -EINVAL;
+
+ switch (cal_type) {
+ case ASM_TOPOLOGY_CAL_TYPE:
+ ret = ASM_TOPOLOGY_CAL;
+ break;
+ case ASM_CUST_TOPOLOGY_CAL_TYPE:
+ ret = ASM_CUSTOM_TOP_CAL;
+ break;
+ case ASM_AUDSTRM_CAL_TYPE:
+ ret = ASM_AUDSTRM_CAL;
+ break;
+ case ASM_RTAC_APR_CAL_TYPE:
+ ret = ASM_RTAC_APR_CAL;
+ break;
+ default:
+ pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
+ }
+ return ret;
+}
+
+static int q6asm_alloc_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_alloc_cal(data_size, data,
+ cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int q6asm_dealloc_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_dealloc_cal(data_size, data,
+ cal_data[cal_index]);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int q6asm_set_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_set_cal(data_size, data,
+ cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (cal_index == ASM_CUSTOM_TOP_CAL) {
+ mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
+ set_custom_topology = 1;
+ mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
+ }
+done:
+ return ret;
+}
+
+static void q6asm_delete_cal_data(void)
+{
+ pr_debug("%s:\n", __func__);
+ cal_utils_destroy_cal_types(ASM_MAX_CAL_TYPES, cal_data);
+}
+
+static int q6asm_init_cal_data(void)
+{
+ int ret = 0;
+ struct cal_type_info cal_type_info[] = {
+ {{ASM_TOPOLOGY_CAL_TYPE,
+ {NULL, NULL, NULL,
+ q6asm_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{ASM_CUST_TOPOLOGY_CAL_TYPE,
+ {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
+ q6asm_set_cal, NULL, NULL} },
+ {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
+
+ {{ASM_AUDSTRM_CAL_TYPE,
+ {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
+ q6asm_set_cal, NULL, NULL} },
+ {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
+
+ {{ASM_RTAC_APR_CAL_TYPE,
+ {NULL, NULL, NULL, NULL, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} }
+ };
+ pr_debug("%s\n", __func__);
+
+ ret = cal_utils_create_cal_types(ASM_MAX_CAL_TYPES, cal_data,
+ cal_type_info);
+ if (ret < 0) {
+ pr_err("%s: could not create cal type! %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return ret;
+err:
+ q6asm_delete_cal_data();
+ return ret;
+}
+
+static int q6asm_is_valid_session(struct apr_client_data *data, void *priv)
+{
+ struct audio_client *ac = (struct audio_client *)priv;
+ union asm_token_struct asm_token;
+
+ asm_token.token = data->token;
+ if (asm_token._token.session_id != ac->session) {
+ pr_err("%s: Invalid session[%d] rxed expected[%d]",
+ __func__, asm_token._token.session_id, ac->session);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __init q6asm_init(void)
+{
+ int lcnt, ret;
+
+ pr_debug("%s:\n", __func__);
+
+ memset(session, 0, sizeof(session));
+ set_custom_topology = 1;
+
+ /*setup common client used for cal mem map */
+ common_client.session = ASM_CONTROL_SESSION;
+ common_client.port[0].buf = &common_buf[0];
+ common_client.port[1].buf = &common_buf[1];
+ init_waitqueue_head(&common_client.cmd_wait);
+ init_waitqueue_head(&common_client.time_wait);
+ init_waitqueue_head(&common_client.mem_wait);
+ atomic_set(&common_client.time_flag, 1);
+ INIT_LIST_HEAD(&common_client.port[0].mem_map_handle);
+ INIT_LIST_HEAD(&common_client.port[1].mem_map_handle);
+ mutex_init(&common_client.cmd_lock);
+ for (lcnt = 0; lcnt <= OUT; lcnt++) {
+ mutex_init(&common_client.port[lcnt].lock);
+ spin_lock_init(&common_client.port[lcnt].dsp_lock);
+ }
+ atomic_set(&common_client.cmd_state, 0);
+ atomic_set(&common_client.mem_state, 0);
+
+ ret = q6asm_init_cal_data();
+ if (ret)
+ pr_err("%s: could not init cal data! ret %d\n",
+ __func__, ret);
+
+ config_debug_fs_init();
+
+ return 0;
+}
+
+static void __exit q6asm_exit(void)
+{
+ q6asm_delete_cal_data();
+}
+
+device_initcall(q6asm_init);
+__exitcall(q6asm_exit);
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
new file mode 100644
index 0000000..ea78e6a
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -0,0 +1,807 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6audio-v2.h>
+
+int q6audio_get_port_index(u16 port_id)
+{
+ switch (port_id) {
+ case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
+ case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_PCM_RX;
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_PCM_TX;
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ return IDX_AFE_PORT_ID_SECONDARY_PCM_RX;
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ return IDX_AFE_PORT_ID_SECONDARY_PCM_TX;
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_PCM_RX;
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_PCM_TX;
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_PCM_RX;
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_PCM_TX;
+ case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
+ case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
+ case MI2S_RX: return IDX_MI2S_RX;
+ case MI2S_TX: return IDX_MI2S_TX;
+ case HDMI_RX: return IDX_HDMI_RX;
+ case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX;
+ case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX;
+ case RSVD_2: return IDX_RSVD_2;
+ case RSVD_3: return IDX_RSVD_3;
+ case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
+ case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
+ case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
+ case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
+ case VOICE2_PLAYBACK_TX: return IDX_VOICE2_PLAYBACK_TX;
+ case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
+ case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
+ case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
+ case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
+ case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
+ case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
+ case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
+ case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
+ case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
+ case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+ case SLIMBUS_5_RX: return IDX_SLIMBUS_5_RX;
+ case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
+ case SLIMBUS_6_RX: return IDX_SLIMBUS_6_RX;
+ case SLIMBUS_6_TX: return IDX_SLIMBUS_6_TX;
+ case SLIMBUS_7_RX: return IDX_SLIMBUS_7_RX;
+ case SLIMBUS_7_TX: return IDX_SLIMBUS_7_TX;
+ case SLIMBUS_8_RX: return IDX_SLIMBUS_8_RX;
+ case SLIMBUS_8_TX: return IDX_SLIMBUS_8_TX;
+ case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
+ case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
+ case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
+ case INT_FM_RX: return IDX_INT_FM_RX;
+ case INT_FM_TX: return IDX_INT_FM_TX;
+ case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
+ case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX;
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_TX;
+ case AUDIO_PORT_ID_I2S_RX:
+ return IDX_AUDIO_PORT_ID_I2S_RX;
+ case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX_SD1;
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_0;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_0;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_1;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_1;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_2;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_2;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_3;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_3;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_4;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_4;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_5;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_5;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_6;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_6;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_RX_7;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ return IDX_AFE_PORT_ID_PRIMARY_TDM_TX_7;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_0;
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_0;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_1;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_1;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_2;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_2;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_3;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_3;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_4;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_4;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_5;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_5;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_6;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_6;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_RX_7;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ return IDX_AFE_PORT_ID_SECONDARY_TDM_TX_7;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_0;
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_0;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_1;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_1;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_2;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_2;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_3;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_3;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_4;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_4;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_5;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_5;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_6;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_6;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_RX_7;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ return IDX_AFE_PORT_ID_TERTIARY_TDM_TX_7;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_0;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_0;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_1;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_1;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_2;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_2;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_3;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_3;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_4;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_4;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_5;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_5;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_6;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_6;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_7;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_7;
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_SENARY_MI2S_TX;
+ case AFE_PORT_ID_USB_RX:
+ return IDX_AFE_PORT_ID_USB_RX;
+ case AFE_PORT_ID_USB_TX:
+ return IDX_AFE_PORT_ID_USB_TX;
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT0_MI2S_RX;
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT0_MI2S_TX;
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT1_MI2S_RX;
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT1_MI2S_TX;
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT2_MI2S_RX;
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT2_MI2S_TX;
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT3_MI2S_RX;
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT3_MI2S_TX;
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT4_MI2S_RX;
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT4_MI2S_TX;
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT5_MI2S_RX;
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT5_MI2S_TX;
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT6_MI2S_RX;
+ case AFE_PORT_ID_INT6_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT6_MI2S_TX;
+ default: return -EINVAL;
+ }
+}
+
+int q6audio_get_port_id(u16 port_id)
+{
+ switch (port_id) {
+ case PRIMARY_I2S_RX: return PRIMARY_I2S_RX;
+ case PRIMARY_I2S_TX: return PRIMARY_I2S_TX;
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ return AFE_PORT_ID_PRIMARY_PCM_RX;
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ return AFE_PORT_ID_PRIMARY_PCM_TX;
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ return AFE_PORT_ID_SECONDARY_PCM_RX;
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ return AFE_PORT_ID_SECONDARY_PCM_TX;
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ return AFE_PORT_ID_TERTIARY_PCM_RX;
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ return AFE_PORT_ID_TERTIARY_PCM_TX;
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ return AFE_PORT_ID_QUATERNARY_PCM_RX;
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ return AFE_PORT_ID_QUATERNARY_PCM_TX;
+ case SECONDARY_I2S_RX: return AFE_PORT_ID_SECONDARY_MI2S_RX;
+ case SECONDARY_I2S_TX: return AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case MI2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case MI2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
+ case HDMI_RX: return AFE_PORT_ID_MULTICHAN_HDMI_RX;
+ case DISPLAY_PORT_RX:
+ return AFE_PORT_ID_HDMI_OVER_DP_RX;
+ case AFE_PORT_ID_SPDIF_RX: return AFE_PORT_ID_SPDIF_RX;
+ case RSVD_2: return IDX_RSVD_2;
+ case RSVD_3: return IDX_RSVD_3;
+ case DIGI_MIC_TX: return AFE_PORT_ID_DIGITAL_MIC_TX;
+ case VOICE_RECORD_RX: return AFE_PORT_ID_VOICE_RECORD_RX;
+ case VOICE_RECORD_TX: return AFE_PORT_ID_VOICE_RECORD_TX;
+ case VOICE_PLAYBACK_TX: return AFE_PORT_ID_VOICE_PLAYBACK_TX;
+ case VOICE2_PLAYBACK_TX: return AFE_PORT_ID_VOICE2_PLAYBACK_TX;
+ case SLIMBUS_0_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX;
+ case SLIMBUS_0_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX;
+ case SLIMBUS_1_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX;
+ case SLIMBUS_1_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX;
+ case SLIMBUS_2_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX;
+ case SLIMBUS_2_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX;
+ case SLIMBUS_3_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX;
+ case SLIMBUS_3_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX;
+ case SLIMBUS_4_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX;
+ case SLIMBUS_4_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX;
+ case SLIMBUS_5_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX;
+ case SLIMBUS_5_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
+ case SLIMBUS_6_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX;
+ case SLIMBUS_6_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX;
+ case SLIMBUS_7_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_7_RX;
+ case SLIMBUS_7_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_7_TX;
+ case SLIMBUS_8_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_8_RX;
+ case SLIMBUS_8_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_8_TX;
+ case INT_BT_SCO_RX: return AFE_PORT_ID_INTERNAL_BT_SCO_RX;
+ case INT_BT_SCO_TX: return AFE_PORT_ID_INTERNAL_BT_SCO_TX;
+ case INT_BT_A2DP_RX: return AFE_PORT_ID_INTERNAL_BT_A2DP_RX;
+ case INT_FM_RX: return AFE_PORT_ID_INTERNAL_FM_RX;
+ case INT_FM_TX: return AFE_PORT_ID_INTERNAL_FM_TX;
+ case RT_PROXY_PORT_001_RX: return AFE_PORT_ID_RT_PROXY_PORT_001_RX;
+ case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ return AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return AFE_PORT_ID_PRIMARY_MI2S_TX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ return AFE_PORT_ID_SECONDARY_MI2S_RX;
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ return AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return AFE_PORT_ID_TERTIARY_MI2S_TX;
+ case AUDIO_PORT_ID_I2S_RX:
+ return AUDIO_PORT_ID_I2S_RX;
+ case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ return AFE_PORT_ID_SECONDARY_MI2S_RX_SD1;
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ return AFE_PORT_ID_PRIMARY_TDM_RX;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ return AFE_PORT_ID_PRIMARY_TDM_TX;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ return AFE_PORT_ID_PRIMARY_TDM_RX_1;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ return AFE_PORT_ID_PRIMARY_TDM_TX_1;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ return AFE_PORT_ID_PRIMARY_TDM_RX_2;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ return AFE_PORT_ID_PRIMARY_TDM_TX_2;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ return AFE_PORT_ID_PRIMARY_TDM_RX_3;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ return AFE_PORT_ID_PRIMARY_TDM_TX_3;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ return AFE_PORT_ID_PRIMARY_TDM_RX_4;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ return AFE_PORT_ID_PRIMARY_TDM_TX_4;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ return AFE_PORT_ID_PRIMARY_TDM_RX_5;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ return AFE_PORT_ID_PRIMARY_TDM_TX_5;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ return AFE_PORT_ID_PRIMARY_TDM_RX_6;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ return AFE_PORT_ID_PRIMARY_TDM_TX_6;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ return AFE_PORT_ID_PRIMARY_TDM_RX_7;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ return AFE_PORT_ID_PRIMARY_TDM_TX_7;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ return AFE_PORT_ID_SECONDARY_TDM_RX;
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ return AFE_PORT_ID_SECONDARY_TDM_TX;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ return AFE_PORT_ID_SECONDARY_TDM_RX_1;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ return AFE_PORT_ID_SECONDARY_TDM_TX_1;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ return AFE_PORT_ID_SECONDARY_TDM_RX_2;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ return AFE_PORT_ID_SECONDARY_TDM_TX_2;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ return AFE_PORT_ID_SECONDARY_TDM_RX_3;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ return AFE_PORT_ID_SECONDARY_TDM_TX_3;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ return AFE_PORT_ID_SECONDARY_TDM_RX_4;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ return AFE_PORT_ID_SECONDARY_TDM_TX_4;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ return AFE_PORT_ID_SECONDARY_TDM_RX_5;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ return AFE_PORT_ID_SECONDARY_TDM_TX_5;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ return AFE_PORT_ID_SECONDARY_TDM_RX_6;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ return AFE_PORT_ID_SECONDARY_TDM_TX_6;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ return AFE_PORT_ID_SECONDARY_TDM_RX_7;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ return AFE_PORT_ID_SECONDARY_TDM_TX_7;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ return AFE_PORT_ID_TERTIARY_TDM_RX;
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ return AFE_PORT_ID_TERTIARY_TDM_TX;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ return AFE_PORT_ID_TERTIARY_TDM_RX_1;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ return AFE_PORT_ID_TERTIARY_TDM_TX_1;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ return AFE_PORT_ID_TERTIARY_TDM_RX_2;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ return AFE_PORT_ID_TERTIARY_TDM_TX_2;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ return AFE_PORT_ID_TERTIARY_TDM_RX_3;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ return AFE_PORT_ID_TERTIARY_TDM_TX_3;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ return AFE_PORT_ID_TERTIARY_TDM_RX_4;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ return AFE_PORT_ID_TERTIARY_TDM_TX_4;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ return AFE_PORT_ID_TERTIARY_TDM_RX_5;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ return AFE_PORT_ID_TERTIARY_TDM_TX_5;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ return AFE_PORT_ID_TERTIARY_TDM_RX_6;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ return AFE_PORT_ID_TERTIARY_TDM_TX_6;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ return AFE_PORT_ID_TERTIARY_TDM_RX_7;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ return AFE_PORT_ID_TERTIARY_TDM_TX_7;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ return AFE_PORT_ID_QUATERNARY_TDM_RX;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ return AFE_PORT_ID_QUATERNARY_TDM_TX;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ return AFE_PORT_ID_QUATERNARY_TDM_RX_1;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ return AFE_PORT_ID_QUATERNARY_TDM_TX_1;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ return AFE_PORT_ID_QUATERNARY_TDM_RX_2;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ return AFE_PORT_ID_QUATERNARY_TDM_TX_2;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ return AFE_PORT_ID_QUATERNARY_TDM_RX_3;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ return AFE_PORT_ID_QUATERNARY_TDM_TX_3;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ return AFE_PORT_ID_QUATERNARY_TDM_RX_4;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ return AFE_PORT_ID_QUATERNARY_TDM_TX_4;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ return AFE_PORT_ID_QUATERNARY_TDM_RX_5;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ return AFE_PORT_ID_QUATERNARY_TDM_TX_5;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ return AFE_PORT_ID_QUATERNARY_TDM_RX_6;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ return AFE_PORT_ID_QUATERNARY_TDM_TX_6;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ return AFE_PORT_ID_QUATERNARY_TDM_RX_7;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ return AFE_PORT_ID_QUATERNARY_TDM_TX_7;
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ return AFE_PORT_ID_SENARY_MI2S_TX;
+ case AFE_PORT_ID_USB_RX:
+ return AFE_PORT_ID_USB_RX;
+ case AFE_PORT_ID_USB_TX:
+ return AFE_PORT_ID_USB_TX;
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ return AFE_PORT_ID_INT0_MI2S_RX;
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ return AFE_PORT_ID_INT0_MI2S_TX;
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ return AFE_PORT_ID_INT1_MI2S_RX;
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ return AFE_PORT_ID_INT1_MI2S_TX;
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ return AFE_PORT_ID_INT2_MI2S_RX;
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ return AFE_PORT_ID_INT2_MI2S_TX;
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ return AFE_PORT_ID_INT3_MI2S_RX;
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ return AFE_PORT_ID_INT3_MI2S_TX;
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ return AFE_PORT_ID_INT4_MI2S_RX;
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ return AFE_PORT_ID_INT4_MI2S_TX;
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ return AFE_PORT_ID_INT5_MI2S_RX;
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ return AFE_PORT_ID_INT5_MI2S_TX;
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ return AFE_PORT_ID_INT6_MI2S_RX;
+ case AFE_PORT_ID_INT6_MI2S_TX:
+ return AFE_PORT_ID_INT6_MI2S_TX;
+ default:
+ pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
+ return -EINVAL;
+ }
+}
+int q6audio_convert_virtual_to_portid(u16 port_id)
+{
+ int ret;
+
+ /* if port_id is virtual, convert to physical..
+ * if port_id is already physical, return physical
+ */
+ if (q6audio_validate_port(port_id) < 0) {
+ if (port_id == RT_PROXY_DAI_001_RX ||
+ port_id == RT_PROXY_DAI_001_TX ||
+ port_id == RT_PROXY_DAI_002_RX ||
+ port_id == RT_PROXY_DAI_002_TX)
+ ret = VIRTUAL_ID_TO_PORTID(port_id);
+ else
+ ret = -EINVAL;
+ } else
+ ret = port_id;
+
+ return ret;
+}
+
+int q6audio_is_digital_pcm_interface(u16 port_id)
+{
+ int ret = 0;
+
+ switch (port_id) {
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ case SECONDARY_I2S_RX:
+ case SECONDARY_I2S_TX:
+ case MI2S_RX:
+ case MI2S_TX:
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ case AUDIO_PORT_ID_I2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ case AFE_PORT_ID_INT6_MI2S_TX:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int q6audio_validate_port(u16 port_id)
+{
+ int ret;
+
+ switch (port_id) {
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ case AFE_PORT_ID_SECONDARY_PCM_RX:
+ case AFE_PORT_ID_SECONDARY_PCM_TX:
+ case AFE_PORT_ID_TERTIARY_PCM_RX:
+ case AFE_PORT_ID_TERTIARY_PCM_TX:
+ case AFE_PORT_ID_QUATERNARY_PCM_RX:
+ case AFE_PORT_ID_QUATERNARY_PCM_TX:
+ case SECONDARY_I2S_RX:
+ case SECONDARY_I2S_TX:
+ case MI2S_RX:
+ case MI2S_TX:
+ case HDMI_RX:
+ case DISPLAY_PORT_RX:
+ case RSVD_2:
+ case RSVD_3:
+ case DIGI_MIC_TX:
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_4_TX:
+ case SLIMBUS_5_RX:
+ case SLIMBUS_5_TX:
+ case SLIMBUS_6_RX:
+ case SLIMBUS_6_TX:
+ case SLIMBUS_7_RX:
+ case SLIMBUS_7_TX:
+ case SLIMBUS_8_RX:
+ case SLIMBUS_8_TX:
+ case INT_BT_SCO_RX:
+ case INT_BT_SCO_TX:
+ case INT_BT_A2DP_RX:
+ case INT_FM_RX:
+ case INT_FM_TX:
+ case RT_PROXY_PORT_001_RX:
+ case RT_PROXY_PORT_001_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ case AFE_PORT_ID_SPDIF_RX:
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ case AFE_PORT_ID_SENARY_MI2S_TX:
+ case AFE_PORT_ID_USB_RX:
+ case AFE_PORT_ID_USB_TX:
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ case AFE_PORT_ID_INT6_MI2S_TX:
+ {
+ ret = 0;
+ break;
+ }
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
new file mode 100644
index 0000000..ac3dd0e
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -0,0 +1,951 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/qdsp6v2/apr.h>
+#include <soc/qcom/smd.h>
+#include <sound/q6core.h>
+#include <sound/audio_cal_utils.h>
+
+#define TIMEOUT_MS 1000
+/*
+ * AVS bring up in the modem is optimitized for the new
+ * Sub System Restart design and 100 milliseconds timeout
+ * is sufficient to make sure the Q6 will be ready.
+ */
+#define Q6_READY_TIMEOUT_MS 100
+
+enum {
+ META_CAL,
+ CUST_TOP_CAL,
+ CORE_MAX_CAL
+};
+
+struct q6core_str {
+ struct apr_svc *core_handle_q;
+ wait_queue_head_t bus_bw_req_wait;
+ wait_queue_head_t cmd_req_wait;
+ u32 bus_bw_resp_received;
+ enum cmd_flags {
+ FLAG_NONE,
+ FLAG_CMDRSP_LICENSE_RESULT
+ } cmd_resp_received_flag;
+ struct mutex cmd_lock;
+ union {
+ struct avcs_cmdrsp_get_license_validation_result
+ cmdrsp_license_result;
+ } cmd_resp_payload;
+ u32 param;
+ struct cal_type_data *cal_data[CORE_MAX_CAL];
+ uint32_t mem_map_cal_handle;
+ int32_t adsp_status;
+};
+
+static struct q6core_str q6core_lcl;
+
+struct generic_get_data_ {
+ int valid;
+ int size_in_ints;
+ int ints[];
+};
+static struct generic_get_data_ *generic_get_data;
+
+static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
+{
+ uint32_t *payload1;
+
+ if (data == NULL) {
+ pr_err("%s: data argument is null\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: core msg: payload len = %u, apr resp opcode = 0x%x\n",
+ __func__,
+ data->payload_size, data->opcode);
+
+ switch (data->opcode) {
+
+ case APR_BASIC_RSP_RESULT:{
+
+ if (data->payload_size == 0) {
+ pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
+ __func__);
+ return 0;
+ }
+
+ payload1 = data->payload;
+
+ switch (payload1[0]) {
+
+ case AVCS_CMD_SHARED_MEM_UNMAP_REGIONS:
+ pr_debug("%s: Cmd = AVCS_CMD_SHARED_MEM_UNMAP_REGIONS status[0x%x]\n",
+ __func__, payload1[1]);
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+ case AVCS_CMD_SHARED_MEM_MAP_REGIONS:
+ pr_debug("%s: Cmd = AVCS_CMD_SHARED_MEM_MAP_REGIONS status[0x%x]\n",
+ __func__, payload1[1]);
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+ case AVCS_CMD_REGISTER_TOPOLOGIES:
+ pr_debug("%s: Cmd = AVCS_CMD_REGISTER_TOPOLOGIES status[0x%x]\n",
+ __func__, payload1[1]);
+ /* -ADSP status to match Linux error standard */
+ q6core_lcl.adsp_status = -payload1[1];
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+ case AVCS_CMD_DEREGISTER_TOPOLOGIES:
+ pr_debug("%s: Cmd = AVCS_CMD_DEREGISTER_TOPOLOGIES status[0x%x]\n",
+ __func__, payload1[1]);
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+ default:
+ pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n",
+ __func__,
+ payload1[0], payload1[1], data->opcode);
+ break;
+ }
+ break;
+ }
+
+ case RESET_EVENTS:{
+ pr_debug("%s: Reset event received in Core service\n",
+ __func__);
+ apr_reset(q6core_lcl.core_handle_q);
+ q6core_lcl.core_handle_q = NULL;
+ break;
+ }
+ case AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS:
+ payload1 = data->payload;
+ pr_debug("%s: AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS handle %d\n",
+ __func__, payload1[0]);
+ q6core_lcl.mem_map_cal_handle = payload1[0];
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+ case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
+ payload1 = data->payload;
+ q6core_lcl.param = payload1[0];
+ pr_debug("%s: Received ADSP get state response 0x%x\n",
+ __func__, q6core_lcl.param);
+ /* ensure .param is updated prior to .bus_bw_resp_received */
+ wmb();
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+ case AVCS_CMDRSP_GET_LICENSE_VALIDATION_RESULT:
+ payload1 = data->payload;
+ pr_debug("%s: cmd = LICENSE_VALIDATION_RESULT, result = 0x%x\n",
+ __func__, payload1[0]);
+ q6core_lcl.cmd_resp_payload.cmdrsp_license_result.result
+ = payload1[0];
+ q6core_lcl.cmd_resp_received_flag = FLAG_CMDRSP_LICENSE_RESULT;
+ wake_up(&q6core_lcl.cmd_req_wait);
+ break;
+ default:
+ pr_err("%s: Message id from adsp core svc: 0x%x\n",
+ __func__, data->opcode);
+ if (generic_get_data) {
+ generic_get_data->valid = 1;
+ generic_get_data->size_in_ints =
+ data->payload_size/sizeof(int);
+ pr_debug("DTS_EAGLE_CORE callback size = %i\n",
+ data->payload_size);
+ memcpy(generic_get_data->ints, data->payload,
+ data->payload_size);
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void ocm_core_open(void)
+{
+ if (q6core_lcl.core_handle_q == NULL)
+ q6core_lcl.core_handle_q = apr_register("ADSP", "CORE",
+ aprv2_core_fn_q, 0xFFFFFFFF, NULL);
+ pr_debug("%s: Open_q %pK\n", __func__, q6core_lcl.core_handle_q);
+ if (q6core_lcl.core_handle_q == NULL)
+ pr_err("%s: Unable to register CORE\n", __func__);
+}
+
+int32_t core_set_license(uint32_t key, uint32_t module_id)
+{
+ struct avcs_cmd_set_license *cmd_setl = NULL;
+ struct audio_cal_info_metainfo *metainfo = NULL;
+ struct cal_block_data *cal_block = NULL;
+ int rc = 0, packet_size = 0;
+
+ pr_debug("%s: key:0x%x, id:0x%x\n", __func__, key, module_id);
+
+ mutex_lock(&(q6core_lcl.cmd_lock));
+ if (q6core_lcl.cal_data[META_CAL] == NULL) {
+ pr_err("%s: cal_data not initialized yet!!\n", __func__);
+ rc = -EINVAL;
+ goto cmd_unlock;
+ }
+
+ mutex_lock(&((q6core_lcl.cal_data[META_CAL])->lock));
+ cal_block =
+ cal_utils_get_only_cal_block(q6core_lcl.cal_data[META_CAL]);
+ if (cal_block == NULL ||
+ cal_block->cal_data.kvaddr == NULL ||
+ cal_block->cal_data.size <= 0) {
+ pr_err("%s: Invalid cal block to send", __func__);
+ rc = -EINVAL;
+ goto cal_data_unlock;
+ }
+ metainfo = (struct audio_cal_info_metainfo *)cal_block->cal_info;
+ if (metainfo == NULL) {
+ pr_err("%s: No metainfo!!!", __func__);
+ rc = -EINVAL;
+ goto cal_data_unlock;
+ }
+ if (metainfo->nKey != key) {
+ pr_err("%s: metainfo key mismatch!!! found:%x, needed:%x\n",
+ __func__, metainfo->nKey, key);
+ rc = -EINVAL;
+ goto cal_data_unlock;
+ } else if (key == 0) {
+ pr_err("%s: metainfo key is %d a invalid key", __func__, key);
+ goto cal_data_unlock;
+ }
+
+ packet_size = sizeof(struct avcs_cmd_set_license) +
+ cal_block->cal_data.size;
+ /*round up total packet_size to next 4 byte boundary*/
+ packet_size = ((packet_size + 0x3)>>2)<<2;
+
+ cmd_setl = kzalloc(packet_size, GFP_KERNEL);
+ if (cmd_setl == NULL) {
+ rc = -ENOMEM;
+ goto cal_data_unlock;
+ }
+
+ ocm_core_open();
+ if (q6core_lcl.core_handle_q == NULL) {
+ pr_err("%s: apr registration for CORE failed\n", __func__);
+ rc = -ENODEV;
+ goto fail_cmd;
+ }
+
+ cmd_setl->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cmd_setl->hdr.pkt_size = packet_size;
+ cmd_setl->hdr.src_port = 0;
+ cmd_setl->hdr.dest_port = 0;
+ cmd_setl->hdr.token = 0;
+ cmd_setl->hdr.opcode = AVCS_CMD_SET_LICENSE;
+ cmd_setl->id = module_id;
+ cmd_setl->overwrite = 1;
+ cmd_setl->size = cal_block->cal_data.size;
+ memcpy((uint8_t *)cmd_setl + sizeof(struct avcs_cmd_set_license),
+ cal_block->cal_data.kvaddr,
+ cal_block->cal_data.size);
+ pr_info("%s: Set license opcode=0x%x ,key=0x%x, id =0x%x, size = %d\n",
+ __func__, cmd_setl->hdr.opcode,
+ metainfo->nKey, cmd_setl->id, cmd_setl->size);
+ rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)cmd_setl);
+ if (rc < 0)
+ pr_err("%s: SET_LICENSE failed op[0x%x]rc[%d]\n",
+ __func__, cmd_setl->hdr.opcode, rc);
+
+fail_cmd:
+ kfree(cmd_setl);
+cal_data_unlock:
+ mutex_unlock(&((q6core_lcl.cal_data[META_CAL])->lock));
+cmd_unlock:
+ mutex_unlock(&(q6core_lcl.cmd_lock));
+
+ return rc;
+}
+
+int32_t core_get_license_status(uint32_t module_id)
+{
+ struct avcs_cmd_get_license_validation_result get_lvr_cmd;
+ int ret = 0;
+
+ pr_debug("%s: module_id 0x%x", __func__, module_id);
+
+ mutex_lock(&(q6core_lcl.cmd_lock));
+ ocm_core_open();
+ if (q6core_lcl.core_handle_q == NULL) {
+ pr_err("%s: apr registration for CORE failed\n", __func__);
+ ret = -ENODEV;
+ goto fail_cmd;
+ }
+
+ get_lvr_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ get_lvr_cmd.hdr.pkt_size =
+ sizeof(struct avcs_cmd_get_license_validation_result);
+
+ get_lvr_cmd.hdr.src_port = 0;
+ get_lvr_cmd.hdr.dest_port = 0;
+ get_lvr_cmd.hdr.token = 0;
+ get_lvr_cmd.hdr.opcode = AVCS_CMD_GET_LICENSE_VALIDATION_RESULT;
+ get_lvr_cmd.id = module_id;
+
+
+ ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &get_lvr_cmd);
+ if (ret < 0) {
+ pr_err("%s: license_validation request failed, err %d\n",
+ __func__, ret);
+ ret = -EREMOTE;
+ goto fail_cmd;
+ }
+
+ q6core_lcl.cmd_resp_received_flag &= ~(FLAG_CMDRSP_LICENSE_RESULT);
+ mutex_unlock(&(q6core_lcl.cmd_lock));
+ ret = wait_event_timeout(q6core_lcl.cmd_req_wait,
+ (q6core_lcl.cmd_resp_received_flag ==
+ FLAG_CMDRSP_LICENSE_RESULT),
+ msecs_to_jiffies(TIMEOUT_MS));
+ mutex_lock(&(q6core_lcl.cmd_lock));
+ if (!ret) {
+ pr_err("%s: wait_event timeout for CMDRSP_LICENSE_RESULT\n",
+ __func__);
+ ret = -ETIME;
+ goto fail_cmd;
+ }
+ q6core_lcl.cmd_resp_received_flag &= ~(FLAG_CMDRSP_LICENSE_RESULT);
+ ret = q6core_lcl.cmd_resp_payload.cmdrsp_license_result.result;
+
+fail_cmd:
+ mutex_unlock(&(q6core_lcl.cmd_lock));
+ pr_info("%s: cmdrsp_license_result.result = 0x%x for module 0x%x\n",
+ __func__, ret, module_id);
+ return ret;
+}
+
+int core_dts_eagle_set(int size, char *data)
+{
+ struct adsp_dts_eagle *payload = NULL;
+ int rc = 0, size_aligned4byte;
+
+ pr_debug("DTS_EAGLE_CORE - %s\n", __func__);
+ if (size <= 0 || !data) {
+ pr_err("DTS_EAGLE_CORE - %s: invalid size %i or pointer %pK.\n",
+ __func__, size, data);
+ return -EINVAL;
+ }
+
+ size_aligned4byte = (size+3) & 0xFFFFFFFC;
+ mutex_lock(&(q6core_lcl.cmd_lock));
+ ocm_core_open();
+ if (q6core_lcl.core_handle_q) {
+ payload = kzalloc(sizeof(struct adsp_dts_eagle) +
+ size_aligned4byte, GFP_KERNEL);
+ if (!payload) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+ payload->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ payload->hdr.pkt_size = sizeof(struct adsp_dts_eagle) +
+ size_aligned4byte;
+ payload->hdr.src_port = 0;
+ payload->hdr.dest_port = 0;
+ payload->hdr.token = 0;
+ payload->hdr.opcode = ADSP_CMD_SET_DTS_EAGLE_DATA_ID;
+ payload->id = DTS_EAGLE_LICENSE_ID;
+ payload->overwrite = 1;
+ payload->size = size;
+ memcpy(payload->data, data, size);
+ rc = apr_send_pkt(q6core_lcl.core_handle_q,
+ (uint32_t *)payload);
+ if (rc < 0) {
+ pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n",
+ __func__, payload->hdr.opcode, rc);
+ }
+ kfree(payload);
+ }
+
+exit:
+ mutex_unlock(&(q6core_lcl.cmd_lock));
+ return rc;
+}
+
+int core_dts_eagle_get(int id, int size, char *data)
+{
+ struct apr_hdr ah;
+ int rc = 0;
+
+ pr_debug("DTS_EAGLE_CORE - %s\n", __func__);
+ if (size <= 0 || !data) {
+ pr_err("DTS_EAGLE_CORE - %s: invalid size %i or pointer %pK.\n",
+ __func__, size, data);
+ return -EINVAL;
+ }
+ mutex_lock(&(q6core_lcl.cmd_lock));
+ ocm_core_open();
+ if (q6core_lcl.core_handle_q) {
+ ah.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ ah.pkt_size = sizeof(struct apr_hdr);
+ ah.src_port = 0;
+ ah.dest_port = 0;
+ ah.token = 0;
+ ah.opcode = id;
+
+ q6core_lcl.bus_bw_resp_received = 0;
+ generic_get_data = kzalloc(sizeof(struct generic_get_data_)
+ + size, GFP_KERNEL);
+ if (!generic_get_data) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ rc = apr_send_pkt(q6core_lcl.core_handle_q,
+ (uint32_t *)&ah);
+ if (rc < 0) {
+ pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n",
+ __func__, ah.opcode, rc);
+ goto exit;
+ }
+
+ rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!rc) {
+ pr_err("DTS_EAGLE_CORE - %s: EAGLE get params timed out\n",
+ __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+ if (generic_get_data->valid) {
+ rc = 0;
+ memcpy(data, generic_get_data->ints, size);
+ } else {
+ rc = -EINVAL;
+ pr_err("DTS_EAGLE_CORE - %s: EAGLE get params problem getting data - check callback error value\n",
+ __func__);
+ }
+ }
+
+exit:
+ kfree(generic_get_data);
+ generic_get_data = NULL;
+ mutex_unlock(&(q6core_lcl.cmd_lock));
+ return rc;
+}
+
+uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
+{
+ struct adsp_dolby_manufacturer_id payload;
+ int rc = 0;
+
+ pr_debug("%s: manufacturer_id :%d\n", __func__, manufacturer_id);
+ mutex_lock(&(q6core_lcl.cmd_lock));
+ ocm_core_open();
+ if (q6core_lcl.core_handle_q) {
+ payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ payload.hdr.pkt_size =
+ sizeof(struct adsp_dolby_manufacturer_id);
+ payload.hdr.src_port = 0;
+ payload.hdr.dest_port = 0;
+ payload.hdr.token = 0;
+ payload.hdr.opcode = ADSP_CMD_SET_DOLBY_MANUFACTURER_ID;
+ payload.manufacturer_id = manufacturer_id;
+ pr_debug("%s: Send Dolby security opcode=0x%x manufacturer ID = %d\n",
+ __func__,
+ payload.hdr.opcode, payload.manufacturer_id);
+ rc = apr_send_pkt(q6core_lcl.core_handle_q,
+ (uint32_t *)&payload);
+ if (rc < 0)
+ pr_err("%s: SET_DOLBY_MANUFACTURER_ID failed op[0x%x]rc[%d]\n",
+ __func__, payload.hdr.opcode, rc);
+ }
+ mutex_unlock(&(q6core_lcl.cmd_lock));
+ return rc;
+}
+
+bool q6core_is_adsp_ready(void)
+{
+ int rc;
+ bool ret = false;
+ struct apr_hdr hdr;
+
+ pr_debug("%s: enter\n", __func__);
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
+ hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
+
+ mutex_lock(&(q6core_lcl.cmd_lock));
+ ocm_core_open();
+ q6core_lcl.bus_bw_resp_received = 0;
+ rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
+ if (rc < 0) {
+ pr_err("%s: Get ADSP state APR packet send event %d\n",
+ __func__, rc);
+ goto bail;
+ }
+
+ rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
+ if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
+ /* ensure to read updated param by callback thread */
+ rmb();
+ ret = !!q6core_lcl.param;
+ }
+bail:
+ pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
+ mutex_unlock(&(q6core_lcl.cmd_lock));
+ return ret;
+}
+
+
+static int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id,
+ uint32_t *bufsz, uint32_t bufcnt, uint32_t *map_handle)
+{
+ struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+ struct avs_shared_map_region_payload *mregions = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ int ret = 0;
+ int i = 0;
+ int cmd_size = 0;
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
+ + sizeof(struct avs_shared_map_region_payload)
+ * bufcnt;
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (mmap_region_cmd == NULL)
+ return -ENOMEM;
+
+ mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
+ mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mmap_regions->hdr.pkt_size = cmd_size;
+ mmap_regions->hdr.src_port = 0;
+ mmap_regions->hdr.dest_port = 0;
+ mmap_regions->hdr.token = 0;
+ mmap_regions->hdr.opcode = AVCS_CMD_SHARED_MEM_MAP_REGIONS;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
+ mmap_regions->num_regions = bufcnt & 0x00ff;
+ mmap_regions->property_flag = 0x00;
+
+ payload = ((u8 *) mmap_region_cmd +
+ sizeof(struct avs_cmd_shared_mem_map_regions));
+ mregions = (struct avs_shared_map_region_payload *)payload;
+
+ for (i = 0; i < bufcnt; i++) {
+ mregions->shm_addr_lsw = lower_32_bits(buf_add[i]);
+ mregions->shm_addr_msw =
+ msm_audio_populate_upper_32_bits(buf_add[i]);
+ mregions->mem_size_bytes = bufsz[i];
+ ++mregions;
+ }
+
+ pr_debug("%s: sending memory map, addr %pK, size %d, bufcnt = %d\n",
+ __func__, buf_add, bufsz[0], mmap_regions->num_regions);
+
+ *map_handle = 0;
+ q6core_lcl.bus_bw_resp_received = 0;
+ ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)
+ mmap_regions);
+ if (ret < 0) {
+ pr_err("%s: mmap regions failed %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: timeout. waited for memory map\n", __func__);
+ ret = -ETIME;
+ goto done;
+ }
+
+ *map_handle = q6core_lcl.mem_map_cal_handle;
+done:
+ kfree(mmap_region_cmd);
+ return ret;
+}
+
+static int q6core_memory_unmap_regions(uint32_t mem_map_handle)
+{
+ struct avs_cmd_shared_mem_unmap_regions unmap_regions;
+ int ret = 0;
+
+ memset(&unmap_regions, 0, sizeof(unmap_regions));
+ unmap_regions.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ unmap_regions.hdr.pkt_size = sizeof(unmap_regions);
+ unmap_regions.hdr.src_svc = APR_SVC_ADSP_CORE;
+ unmap_regions.hdr.src_domain = APR_DOMAIN_APPS;
+ unmap_regions.hdr.src_port = 0;
+ unmap_regions.hdr.dest_svc = APR_SVC_ADSP_CORE;
+ unmap_regions.hdr.dest_domain = APR_DOMAIN_ADSP;
+ unmap_regions.hdr.dest_port = 0;
+ unmap_regions.hdr.token = 0;
+ unmap_regions.hdr.opcode = AVCS_CMD_SHARED_MEM_UNMAP_REGIONS;
+ unmap_regions.mem_map_handle = mem_map_handle;
+
+ q6core_lcl.bus_bw_resp_received = 0;
+
+ pr_debug("%s: unmap regions map handle %d\n",
+ __func__, mem_map_handle);
+
+ ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)
+ &unmap_regions);
+ if (ret < 0) {
+ pr_err("%s: unmap regions failed %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: timeout. waited for memory_unmap\n",
+ __func__);
+ ret = -ETIME;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int q6core_dereg_all_custom_topologies(void)
+{
+ int ret = 0;
+ struct avcs_cmd_deregister_topologies dereg_top;
+
+ memset(&dereg_top, 0, sizeof(dereg_top));
+ dereg_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ dereg_top.hdr.pkt_size = sizeof(dereg_top);
+ dereg_top.hdr.src_svc = APR_SVC_ADSP_CORE;
+ dereg_top.hdr.src_domain = APR_DOMAIN_APPS;
+ dereg_top.hdr.src_port = 0;
+ dereg_top.hdr.dest_svc = APR_SVC_ADSP_CORE;
+ dereg_top.hdr.dest_domain = APR_DOMAIN_ADSP;
+ dereg_top.hdr.dest_port = 0;
+ dereg_top.hdr.token = 0;
+ dereg_top.hdr.opcode = AVCS_CMD_DEREGISTER_TOPOLOGIES;
+ dereg_top.payload_addr_lsw = 0;
+ dereg_top.payload_addr_msw = 0;
+ dereg_top.mem_map_handle = 0;
+ dereg_top.payload_size = 0;
+ dereg_top.mode = AVCS_MODE_DEREGISTER_ALL_CUSTOM_TOPOLOGIES;
+
+ q6core_lcl.bus_bw_resp_received = 0;
+
+ pr_debug("%s: Deregister topologies mode %d\n",
+ __func__, dereg_top.mode);
+
+ ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &dereg_top);
+ if (ret < 0) {
+ pr_err("%s: Deregister topologies failed %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout for Deregister topologies\n",
+ __func__);
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int q6core_send_custom_topologies(void)
+{
+ int ret = 0;
+ int ret2 = 0;
+ struct cal_block_data *cal_block = NULL;
+ struct avcs_cmd_register_topologies reg_top;
+
+ if (!q6core_is_adsp_ready()) {
+ pr_err("%s: ADSP is not ready!\n", __func__);
+ return -ENODEV;
+ }
+
+ memset(®_top, 0, sizeof(reg_top));
+ mutex_lock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock);
+ mutex_lock(&q6core_lcl.cmd_lock);
+
+ cal_block = cal_utils_get_only_cal_block(
+ q6core_lcl.cal_data[CUST_TOP_CAL]);
+ if (cal_block == NULL) {
+ pr_debug("%s: cal block is NULL!\n", __func__);
+ goto unlock;
+ }
+ if (cal_block->cal_data.size <= 0) {
+ pr_debug("%s: cal size is %zd not sending\n",
+ __func__, cal_block->cal_data.size);
+ goto unlock;
+ }
+
+ q6core_dereg_all_custom_topologies();
+
+ ret = q6core_map_memory_regions(&cal_block->cal_data.paddr, 0,
+ (uint32_t *)&cal_block->map_data.map_size, 1,
+ &cal_block->map_data.q6map_handle);
+ if (!ret) {
+ pr_err("%s: q6core_map_memory_regions failed\n", __func__);
+ goto unlock;
+ }
+
+ reg_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ reg_top.hdr.pkt_size = sizeof(reg_top);
+ reg_top.hdr.src_svc = APR_SVC_ADSP_CORE;
+ reg_top.hdr.src_domain = APR_DOMAIN_APPS;
+ reg_top.hdr.src_port = 0;
+ reg_top.hdr.dest_svc = APR_SVC_ADSP_CORE;
+ reg_top.hdr.dest_domain = APR_DOMAIN_ADSP;
+ reg_top.hdr.dest_port = 0;
+ reg_top.hdr.token = 0;
+ reg_top.hdr.opcode = AVCS_CMD_REGISTER_TOPOLOGIES;
+ reg_top.payload_addr_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ reg_top.payload_addr_msw =
+ msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
+ reg_top.mem_map_handle = cal_block->map_data.q6map_handle;
+ reg_top.payload_size = cal_block->cal_data.size;
+
+ q6core_lcl.adsp_status = 0;
+ q6core_lcl.bus_bw_resp_received = 0;
+
+ pr_debug("%s: Register topologies addr %pK, size %zd, map handle %d\n",
+ __func__, &cal_block->cal_data.paddr, cal_block->cal_data.size,
+ cal_block->map_data.q6map_handle);
+
+ ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) ®_top);
+ if (ret < 0) {
+ pr_err("%s: Register topologies failed %d\n",
+ __func__, ret);
+ goto unmap;
+ }
+
+ ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout for Register topologies\n",
+ __func__);
+ goto unmap;
+ }
+
+ if (q6core_lcl.adsp_status < 0)
+ ret = q6core_lcl.adsp_status;
+unmap:
+ ret2 = q6core_memory_unmap_regions(cal_block->map_data.q6map_handle);
+ if (!ret2) {
+ pr_err("%s: q6core_memory_unmap_regions failed for map handle %d\n",
+ __func__, cal_block->map_data.q6map_handle);
+ ret = ret2;
+ goto unlock;
+ }
+
+unlock:
+ mutex_unlock(&q6core_lcl.cmd_lock);
+ mutex_unlock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock);
+
+ return ret;
+}
+
+static int get_cal_type_index(int32_t cal_type)
+{
+ int ret = -EINVAL;
+
+ switch (cal_type) {
+ case AUDIO_CORE_METAINFO_CAL_TYPE:
+ ret = META_CAL;
+ break;
+ case CORE_CUSTOM_TOPOLOGIES_CAL_TYPE:
+ ret = CUST_TOP_CAL;
+ break;
+ default:
+ pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
+ }
+ return ret;
+}
+
+static int q6core_alloc_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+
+ ret = cal_utils_alloc_cal(data_size, data,
+ q6core_lcl.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int q6core_dealloc_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+
+ ret = cal_utils_dealloc_cal(data_size, data,
+ q6core_lcl.cal_data[cal_index]);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int q6core_set_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+
+ ret = cal_utils_set_cal(data_size, data,
+ q6core_lcl.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ goto done;
+ }
+
+ if (cal_index == CUST_TOP_CAL)
+ ret = q6core_send_custom_topologies();
+done:
+ return ret;
+}
+
+static void q6core_delete_cal_data(void)
+{
+ pr_debug("%s:\n", __func__);
+
+ cal_utils_destroy_cal_types(CORE_MAX_CAL, q6core_lcl.cal_data);
+}
+
+
+static int q6core_init_cal_data(void)
+{
+ int ret = 0;
+ struct cal_type_info cal_type_info[] = {
+ {{AUDIO_CORE_METAINFO_CAL_TYPE,
+ {q6core_alloc_cal, q6core_dealloc_cal, NULL,
+ q6core_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{CORE_CUSTOM_TOPOLOGIES_CAL_TYPE,
+ {q6core_alloc_cal, q6core_dealloc_cal, NULL,
+ q6core_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} }
+ };
+ pr_debug("%s:\n", __func__);
+
+ ret = cal_utils_create_cal_types(CORE_MAX_CAL,
+ q6core_lcl.cal_data, cal_type_info);
+ if (ret < 0) {
+ pr_err("%s: could not create cal type!\n",
+ __func__);
+ goto err;
+ }
+
+ return ret;
+err:
+ q6core_delete_cal_data();
+ return ret;
+}
+
+static int __init core_init(void)
+{
+ init_waitqueue_head(&q6core_lcl.bus_bw_req_wait);
+ q6core_lcl.bus_bw_resp_received = 0;
+
+ q6core_lcl.core_handle_q = NULL;
+
+ init_waitqueue_head(&q6core_lcl.cmd_req_wait);
+ q6core_lcl.cmd_resp_received_flag = FLAG_NONE;
+ mutex_init(&q6core_lcl.cmd_lock);
+ q6core_lcl.mem_map_cal_handle = 0;
+ q6core_lcl.adsp_status = 0;
+
+ q6core_init_cal_data();
+ return 0;
+}
+module_init(core_init);
+
+static void __exit core_exit(void)
+{
+ mutex_destroy(&q6core_lcl.cmd_lock);
+ q6core_delete_cal_data();
+}
+module_exit(core_exit);
+MODULE_DESCRIPTION("ADSP core driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
new file mode 100644
index 0000000..d761cf5
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -0,0 +1,1950 @@
+/*
+ * Copyright (c) 2013-2017, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <sound/q6core.h>
+#include <sound/q6lsm.h>
+#include <asm/ioctls.h>
+#include <linux/memory.h>
+#include <linux/msm_audio_ion.h>
+#include <sound/q6afe-v2.h>
+#include <sound/audio_cal_utils.h>
+#include <sound/adsp_err.h>
+
+#define APR_TIMEOUT (5 * HZ)
+#define LSM_ALIGN_BOUNDARY 512
+#define LSM_SAMPLE_RATE 16000
+#define QLSM_PARAM_ID_MINOR_VERSION 1
+static int lsm_afe_port;
+
+enum {
+ LSM_CUSTOM_TOP_IDX,
+ LSM_TOP_IDX,
+ LSM_CAL_IDX,
+ LSM_MAX_CAL_IDX
+};
+
+enum {
+ CMD_STATE_CLEARED = 0,
+ CMD_STATE_WAIT_RESP = 1,
+};
+
+enum {
+ LSM_INVALID_SESSION_ID = 0,
+ LSM_MIN_SESSION_ID = 1,
+ LSM_MAX_SESSION_ID = 8,
+ LSM_CONTROL_SESSION = 0x0F,
+};
+
+#define CHECK_SESSION(x) (x < LSM_MIN_SESSION_ID || x > LSM_MAX_SESSION_ID)
+struct lsm_common {
+ void *apr;
+ atomic_t apr_users;
+ struct lsm_client common_client[LSM_MAX_SESSION_ID + 1];
+
+ int set_custom_topology;
+ struct cal_type_data *cal_data[LSM_MAX_CAL_IDX];
+
+ struct mutex apr_lock;
+};
+
+struct lsm_module_param_ids {
+ uint32_t module_id;
+ uint32_t param_id;
+};
+
+static struct lsm_common lsm_common;
+/*
+ * mmap_handle_p can point either client->sound_model.mem_map_handle or
+ * lsm_common.mmap_handle_for_cal.
+ * mmap_lock must be held while accessing this.
+ */
+static spinlock_t mmap_lock;
+static uint32_t *mmap_handle_p;
+
+static spinlock_t lsm_session_lock;
+static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1];
+
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
+static int q6lsm_send_cal(struct lsm_client *client, u32 set_params_opcode);
+static int q6lsm_memory_map_regions(struct lsm_client *client,
+ dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
+ uint32_t *mmap_p);
+static int q6lsm_memory_unmap_regions(struct lsm_client *client,
+ uint32_t handle);
+
+static void q6lsm_set_param_hdr_info(
+ struct lsm_set_params_hdr *param_hdr,
+ u32 payload_size, u32 addr_lsw, u32 addr_msw,
+ u32 mmap_handle)
+{
+ param_hdr->data_payload_size = payload_size;
+ param_hdr->data_payload_addr_lsw = addr_lsw;
+ param_hdr->data_payload_addr_msw = addr_msw;
+ param_hdr->mem_map_handle = mmap_handle;
+}
+
+static void q6lsm_set_param_common(
+ struct lsm_param_payload_common *common,
+ struct lsm_module_param_ids *ids,
+ u32 param_size, u32 set_param_version)
+{
+ common->module_id = ids->module_id;
+ common->param_id = ids->param_id;
+
+ switch (set_param_version) {
+ case LSM_SESSION_CMD_SET_PARAMS_V2:
+ common->p_size.param_size = param_size;
+ break;
+ case LSM_SESSION_CMD_SET_PARAMS:
+ default:
+ common->p_size.sr.param_size =
+ (u16) param_size;
+ common->p_size.sr.reserved = 0;
+ break;
+ }
+}
+
+static int q6lsm_callback(struct apr_client_data *data, void *priv)
+{
+ struct lsm_client *client = (struct lsm_client *)priv;
+ uint32_t token;
+ uint32_t *payload;
+
+ if (!client || !data) {
+ pr_err("%s: client %pK data %pK\n",
+ __func__, client, data);
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
+ __func__, data->opcode, data->reset_event,
+ data->reset_proc);
+
+ cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX,
+ lsm_common.cal_data);
+ mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
+ lsm_common.set_custom_topology = 1;
+ mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
+ return 0;
+ }
+
+ payload = data->payload;
+ pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n"
+ "payload [0] = 0x%x\n", __func__, client->session,
+ data->opcode, data->token, data->payload_size, payload[0]);
+ if (data->opcode == LSM_DATA_EVENT_READ_DONE) {
+ struct lsm_cmd_read_done read_done;
+
+ token = data->token;
+ if (data->payload_size > sizeof(read_done)) {
+ pr_err("%s: read done error payload size %d expected size %zd\n",
+ __func__, data->payload_size,
+ sizeof(read_done));
+ return -EINVAL;
+ }
+ pr_debug("%s: opcode %x status %x lsw %x msw %x mem_map handle %x\n",
+ __func__, data->opcode, payload[0], payload[1],
+ payload[2], payload[3]);
+ read_done.status = payload[0];
+ read_done.buf_addr_lsw = payload[1];
+ read_done.buf_addr_msw = payload[2];
+ read_done.mem_map_handle = payload[3];
+ read_done.total_size = payload[4];
+ read_done.offset = payload[5];
+ if (client->cb)
+ client->cb(data->opcode, data->token,
+ (void *)&read_done,
+ client->priv);
+ return 0;
+ } else if (data->opcode == APR_BASIC_RSP_RESULT) {
+ token = data->token;
+ switch (payload[0]) {
+ case LSM_SESSION_CMD_START:
+ case LSM_SESSION_CMD_STOP:
+ case LSM_SESSION_CMD_SET_PARAMS:
+ case LSM_SESSION_CMD_OPEN_TX:
+ case LSM_SESSION_CMD_CLOSE_TX:
+ case LSM_SESSION_CMD_REGISTER_SOUND_MODEL:
+ case LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL:
+ case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
+ case LSM_SESSION_CMD_EOB:
+ case LSM_SESSION_CMD_READ:
+ case LSM_SESSION_CMD_OPEN_TX_V2:
+ case LSM_CMD_ADD_TOPOLOGIES:
+ case LSM_SESSION_CMD_SET_PARAMS_V2:
+ if (token != client->session &&
+ payload[0] !=
+ LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL) {
+ pr_err("%s: Invalid session %d receivced expected %d\n",
+ __func__, token, client->session);
+ return -EINVAL;
+ }
+ client->cmd_err_code = payload[1];
+ if (client->cmd_err_code)
+ pr_err("%s: cmd 0x%x failed status %d\n",
+ __func__, payload[0], client->cmd_err_code);
+ if (atomic_cmpxchg(&client->cmd_state,
+ CMD_STATE_WAIT_RESP,
+ CMD_STATE_CLEARED) ==
+ CMD_STATE_WAIT_RESP)
+ wake_up(&client->cmd_wait);
+ break;
+ default:
+ pr_debug("%s: Unknown command 0x%x\n",
+ __func__, payload[0]);
+ break;
+ }
+ return 0;
+ }
+
+ if (client->cb)
+ client->cb(data->opcode, data->token, data->payload,
+ client->priv);
+
+ return 0;
+}
+
+static int q6lsm_session_alloc(struct lsm_client *client)
+{
+ unsigned long flags;
+ int n, ret = -ENOMEM;
+
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
+ if (!lsm_session[n]) {
+ lsm_session[n] = client;
+ ret = n;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+ pr_debug("%s: Alloc Session %d", __func__, n);
+ return ret;
+}
+
+static void q6lsm_session_free(struct lsm_client *client)
+{
+ unsigned long flags;
+
+ pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ lsm_session[client->session] = LSM_INVALID_SESSION_ID;
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+ client->session = LSM_INVALID_SESSION_ID;
+}
+
+static void *q6lsm_mmap_apr_reg(void)
+{
+ if (atomic_inc_return(&lsm_common.apr_users) == 1) {
+ lsm_common.apr =
+ apr_register("ADSP", "LSM", q6lsm_mmapcallback,
+ 0x0FFFFFFFF, &lsm_common);
+ if (!lsm_common.apr) {
+ pr_debug("%s: Unable to register APR LSM common port\n",
+ __func__);
+ atomic_dec(&lsm_common.apr_users);
+ }
+ }
+ return lsm_common.apr;
+}
+
+static int q6lsm_mmap_apr_dereg(void)
+{
+ if (atomic_read(&lsm_common.apr_users) <= 0) {
+ WARN("%s: APR common port already closed\n", __func__);
+ } else {
+ if (atomic_dec_return(&lsm_common.apr_users) == 0) {
+ apr_deregister(lsm_common.apr);
+ pr_debug("%s: APR De-Register common port\n", __func__);
+ }
+ }
+ return 0;
+}
+
+struct lsm_client *q6lsm_client_alloc(lsm_app_cb cb, void *priv)
+{
+ struct lsm_client *client;
+ int n;
+
+ client = kzalloc(sizeof(struct lsm_client), GFP_KERNEL);
+ if (!client)
+ return NULL;
+ n = q6lsm_session_alloc(client);
+ if (n <= 0) {
+ kfree(client);
+ return NULL;
+ }
+ client->session = n;
+ client->cb = cb;
+ client->priv = priv;
+ if (CHECK_SESSION(client->session)) {
+ pr_err("%s: Client session %d\n",
+ __func__, client->session);
+ kfree(client);
+ return NULL;
+ }
+ pr_debug("%s: Client Session %d\n", __func__, client->session);
+ client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
+ ((client->session) << 8 | client->session),
+ client);
+
+ if (client->apr == NULL) {
+ pr_err("%s: Registration with APR failed\n", __func__);
+ goto fail;
+ }
+
+ pr_debug("%s: Registering the common port with APR\n", __func__);
+ client->mmap_apr = q6lsm_mmap_apr_reg();
+ if (!client->mmap_apr) {
+ pr_err("%s: APR registration failed\n", __func__);
+ goto fail;
+ }
+
+ init_waitqueue_head(&client->cmd_wait);
+ mutex_init(&client->cmd_lock);
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ pr_debug("%s: New client allocated\n", __func__);
+ return client;
+fail:
+ q6lsm_client_free(client);
+ return NULL;
+}
+
+void q6lsm_client_free(struct lsm_client *client)
+{
+ if (!client)
+ return;
+ if (CHECK_SESSION(client->session)) {
+ pr_err("%s: Invalid Session %d\n", __func__, client->session);
+ return;
+ }
+ apr_deregister(client->apr);
+ client->mmap_apr = NULL;
+ q6lsm_session_free(client);
+ q6lsm_mmap_apr_dereg();
+ mutex_destroy(&client->cmd_lock);
+ kfree(client);
+ client = NULL;
+}
+
+/*
+ * q6lsm_apr_send_pkt : If wait == true, hold mutex to prevent from preempting
+ * other thread's wait.
+ * If mmap_handle_p != NULL, disable irq and spin lock to
+ * protect mmap_handle_p
+ */
+static int q6lsm_apr_send_pkt(struct lsm_client *client, void *handle,
+ void *data, bool wait, uint32_t *mmap_p)
+{
+ int ret;
+ unsigned long flags = 0;
+ struct apr_hdr *msg_hdr = (struct apr_hdr *) data;
+
+ pr_debug("%s: enter wait %d\n", __func__, wait);
+ if (wait)
+ mutex_lock(&lsm_common.apr_lock);
+ if (mmap_p) {
+ WARN_ON(!wait);
+ spin_lock_irqsave(&mmap_lock, flags);
+ mmap_handle_p = mmap_p;
+ }
+ atomic_set(&client->cmd_state, CMD_STATE_WAIT_RESP);
+ client->cmd_err_code = 0;
+ ret = apr_send_pkt(handle, data);
+ if (mmap_p)
+ spin_unlock_irqrestore(&mmap_lock, flags);
+
+ if (ret < 0) {
+ pr_err("%s: apr_send_pkt failed %d\n", __func__, ret);
+ } else if (wait) {
+ ret = wait_event_timeout(client->cmd_wait,
+ (atomic_read(&client->cmd_state) ==
+ CMD_STATE_CLEARED),
+ APR_TIMEOUT);
+ if (likely(ret)) {
+ /* q6 returned error */
+ if (client->cmd_err_code) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ client->cmd_err_code));
+ ret = adsp_err_get_lnx_err_code(
+ client->cmd_err_code);
+ } else {
+ ret = 0;
+ }
+ } else {
+ pr_err("%s: wait timedout, apr_opcode = 0x%x, size = %d\n",
+ __func__, msg_hdr->opcode, msg_hdr->pkt_size);
+ /* ret = 0 means wait timed out */
+ ret = -ETIMEDOUT;
+ }
+ } else {
+ ret = 0;
+ }
+ if (wait)
+ mutex_unlock(&lsm_common.apr_lock);
+
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+ return ret;
+}
+
+static void q6lsm_add_hdr(struct lsm_client *client, struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg)
+{
+ pr_debug("%s: pkt_size %d cmd_flg %d session %d\n", __func__,
+ pkt_size, cmd_flg, client->session);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+ hdr->src_svc = APR_SVC_LSM;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_LSM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((client->session << 8) & 0xFF00) | client->session;
+ hdr->dest_port = ((client->session << 8) & 0xFF00) | client->session;
+ hdr->pkt_size = pkt_size;
+ if (cmd_flg)
+ hdr->token = client->session;
+}
+
+
+static int q6lsm_send_custom_topologies(struct lsm_client *client)
+{
+ int rc;
+ struct cal_block_data *cal_block = NULL;
+ struct lsm_custom_topologies cstm_top;
+
+ if (lsm_common.cal_data[LSM_CUSTOM_TOP_IDX] == NULL) {
+ pr_err("%s: LSM_CUSTOM_TOP_IDX invalid\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ lsm_common.set_custom_topology = 0;
+
+ mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
+ cal_block = cal_utils_get_only_cal_block(
+ lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]);
+ if (!cal_block) {
+ pr_err("%s: Cal block for LSM_CUSTOM_TOP_IDX not found\n",
+ __func__);
+ rc = -EINVAL;
+ goto unlock;
+ }
+
+ if (cal_block->cal_data.size <= 0) {
+ pr_err("%s: Invalid size for LSM_CUSTOM_TOP %zd\n",
+ __func__, cal_block->cal_data.size);
+ rc = -EINVAL;
+ goto unlock;
+ }
+
+ memset(&cstm_top, 0, sizeof(cstm_top));
+ /* Map the memory for out-of-band data */
+ rc = q6lsm_memory_map_regions(client, cal_block->cal_data.paddr,
+ cal_block->map_data.map_size,
+ &cal_block->map_data.q6map_handle);
+ if (rc < 0) {
+ pr_err("%s: Failed to map custom topologied, err = %d\n",
+ __func__, rc);
+ goto unlock;
+ }
+
+ q6lsm_add_hdr(client, &cstm_top.hdr,
+ sizeof(cstm_top), true);
+ cstm_top.hdr.opcode = LSM_CMD_ADD_TOPOLOGIES;
+
+ /*
+ * For ADD_TOPOLOGIES, the dest_port should be 0
+ * Note that source port cannot be zero as it is used
+ * to route the response to a specific client registered
+ * on APR
+ */
+ cstm_top.hdr.dest_port = 0;
+
+ cstm_top.data_payload_addr_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ cstm_top.data_payload_addr_msw =
+ msm_audio_populate_upper_32_bits(
+ cal_block->cal_data.paddr);
+ cstm_top.mem_map_handle = cal_block->map_data.q6map_handle;
+ cstm_top.buffer_size = cal_block->cal_data.size;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &cstm_top, true, NULL);
+ if (rc)
+ pr_err("%s: Failed to add custom top, err = %d\n",
+ __func__, rc);
+ /* go ahead and unmap even if custom top failed */
+ rc = q6lsm_memory_unmap_regions(client,
+ cal_block->map_data.q6map_handle);
+ if (rc) {
+ pr_err("%s: Failed to unmap, err = %d\n",
+ __func__, rc);
+ /* Even if mem unmap failed, treat the cmd as success */
+ rc = 0;
+ }
+
+unlock:
+ mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
+done:
+ return rc;
+}
+
+static int q6lsm_do_open_v2(struct lsm_client *client,
+ uint16_t app_id)
+{
+ int rc;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_lsm_top *lsm_top;
+ struct lsm_stream_cmd_open_tx_v2 open_v2;
+
+ if (lsm_common.cal_data[LSM_TOP_IDX] == NULL) {
+ pr_err("%s: LSM_TOP_IDX invalid\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
+ cal_block = cal_utils_get_only_cal_block(
+ lsm_common.cal_data[LSM_TOP_IDX]);
+ if (!cal_block) {
+ pr_err("%s: Cal block for LSM_TOP_IDX not found\n",
+ __func__);
+ rc = -EINVAL;
+ goto unlock;
+ }
+
+ lsm_top = (struct audio_cal_info_lsm_top *)
+ cal_block->cal_info;
+ if (!lsm_top) {
+ pr_err("%s: cal_info for LSM_TOP_IDX not found\n",
+ __func__);
+ rc = -EINVAL;
+ goto unlock;
+ }
+
+ pr_debug("%s: topology_id = 0x%x, acdb_id = 0x%x, app_type = 0x%x\n",
+ __func__, lsm_top->topology, lsm_top->acdb_id,
+ lsm_top->app_type);
+
+ if (lsm_top->topology == 0) {
+ pr_err("%s: toplogy id not sent for app_type 0x%x\n",
+ __func__, lsm_top->app_type);
+ rc = -EINVAL;
+ goto unlock;
+ }
+
+ client->app_id = lsm_top->app_type;
+ memset(&open_v2, 0, sizeof(open_v2));
+ q6lsm_add_hdr(client, &open_v2.hdr,
+ sizeof(open_v2), true);
+ open_v2.topology_id = lsm_top->topology;
+ open_v2.hdr.opcode = LSM_SESSION_CMD_OPEN_TX_V2;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &open_v2, true, NULL);
+ if (rc)
+ pr_err("%s: open_v2 failed, err = %d\n",
+ __func__, rc);
+ else
+ client->use_topology = true;
+unlock:
+ mutex_unlock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
+done:
+ return rc;
+
+}
+
+void q6lsm_sm_set_param_data(struct lsm_client *client,
+ struct lsm_params_info *p_info,
+ size_t *offset)
+{
+ struct lsm_param_payload_common *param;
+
+ param = (struct lsm_param_payload_common *)
+ client->sound_model.data;
+ param->module_id = p_info->module_id;
+ param->param_id = p_info->param_id;
+ param->p_size.param_size = client->sound_model.size;
+ *offset = sizeof(*param);
+}
+
+int q6lsm_open(struct lsm_client *client, uint16_t app_id)
+{
+ int rc = 0;
+ struct lsm_stream_cmd_open_tx open;
+
+ /* Add Custom topologies if needed */
+ if (lsm_common.set_custom_topology) {
+ rc = q6lsm_send_custom_topologies(client);
+ if (rc)
+ pr_err("%s: Failed to send cust_top, err = %d\n",
+ __func__, rc);
+ }
+
+ /* Try to open with topology first */
+ rc = q6lsm_do_open_v2(client, app_id);
+ if (!rc)
+ /* open_v2 was successful */
+ goto done;
+
+ pr_debug("%s: try without topology\n",
+ __func__);
+
+ memset(&open, 0, sizeof(open));
+ q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
+ switch (client->app_id) {
+ case LSM_VOICE_WAKEUP_APP_ID_V2:
+ open.app_id = client->app_id;
+ break;
+ default:
+ pr_err("%s: default err 0x%x\n", __func__, client->app_id);
+ rc = -EINVAL;
+ break;
+ }
+
+ open.sampling_rate = LSM_SAMPLE_RATE;
+ open.hdr.opcode = LSM_SESSION_CMD_OPEN_TX;
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &open, true, NULL);
+ if (rc)
+ pr_err("%s: Open failed opcode 0x%x, rc %d\n",
+ __func__, open.hdr.opcode, rc);
+ else
+ client->use_topology = false;
+done:
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+static int q6lsm_send_confidence_levels(
+ struct lsm_client *client,
+ struct lsm_module_param_ids *ids,
+ u32 set_param_opcode)
+{
+ u8 *packet;
+ size_t pkt_size;
+ struct lsm_cmd_set_params_conf *conf_params;
+ struct apr_hdr *msg_hdr;
+ struct lsm_param_min_confidence_levels *cfl;
+ uint8_t i = 0;
+ uint8_t padd_size = 0;
+ u8 *conf_levels;
+ int rc;
+ u32 payload_size, param_size;
+
+ padd_size = (4 - (client->num_confidence_levels % 4)) - 1;
+ pkt_size = sizeof(*conf_params) + padd_size +
+ client->num_confidence_levels;
+
+ packet = kzalloc(pkt_size, GFP_KERNEL);
+ if (!packet)
+ return -ENOMEM;
+
+ conf_params = (struct lsm_cmd_set_params_conf *) packet;
+ conf_levels = (u8 *) (packet + sizeof(*conf_params));
+ msg_hdr = &conf_params->msg_hdr;
+ q6lsm_add_hdr(client, msg_hdr,
+ pkt_size, true);
+ msg_hdr->opcode = set_param_opcode;
+ payload_size = pkt_size - sizeof(*msg_hdr) -
+ sizeof(conf_params->params_hdr);
+ q6lsm_set_param_hdr_info(&conf_params->params_hdr,
+ payload_size, 0, 0, 0);
+ cfl = &conf_params->conf_payload;
+ param_size = ((sizeof(uint8_t) + padd_size +
+ client->num_confidence_levels)) *
+ sizeof(uint8_t);
+ q6lsm_set_param_common(&cfl->common, ids,
+ param_size, set_param_opcode);
+ cfl->num_confidence_levels = client->num_confidence_levels;
+
+ pr_debug("%s: CMD PARAM SIZE = %d\n",
+ __func__, param_size);
+ pr_debug("%s: Num conf_level = %d\n",
+ __func__, client->num_confidence_levels);
+
+ memcpy(conf_levels, client->confidence_levels,
+ client->num_confidence_levels);
+ for (i = 0; i < client->num_confidence_levels; i++)
+ pr_debug("%s: Confidence_level[%d] = %d\n",
+ __func__, i, conf_levels[i]);
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ packet, true, NULL);
+ if (rc)
+ pr_err("%s: confidence_levels cmd failed, err = %d\n",
+ __func__, rc);
+ kfree(packet);
+ return rc;
+}
+
+static int q6lsm_send_params(struct lsm_client *client,
+ struct lsm_module_param_ids *opmode_ids,
+ struct lsm_module_param_ids *connectport_ids,
+ u32 set_param_opcode)
+{
+ int rc;
+ struct lsm_cmd_set_opmode_connectport opmode_connectport;
+ struct apr_hdr *msg_hdr;
+ struct lsm_param_connect_to_port *connect_to_port;
+ struct lsm_param_op_mode *op_mode;
+ u32 data_payload_size, param_size;
+
+ msg_hdr = &opmode_connectport.msg_hdr;
+ q6lsm_add_hdr(client, msg_hdr,
+ sizeof(opmode_connectport), true);
+ msg_hdr->opcode = set_param_opcode;
+ data_payload_size = sizeof(opmode_connectport) -
+ sizeof(*msg_hdr) -
+ sizeof(opmode_connectport.params_hdr);
+ q6lsm_set_param_hdr_info(&opmode_connectport.params_hdr,
+ data_payload_size, 0, 0, 0);
+ connect_to_port = &opmode_connectport.connect_to_port;
+ op_mode = &opmode_connectport.op_mode;
+
+ param_size = sizeof(struct lsm_param_op_mode) -
+ sizeof(op_mode->common);
+ q6lsm_set_param_common(&op_mode->common,
+ opmode_ids, param_size,
+ set_param_opcode);
+ op_mode->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+ op_mode->mode = client->mode;
+ op_mode->reserved = 0;
+ pr_debug("%s: mode = 0x%x", __func__, op_mode->mode);
+
+ param_size = (sizeof(struct lsm_param_connect_to_port) -
+ sizeof(connect_to_port->common));
+ q6lsm_set_param_common(&connect_to_port->common,
+ connectport_ids, param_size,
+ set_param_opcode);
+ connect_to_port->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+ connect_to_port->port_id = client->connect_to_port;
+ connect_to_port->reserved = 0;
+ pr_debug("%s: port= %d", __func__, connect_to_port->port_id);
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &opmode_connectport, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, msg_hdr->opcode, rc);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+void set_lsm_port(int lsm_port)
+{
+ lsm_afe_port = lsm_port;
+}
+
+int get_lsm_port(void)
+{
+ return lsm_afe_port;
+}
+
+int q6lsm_set_data(struct lsm_client *client,
+ enum lsm_detection_mode mode,
+ bool detectfailure)
+{
+ int rc = 0;
+ struct lsm_module_param_ids opmode_ids, connectport_ids;
+ struct lsm_module_param_ids conf_levels_ids;
+
+ if (!client->confidence_levels) {
+ /*
+ * It is possible that confidence levels are
+ * not provided. This is not a error condition.
+ * Return gracefully without any error
+ */
+ pr_debug("%s: no conf levels to set\n",
+ __func__);
+ return rc;
+ }
+
+ if (mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
+ client->mode = 0x01;
+ } else if (mode == LSM_MODE_USER_KEYWORD_DETECTION) {
+ client->mode = 0x03;
+ } else {
+ pr_err("%s: Incorrect detection mode %d\n", __func__, mode);
+ rc = -EINVAL;
+ goto err_ret;
+ }
+ client->mode |= detectfailure << 2;
+ client->connect_to_port = get_lsm_port();
+
+ opmode_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ opmode_ids.param_id = LSM_PARAM_ID_OPERATION_MODE;
+
+ connectport_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+
+ rc = q6lsm_send_params(client, &opmode_ids, &connectport_ids,
+ LSM_SESSION_CMD_SET_PARAMS);
+ if (rc) {
+ pr_err("%s: Failed to set lsm config params %d\n",
+ __func__, rc);
+ goto err_ret;
+ }
+
+ conf_levels_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ conf_levels_ids.param_id = LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
+
+ rc = q6lsm_send_confidence_levels(client, &conf_levels_ids,
+ LSM_SESSION_CMD_SET_PARAMS);
+ if (rc) {
+ pr_err("%s: Failed to send conf_levels, err = %d\n",
+ __func__, rc);
+ goto err_ret;
+ }
+
+ rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS);
+ if (rc) {
+ pr_err("%s: Failed to send calibration data %d\n",
+ __func__, rc);
+ goto err_ret;
+ }
+
+err_ret:
+ return rc;
+}
+
+int q6lsm_register_sound_model(struct lsm_client *client,
+ enum lsm_detection_mode mode,
+ bool detectfailure)
+{
+ int rc;
+ struct lsm_cmd_reg_snd_model cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ rc = q6lsm_set_data(client, mode, detectfailure);
+ if (rc) {
+ pr_err("%s: Failed to set lsm data, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
+ cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
+ cmd.model_addr_lsw = lower_32_bits(client->sound_model.phys);
+ cmd.model_addr_msw = msm_audio_populate_upper_32_bits(
+ client->sound_model.phys);
+ cmd.model_size = client->sound_model.size;
+ /* read updated mem_map_handle by q6lsm_mmapcallback */
+ rmb();
+ cmd.mem_map_handle = client->sound_model.mem_map_handle;
+
+ pr_debug("%s: addr %pK, size %d, handle 0x%x\n", __func__,
+ &client->sound_model.phys, cmd.model_size, cmd.mem_map_handle);
+ rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
+ if (rc)
+ pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
+ cmd.hdr.opcode, rc);
+ else
+ pr_debug("%s: Register sound model succeeded\n", __func__);
+
+ return rc;
+}
+
+int q6lsm_deregister_sound_model(struct lsm_client *client)
+{
+ int rc;
+ struct lsm_cmd_reg_snd_model cmd;
+
+ if (!client) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ if (!client->apr) {
+ pr_err("APR client handle NULL\n");
+ return -EINVAL;
+ }
+
+ if (CHECK_SESSION(client->session)) {
+ pr_err("%s: session[%d]", __func__, client->session);
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
+ cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
+ if (rc) {
+ pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
+ cmd.hdr.opcode, rc);
+ } else {
+ pr_debug("%s: Deregister sound model succeeded\n", __func__);
+ }
+
+ q6lsm_snd_model_buf_free(client);
+
+ return rc;
+}
+
+static void q6lsm_add_mmaphdr(struct lsm_client *client, struct apr_hdr *hdr,
+ u32 pkt_size, u32 cmd_flg, u32 token)
+{
+ pr_debug("%s: pkt size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
+ cmd_flg, client->session);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr->src_port = 0x00;
+ hdr->dest_port = client->session;
+ if (cmd_flg)
+ hdr->token = token;
+ hdr->pkt_size = pkt_size;
+}
+
+static int q6lsm_memory_map_regions(struct lsm_client *client,
+ dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
+ uint32_t *mmap_p)
+{
+ struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+ struct avs_shared_map_region_payload *mregions = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ int rc;
+ int cmd_size = 0;
+
+ pr_debug("%s: dma_addr_p 0x%pK, dma_buf_sz %d, mmap_p 0x%pK, session %d\n",
+ __func__, &dma_addr_p, dma_buf_sz, mmap_p,
+ client->session);
+ if (CHECK_SESSION(client->session)) {
+ pr_err("%s: session[%d]", __func__, client->session);
+ return -EINVAL;
+ }
+ cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
+ sizeof(struct avs_shared_map_region_payload);
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (!mmap_region_cmd)
+ return -ENOMEM;
+
+ mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
+ q6lsm_add_mmaphdr(client, &mmap_regions->hdr, cmd_size, true,
+ (client->session << 8));
+
+ mmap_regions->hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ mmap_regions->num_regions = 1;
+ mmap_regions->property_flag = 0x00;
+ payload = ((u8 *)mmap_region_cmd +
+ sizeof(struct avs_cmd_shared_mem_map_regions));
+ mregions = (struct avs_shared_map_region_payload *)payload;
+
+ mregions->shm_addr_lsw = lower_32_bits(dma_addr_p);
+ mregions->shm_addr_msw = msm_audio_populate_upper_32_bits(dma_addr_p);
+ mregions->mem_size_bytes = dma_buf_sz;
+
+ rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
+ true, mmap_p);
+ if (rc)
+ pr_err("%s: Failed mmap_regions opcode 0x%x, rc %d\n",
+ __func__, mmap_regions->hdr.opcode, rc);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ kfree(mmap_region_cmd);
+ return rc;
+}
+
+static int q6lsm_memory_unmap_regions(struct lsm_client *client,
+ uint32_t handle)
+{
+ struct avs_cmd_shared_mem_unmap_regions unmap;
+ int rc = 0;
+ int cmd_size = 0;
+
+ if (CHECK_SESSION(client->session)) {
+ pr_err("%s: session[%d]", __func__, client->session);
+ return -EINVAL;
+ }
+ cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+ q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
+ true, (client->session << 8));
+ unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
+ unmap.mem_map_handle = handle;
+
+ pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
+ rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
+ NULL);
+ if (rc)
+ pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
+ __func__, unmap.hdr.opcode, rc);
+
+ return rc;
+}
+
+static int q6lsm_send_cal(struct lsm_client *client,
+ u32 set_params_opcode)
+{
+ int rc = 0;
+ struct lsm_cmd_set_params params;
+ struct lsm_set_params_hdr *params_hdr = ¶ms.param_hdr;
+ struct apr_hdr *msg_hdr = ¶ms.msg_hdr;
+ struct cal_block_data *cal_block = NULL;
+
+ pr_debug("%s: Session id %d\n", __func__, client->session);
+ if (CHECK_SESSION(client->session)) {
+ pr_err("%s: session[%d]", __func__, client->session);
+ return -EINVAL;
+ }
+
+ if (lsm_common.cal_data[LSM_CAL_IDX] == NULL)
+ goto done;
+
+ mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
+ cal_block = cal_utils_get_only_cal_block(
+ lsm_common.cal_data[LSM_CAL_IDX]);
+ if (cal_block == NULL)
+ goto unlock;
+
+ if (cal_block->cal_data.size <= 0) {
+ pr_debug("%s: No cal to send!\n", __func__);
+ rc = -EINVAL;
+ goto unlock;
+ }
+ if (cal_block->cal_data.size != client->lsm_cal_size) {
+ pr_err("%s: Cal size %zd doesn't match lsm cal size %d\n",
+ __func__, cal_block->cal_data.size,
+ client->lsm_cal_size);
+ rc = -EINVAL;
+ goto unlock;
+ }
+ /* Cache mmap address, only map once or if new addr */
+ lsm_common.common_client[client->session].session = client->session;
+ q6lsm_add_hdr(client, msg_hdr, sizeof(params), true);
+ msg_hdr->opcode = set_params_opcode;
+ q6lsm_set_param_hdr_info(params_hdr,
+ cal_block->cal_data.size,
+ lower_32_bits(client->lsm_cal_phy_addr),
+ msm_audio_populate_upper_32_bits(
+ client->lsm_cal_phy_addr),
+ client->sound_model.mem_map_handle);
+
+ pr_debug("%s: Cal Size = %zd", __func__,
+ cal_block->cal_data.size);
+ rc = q6lsm_apr_send_pkt(client, client->apr, ¶ms, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, msg_hdr->opcode, rc);
+unlock:
+ mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
+done:
+ return rc;
+}
+
+
+int q6lsm_snd_model_buf_free(struct lsm_client *client)
+{
+ int rc;
+
+ pr_debug("%s: Session id %d\n", __func__, client->session);
+ if (CHECK_SESSION(client->session)) {
+ pr_err("%s: session[%d]", __func__, client->session);
+ return -EINVAL;
+ }
+
+ mutex_lock(&client->cmd_lock);
+ rc = q6lsm_memory_unmap_regions(client,
+ client->sound_model.mem_map_handle);
+ if (rc)
+ pr_err("%s: CMD Memory_unmap_regions failed %d\n",
+ __func__, rc);
+
+ if (client->sound_model.data) {
+ msm_audio_ion_free(client->sound_model.client,
+ client->sound_model.handle);
+ client->sound_model.client = NULL;
+ client->sound_model.handle = NULL;
+ client->sound_model.data = NULL;
+ client->sound_model.phys = 0;
+ client->lsm_cal_phy_addr = 0;
+ client->lsm_cal_size = 0;
+ }
+ mutex_unlock(&client->cmd_lock);
+ return rc;
+}
+
+static struct lsm_client *q6lsm_get_lsm_client(int session_id)
+{
+ unsigned long flags;
+ struct lsm_client *client = NULL;
+
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ if (session_id < LSM_MIN_SESSION_ID || session_id > LSM_MAX_SESSION_ID)
+ pr_err("%s: Invalid session %d\n", __func__, session_id);
+ else if (!lsm_session[session_id])
+ pr_err("%s: Not an active session %d\n", __func__, session_id);
+ else
+ client = lsm_session[session_id];
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+ return client;
+}
+
+/*
+ * q6lsm_mmapcallback : atomic context
+ */
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+ unsigned long flags;
+ uint32_t command;
+ uint32_t retcode;
+ uint32_t sid;
+ const uint32_t *payload = data->payload;
+ struct lsm_client *client = NULL;
+
+ if (data->opcode == RESET_EVENTS) {
+ sid = (data->token >> 8) & 0x0F;
+ pr_debug("%s: SSR event received 0x%x, event 0x%x,\n"
+ "proc 0x%x SID 0x%x\n", __func__, data->opcode,
+ data->reset_event, data->reset_proc, sid);
+ lsm_common.common_client[sid].lsm_cal_phy_addr = 0;
+ cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX,
+ lsm_common.cal_data);
+ lsm_common.set_custom_topology = 1;
+ return 0;
+ }
+
+ command = payload[0];
+ retcode = payload[1];
+ sid = (data->token >> 8) & 0x0F;
+ pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x SID 0x%x\n",
+ __func__, data->opcode, command, retcode, sid);
+ client = q6lsm_get_lsm_client(sid);
+ if (!client) {
+ pr_debug("%s: Session %d already freed\n", __func__, sid);
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS:
+ if (atomic_read(&client->cmd_state) == CMD_STATE_WAIT_RESP) {
+ spin_lock_irqsave(&mmap_lock, flags);
+ *mmap_handle_p = command;
+ /* spin_unlock_irqrestore implies barrier */
+ spin_unlock_irqrestore(&mmap_lock, flags);
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ wake_up(&client->cmd_wait);
+ }
+ break;
+ case APR_BASIC_RSP_RESULT:
+ switch (command) {
+ case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ wake_up(&client->cmd_wait);
+ break;
+ case LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS:
+ if (retcode != 0) {
+ /* error state, signal to stop waiting */
+ if (atomic_read(&client->cmd_state) ==
+ CMD_STATE_WAIT_RESP) {
+ spin_lock_irqsave(&mmap_lock, flags);
+ /* implies barrier */
+ spin_unlock_irqrestore(&mmap_lock,
+ flags);
+ atomic_set(&client->cmd_state,
+ CMD_STATE_CLEARED);
+ wake_up(&client->cmd_wait);
+ }
+ }
+ break;
+ default:
+ pr_warn("%s: Unexpected command 0x%x\n", __func__,
+ command);
+ }
+ /* fallthrough */
+ default:
+ pr_debug("%s: command 0x%x return code 0x%x opcode 0x%x\n",
+ __func__, command, retcode, data->opcode);
+ break;
+ }
+ if (client->cb)
+ client->cb(data->opcode, data->token,
+ data->payload, client->priv);
+ return 0;
+}
+
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
+ bool allocate_module_data)
+{
+ int rc = -EINVAL;
+ struct cal_block_data *cal_block = NULL;
+
+ size_t pad_zero = 0, total_mem = 0;
+
+ if (!client || len <= LSM_ALIGN_BOUNDARY)
+ return rc;
+
+ mutex_lock(&client->cmd_lock);
+
+ mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
+ cal_block = cal_utils_get_only_cal_block(
+ lsm_common.cal_data[LSM_CAL_IDX]);
+ if (cal_block == NULL)
+ goto fail;
+
+ pr_debug("%s:Snd Model len = %zd cal size %zd phys addr %pK", __func__,
+ len, cal_block->cal_data.size,
+ &cal_block->cal_data.paddr);
+ if (!cal_block->cal_data.paddr) {
+ pr_err("%s: No LSM calibration set for session", __func__);
+ rc = -EINVAL;
+ goto fail;
+ }
+ if (!client->sound_model.data) {
+
+ /*
+ * if sound module is sent as set_param
+ * Then memory needs to be allocated for
+ * set_param payload as well.
+ */
+ if (allocate_module_data)
+ len += sizeof(struct lsm_param_payload_common);
+
+ client->sound_model.size = len;
+ pad_zero = (LSM_ALIGN_BOUNDARY -
+ (len % LSM_ALIGN_BOUNDARY));
+ if ((len > SIZE_MAX - pad_zero) ||
+ (len + pad_zero >
+ SIZE_MAX - cal_block->cal_data.size)) {
+ pr_err("%s: invalid allocation size, len = %zd, pad_zero =%zd, cal_size = %zd\n",
+ __func__, len, pad_zero,
+ cal_block->cal_data.size);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ total_mem = PAGE_ALIGN(pad_zero + len +
+ cal_block->cal_data.size);
+ pr_debug("%s: Pad zeros sound model %zd Total mem %zd\n",
+ __func__, pad_zero, total_mem);
+ rc = msm_audio_ion_alloc("lsm_client",
+ &client->sound_model.client,
+ &client->sound_model.handle,
+ total_mem,
+ &client->sound_model.phys,
+ &len,
+ &client->sound_model.data);
+ if (rc) {
+ pr_err("%s: Audio ION alloc is failed, rc = %d\n",
+ __func__, rc);
+ goto fail;
+ }
+ pr_debug("%s: Length = %zd\n", __func__, len);
+ client->lsm_cal_phy_addr = (pad_zero +
+ client->sound_model.phys +
+ client->sound_model.size);
+ client->lsm_cal_size = cal_block->cal_data.size;
+ memcpy((client->sound_model.data + pad_zero +
+ client->sound_model.size),
+ (uint32_t *)cal_block->cal_data.kvaddr, client->lsm_cal_size);
+ pr_debug("%s: Copy cal start virt_addr %pK phy_addr %pK\n"
+ "Offset cal virtual Addr %pK\n", __func__,
+ client->sound_model.data, &client->sound_model.phys,
+ (pad_zero + client->sound_model.data +
+ client->sound_model.size));
+ } else {
+ pr_err("%s: sound model busy\n", __func__);
+ rc = -EBUSY;
+ goto fail;
+ }
+ mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
+ mutex_unlock(&client->cmd_lock);
+
+ rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
+ len,
+ &client->sound_model.mem_map_handle);
+ if (rc) {
+ pr_err("%s: CMD Memory_map_regions failed %d\n", __func__, rc);
+ goto exit;
+ }
+
+ return 0;
+fail:
+ mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
+ mutex_unlock(&client->cmd_lock);
+exit:
+ q6lsm_snd_model_buf_free(client);
+ return rc;
+}
+
+static int q6lsm_cmd(struct lsm_client *client, int opcode, bool wait)
+{
+ struct apr_hdr hdr;
+ int rc;
+
+ pr_debug("%s: enter opcode %x wait %d\n", __func__, opcode, wait);
+ q6lsm_add_hdr(client, &hdr, sizeof(hdr), true);
+ switch (opcode) {
+ case LSM_SESSION_CMD_START:
+ case LSM_SESSION_CMD_STOP:
+ case LSM_SESSION_CMD_CLOSE_TX:
+ case LSM_SESSION_CMD_EOB:
+ hdr.opcode = opcode;
+ break;
+ default:
+ pr_err("%s: Invalid opcode 0x%x\n", __func__, opcode);
+ return -EINVAL;
+ }
+ rc = q6lsm_apr_send_pkt(client, client->apr, &hdr, wait, NULL);
+ if (rc)
+ pr_err("%s: Failed commmand 0x%x\n", __func__, hdr.opcode);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+static int q6lsm_send_param_epd_thres(
+ struct lsm_client *client,
+ void *data, struct lsm_module_param_ids *ids)
+{
+ struct snd_lsm_ep_det_thres *ep_det_data;
+ struct lsm_cmd_set_epd_threshold epd_cmd;
+ struct apr_hdr *msg_hdr = &epd_cmd.msg_hdr;
+ struct lsm_set_params_hdr *param_hdr =
+ &epd_cmd.param_hdr;
+ struct lsm_param_epd_thres *epd_thres =
+ &epd_cmd.epd_thres;
+ int rc;
+
+ ep_det_data = (struct snd_lsm_ep_det_thres *) data;
+ q6lsm_add_hdr(client, msg_hdr,
+ sizeof(epd_cmd), true);
+ msg_hdr->opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+ q6lsm_set_param_hdr_info(param_hdr,
+ sizeof(*epd_thres), 0, 0, 0);
+ q6lsm_set_param_common(&epd_thres->common, ids,
+ sizeof(*epd_thres) - sizeof(epd_thres->common),
+ LSM_SESSION_CMD_SET_PARAMS_V2);
+ epd_thres->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+ epd_thres->epd_begin = ep_det_data->epd_begin;
+ epd_thres->epd_end = ep_det_data->epd_end;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &epd_cmd, true, NULL);
+ if (unlikely(rc))
+ pr_err("%s: EPD_THRESHOLD failed, rc %d\n",
+ __func__, rc);
+ return rc;
+}
+
+static int q6lsm_send_param_gain(
+ struct lsm_client *client,
+ u16 gain, struct lsm_module_param_ids *ids)
+{
+ struct lsm_cmd_set_gain lsm_cmd_gain;
+ struct apr_hdr *msg_hdr = &lsm_cmd_gain.msg_hdr;
+ struct lsm_param_gain *lsm_gain = &lsm_cmd_gain.lsm_gain;
+ int rc;
+
+ q6lsm_add_hdr(client, msg_hdr,
+ sizeof(lsm_cmd_gain), true);
+ msg_hdr->opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+ q6lsm_set_param_hdr_info(&lsm_cmd_gain.param_hdr,
+ sizeof(*lsm_gain), 0, 0, 0);
+ q6lsm_set_param_common(&lsm_gain->common, ids,
+ sizeof(*lsm_gain) - sizeof(lsm_gain->common),
+ LSM_SESSION_CMD_SET_PARAMS_V2);
+ lsm_gain->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+ lsm_gain->gain = gain;
+ lsm_gain->reserved = 0;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &lsm_cmd_gain, true, NULL);
+ if (unlikely(rc))
+ pr_err("%s: LSM_GAIN CMD send failed, rc %d\n",
+ __func__, rc);
+ return rc;
+}
+
+int q6lsm_set_one_param(struct lsm_client *client,
+ struct lsm_params_info *p_info, void *data,
+ enum LSM_PARAM_TYPE param_type)
+{
+ int rc = 0, pkt_sz;
+ struct lsm_module_param_ids ids;
+ u8 *packet;
+
+ memset(&ids, 0, sizeof(ids));
+ switch (param_type) {
+ case LSM_ENDPOINT_DETECT_THRESHOLD: {
+ ids.module_id = p_info->module_id;
+ ids.param_id = p_info->param_id;
+ rc = q6lsm_send_param_epd_thres(client, data,
+ &ids);
+ break;
+ }
+
+ case LSM_OPERATION_MODE: {
+ struct snd_lsm_detect_mode *det_mode = data;
+ struct lsm_module_param_ids opmode_ids;
+ struct lsm_module_param_ids connectport_ids;
+
+ if (det_mode->mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
+ client->mode = 0x01;
+ } else if (det_mode->mode == LSM_MODE_USER_KEYWORD_DETECTION) {
+ client->mode = 0x03;
+ } else {
+ pr_err("%s: Incorrect detection mode %d\n",
+ __func__, det_mode->mode);
+ return -EINVAL;
+ }
+
+ client->mode |= det_mode->detect_failure << 2;
+ client->connect_to_port = get_lsm_port();
+
+ opmode_ids.module_id = p_info->module_id;
+ opmode_ids.param_id = p_info->param_id;
+
+ connectport_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
+ connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+
+ rc = q6lsm_send_params(client, &opmode_ids, &connectport_ids,
+ LSM_SESSION_CMD_SET_PARAMS_V2);
+ if (rc)
+ pr_err("%s: OPERATION_MODE failed, rc %d\n",
+ __func__, rc);
+ break;
+ }
+
+ case LSM_GAIN: {
+ struct snd_lsm_gain *lsm_gain = (struct snd_lsm_gain *) data;
+
+ ids.module_id = p_info->module_id;
+ ids.param_id = p_info->param_id;
+ rc = q6lsm_send_param_gain(client, lsm_gain->gain, &ids);
+ if (rc)
+ pr_err("%s: LSM_GAIN command failed, rc %d\n",
+ __func__, rc);
+ break;
+ }
+
+ case LSM_MIN_CONFIDENCE_LEVELS:
+ ids.module_id = p_info->module_id;
+ ids.param_id = p_info->param_id;
+ rc = q6lsm_send_confidence_levels(client, &ids,
+ LSM_SESSION_CMD_SET_PARAMS_V2);
+ if (rc)
+ pr_err("%s: CONFIDENCE_LEVELS cmd failed, rc %d\n",
+ __func__, rc);
+ break;
+ case LSM_REG_SND_MODEL: {
+ struct lsm_cmd_set_params model_param;
+ u32 payload_size;
+
+ memset(&model_param, 0, sizeof(model_param));
+ q6lsm_add_hdr(client, &model_param.msg_hdr,
+ sizeof(model_param), true);
+ model_param.msg_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+ payload_size = p_info->param_size +
+ sizeof(struct lsm_param_payload_common);
+ q6lsm_set_param_hdr_info(&model_param.param_hdr,
+ payload_size,
+ lower_32_bits(client->sound_model.phys),
+ msm_audio_populate_upper_32_bits(
+ client->sound_model.phys),
+ client->sound_model.mem_map_handle);
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &model_param, true, NULL);
+ if (rc) {
+ pr_err("%s: REG_SND_MODEL failed, rc %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS);
+ if (rc)
+ pr_err("%s: Failed to send lsm cal, err = %d\n",
+ __func__, rc);
+ break;
+ }
+
+ case LSM_DEREG_SND_MODEL: {
+ struct lsm_param_payload_common *common;
+ struct lsm_cmd_set_params *param;
+
+ pkt_sz = sizeof(*param) + sizeof(*common);
+ packet = kzalloc(pkt_sz, GFP_KERNEL);
+ if (!packet) {
+ pr_err("%s: No memory for DEREG_SND_MODEL pkt, size = %d\n",
+ __func__, pkt_sz);
+ return -ENOMEM;
+ }
+
+ param = (struct lsm_cmd_set_params *) packet;
+ common = (struct lsm_param_payload_common *)
+ (packet + sizeof(*param));
+ q6lsm_add_hdr(client, ¶m->msg_hdr, pkt_sz, true);
+ param->msg_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+ q6lsm_set_param_hdr_info(¶m->param_hdr,
+ sizeof(*common),
+ 0, 0, 0);
+ ids.module_id = p_info->module_id;
+ ids.param_id = p_info->param_id;
+ q6lsm_set_param_common(common, &ids, 0,
+ LSM_SESSION_CMD_SET_PARAMS_V2);
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ packet, true, NULL);
+ if (rc)
+ pr_err("%s: DEREG_SND_MODEL failed, rc %d\n",
+ __func__, rc);
+ kfree(packet);
+ break;
+ }
+
+ case LSM_CUSTOM_PARAMS: {
+ struct apr_hdr *hdr;
+ u8 *custom_data;
+
+ if (p_info->param_size <
+ sizeof(struct lsm_param_payload_common)) {
+ pr_err("%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ return -EINVAL;
+ }
+
+ pkt_sz = p_info->param_size + sizeof(*hdr);
+ packet = kzalloc(pkt_sz, GFP_KERNEL);
+ if (!packet) {
+ pr_err("%s: no memory for CUSTOM_PARAMS, size = %d\n",
+ __func__, pkt_sz);
+ return -ENOMEM;
+ }
+
+ hdr = (struct apr_hdr *) packet;
+ custom_data = (u8 *) (packet + sizeof(*hdr));
+ q6lsm_add_hdr(client, hdr, pkt_sz, true);
+ hdr->opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+ memcpy(custom_data, data, p_info->param_size);
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ packet, true, NULL);
+ if (rc)
+ pr_err("%s: CUSTOM_PARAMS failed, rc %d\n",
+ __func__, rc);
+ kfree(packet);
+ break;
+ }
+ default:
+ pr_err("%s: wrong param_type 0x%x\n",
+ __func__, p_info->param_type);
+ }
+
+ return rc;
+}
+
+
+int q6lsm_start(struct lsm_client *client, bool wait)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_START, wait);
+}
+
+int q6lsm_stop(struct lsm_client *client, bool wait)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_STOP, wait);
+}
+
+int q6lsm_close(struct lsm_client *client)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_CLOSE_TX, true);
+}
+
+int q6lsm_lab_control(struct lsm_client *client, u32 enable)
+{
+ int rc = 0;
+ struct lsm_params_lab_enable lab_enable;
+ struct lsm_params_lab_config lab_config;
+ struct lsm_module_param_ids lab_ids;
+ u32 param_size;
+
+ if (!client) {
+ pr_err("%s: invalid param client %pK\n", __func__, client);
+ return -EINVAL;
+ }
+ /* enable/disable lab on dsp */
+ q6lsm_add_hdr(client, &lab_enable.msg_hdr, sizeof(lab_enable), true);
+ lab_enable.msg_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+ q6lsm_set_param_hdr_info(&lab_enable.params_hdr,
+ sizeof(struct lsm_lab_enable),
+ 0, 0, 0);
+ param_size = (sizeof(struct lsm_lab_enable) -
+ sizeof(struct lsm_param_payload_common));
+ lab_ids.module_id = LSM_MODULE_ID_LAB;
+ lab_ids.param_id = LSM_PARAM_ID_LAB_ENABLE;
+ q6lsm_set_param_common(&lab_enable.lab_enable.common,
+ &lab_ids, param_size,
+ LSM_SESSION_CMD_SET_PARAMS);
+ lab_enable.lab_enable.enable = (enable) ? 1 : 0;
+ rc = q6lsm_apr_send_pkt(client, client->apr, &lab_enable, true, NULL);
+ if (rc) {
+ pr_err("%s: Lab enable failed rc %d\n", __func__, rc);
+ return rc;
+ }
+ if (!enable)
+ goto exit;
+ /* lab session is being enabled set the config values */
+ q6lsm_add_hdr(client, &lab_config.msg_hdr, sizeof(lab_config), true);
+ lab_config.msg_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+ q6lsm_set_param_hdr_info(&lab_config.params_hdr,
+ sizeof(struct lsm_lab_config),
+ 0, 0, 0);
+ lab_ids.module_id = LSM_MODULE_ID_LAB;
+ lab_ids.param_id = LSM_PARAM_ID_LAB_CONFIG;
+ param_size = (sizeof(struct lsm_lab_config) -
+ sizeof(struct lsm_param_payload_common));
+ q6lsm_set_param_common(&lab_config.lab_config.common,
+ &lab_ids, param_size,
+ LSM_SESSION_CMD_SET_PARAMS);
+ lab_config.lab_config.minor_version = 1;
+ lab_config.lab_config.wake_up_latency_ms = 250;
+ rc = q6lsm_apr_send_pkt(client, client->apr, &lab_config, true, NULL);
+ if (rc) {
+ pr_err("%s: Lab config failed rc %d disable lab\n",
+ __func__, rc);
+ /* Lab config failed disable lab */
+ lab_enable.lab_enable.enable = 0;
+ if (q6lsm_apr_send_pkt(client, client->apr,
+ &lab_enable, true, NULL))
+ pr_err("%s: Lab disable failed\n", __func__);
+ }
+exit:
+ return rc;
+}
+
+int q6lsm_stop_lab(struct lsm_client *client)
+{
+ int rc = 0;
+
+ if (!client) {
+ pr_err("%s: invalid param client %pK\n", __func__, client);
+ return -EINVAL;
+ }
+ rc = q6lsm_cmd(client, LSM_SESSION_CMD_EOB, true);
+ if (rc)
+ pr_err("%s: Lab stop failed %d\n", __func__, rc);
+ return rc;
+}
+
+int q6lsm_read(struct lsm_client *client, struct lsm_cmd_read *read)
+{
+ int rc = 0;
+
+ if (!client || !read) {
+ pr_err("%s: Invalid params client %pK read %pK\n", __func__,
+ client, read);
+ return -EINVAL;
+ }
+ pr_debug("%s: read call memmap handle %x address %x%x size %d\n",
+ __func__, read->mem_map_handle, read->buf_addr_msw,
+ read->buf_addr_lsw, read->buf_size);
+ q6lsm_add_hdr(client, &read->hdr, sizeof(struct lsm_cmd_read), true);
+ read->hdr.opcode = LSM_SESSION_CMD_READ;
+ rc = q6lsm_apr_send_pkt(client, client->apr, read, false, NULL);
+ if (rc)
+ pr_err("%s: read buffer call failed rc %d\n", __func__, rc);
+ return rc;
+}
+
+int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc)
+{
+ int ret = 0, i = 0;
+ size_t allocate_size = 0, len = 0;
+
+ if (!client) {
+ pr_err("%s: invalid client\n", __func__);
+ return -EINVAL;
+ }
+ if (alloc) {
+ if (client->lab_buffer) {
+ pr_err("%s: buffers are allocated period count %d period size %d\n",
+ __func__,
+ client->hw_params.period_count,
+ client->hw_params.buf_sz);
+ return -EINVAL;
+ }
+ allocate_size = client->hw_params.period_count *
+ client->hw_params.buf_sz;
+ allocate_size = PAGE_ALIGN(allocate_size);
+ client->lab_buffer =
+ kzalloc(sizeof(struct lsm_lab_buffer) *
+ client->hw_params.period_count, GFP_KERNEL);
+ if (!client->lab_buffer) {
+ pr_err("%s: memory allocation for lab buffer failed count %d\n"
+ , __func__,
+ client->hw_params.period_count);
+ return -ENOMEM;
+ }
+ ret = msm_audio_ion_alloc("lsm_lab",
+ &client->lab_buffer[0].client,
+ &client->lab_buffer[0].handle,
+ allocate_size, &client->lab_buffer[0].phys,
+ &len,
+ &client->lab_buffer[0].data);
+ if (ret)
+ pr_err("%s: ion alloc failed ret %d size %zd\n",
+ __func__, ret, allocate_size);
+ else {
+ ret = q6lsm_memory_map_regions(client,
+ client->lab_buffer[0].phys, len,
+ &client->lab_buffer[0].mem_map_handle);
+ if (ret) {
+ pr_err("%s: memory map filed ret %d size %zd\n",
+ __func__, ret, len);
+ msm_audio_ion_free(
+ client->lab_buffer[0].client,
+ client->lab_buffer[0].handle);
+ }
+ }
+ if (ret) {
+ pr_err("%s: alloc lab buffer failed ret %d\n",
+ __func__, ret);
+ kfree(client->lab_buffer);
+ client->lab_buffer = NULL;
+ } else {
+ pr_debug("%s: Memory map handle %x phys %pK size %d\n",
+ __func__,
+ client->lab_buffer[0].mem_map_handle,
+ &client->lab_buffer[0].phys,
+ client->hw_params.buf_sz);
+ for (i = 0; i < client->hw_params.period_count; i++) {
+ client->lab_buffer[i].phys =
+ client->lab_buffer[0].phys +
+ (i * client->hw_params.buf_sz);
+ client->lab_buffer[i].size =
+ client->hw_params.buf_sz;
+ client->lab_buffer[i].data =
+ (u8 *)(client->lab_buffer[0].data) +
+ (i * client->hw_params.buf_sz);
+ client->lab_buffer[i].mem_map_handle =
+ client->lab_buffer[0].mem_map_handle;
+ }
+ }
+ } else {
+ ret = q6lsm_memory_unmap_regions(client,
+ client->lab_buffer[0].mem_map_handle);
+ if (!ret)
+ msm_audio_ion_free(
+ client->lab_buffer[0].client,
+ client->lab_buffer[0].handle);
+ else
+ pr_err("%s: unmap failed not freeing memory\n",
+ __func__);
+ kfree(client->lab_buffer);
+ client->lab_buffer = NULL;
+ }
+ return ret;
+}
+
+static int get_cal_type_index(int32_t cal_type)
+{
+ int ret = -EINVAL;
+
+ switch (cal_type) {
+ case LSM_CUST_TOPOLOGY_CAL_TYPE:
+ ret = LSM_CUSTOM_TOP_IDX;
+ break;
+ case LSM_TOPOLOGY_CAL_TYPE:
+ ret = LSM_TOP_IDX;
+ break;
+ case LSM_CAL_TYPE:
+ ret = LSM_CAL_IDX;
+ break;
+ default:
+ pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
+ }
+ return ret;
+}
+
+static int q6lsm_alloc_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_alloc_cal(data_size, data,
+ lsm_common.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int q6lsm_dealloc_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_dealloc_cal(data_size, data,
+ lsm_common.cal_data[cal_index]);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int q6lsm_set_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s:\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_set_cal(data_size, data,
+ lsm_common.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (cal_index == LSM_CUSTOM_TOP_IDX) {
+ mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
+ lsm_common.set_custom_topology = 1;
+ mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
+ }
+
+done:
+ return ret;
+}
+
+static void lsm_delete_cal_data(void)
+{
+ pr_debug("%s:\n", __func__);
+
+ cal_utils_destroy_cal_types(LSM_MAX_CAL_IDX, lsm_common.cal_data);
+}
+
+static int q6lsm_init_cal_data(void)
+{
+ int ret = 0;
+ struct cal_type_info cal_type_info[] = {
+ {{LSM_CUST_TOPOLOGY_CAL_TYPE,
+ {q6lsm_alloc_cal, q6lsm_dealloc_cal, NULL,
+ q6lsm_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{LSM_TOPOLOGY_CAL_TYPE,
+ {NULL, NULL, NULL,
+ q6lsm_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{LSM_CAL_TYPE,
+ {q6lsm_alloc_cal, q6lsm_dealloc_cal, NULL,
+ q6lsm_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} }
+ };
+ pr_debug("%s:\n", __func__);
+
+ ret = cal_utils_create_cal_types(LSM_MAX_CAL_IDX,
+ lsm_common.cal_data, cal_type_info);
+ if (ret < 0) {
+ pr_err("%s: could not create cal type!\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return ret;
+err:
+ lsm_delete_cal_data();
+ return ret;
+}
+
+static int __init q6lsm_init(void)
+{
+ int i = 0;
+
+ pr_debug("%s:\n", __func__);
+ spin_lock_init(&lsm_session_lock);
+ spin_lock_init(&mmap_lock);
+ mutex_init(&lsm_common.apr_lock);
+ for (; i <= LSM_MAX_SESSION_ID; i++) {
+ lsm_common.common_client[i].session = LSM_CONTROL_SESSION;
+ init_waitqueue_head(&lsm_common.common_client[i].cmd_wait);
+ mutex_init(&lsm_common.common_client[i].cmd_lock);
+ atomic_set(&lsm_common.common_client[i].cmd_state,
+ CMD_STATE_CLEARED);
+ }
+
+ if (q6lsm_init_cal_data())
+ pr_err("%s: could not init cal data!\n", __func__);
+
+ return 0;
+}
+
+static void __exit q6lsm_exit(void)
+{
+ lsm_delete_cal_data();
+}
+
+device_initcall(q6lsm_init);
+__exitcall(q6lsm_exit);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
new file mode 100644
index 0000000..54d72be
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -0,0 +1,8425 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/msm_audio_ion.h>
+
+#include <soc/qcom/socinfo.h>
+#include <linux/qdsp6v2/apr_tal.h>
+
+#include "sound/q6audio-v2.h"
+#include "sound/apr_audio-v2.h"
+#include "sound/q6afe-v2.h"
+#include <sound/audio_cal_utils.h>
+#include "q6voice.h"
+#include <sound/adsp_err.h>
+
+#define TIMEOUT_MS 300
+
+
+#define CMD_STATUS_SUCCESS 0
+#define CMD_STATUS_FAIL 1
+
+enum {
+ VOC_TOKEN_NONE,
+ VOIP_MEM_MAP_TOKEN,
+ VOC_CAL_MEM_MAP_TOKEN,
+ VOC_VOICE_HOST_PCM_MAP_TOKEN,
+ VOC_RTAC_MEM_MAP_TOKEN,
+ VOC_SOURCE_TRACKING_MEM_MAP_TOKEN
+};
+
+struct cvd_version_table cvd_version_table_mapping[CVD_INT_VERSION_MAX] = {
+ {CVD_VERSION_DEFAULT, CVD_INT_VERSION_DEFAULT},
+ {CVD_VERSION_0_0, CVD_INT_VERSION_0_0},
+ {CVD_VERSION_2_1, CVD_INT_VERSION_2_1},
+ {CVD_VERSION_2_2, CVD_INT_VERSION_2_2},
+ {CVD_VERSION_2_3, CVD_INT_VERSION_2_3},
+};
+
+static struct common_data common;
+static bool module_initialized;
+
+static int voice_send_enable_vocproc_cmd(struct voice_data *v);
+static int voice_send_netid_timing_cmd(struct voice_data *v);
+static int voice_send_attach_vocproc_cmd(struct voice_data *v);
+static int voice_send_set_device_cmd(struct voice_data *v);
+static int voice_send_vol_step_cmd(struct voice_data *v);
+static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
+ uint32_t mem_handle);
+static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
+static int voice_send_mvm_media_type_cmd(struct voice_data *v);
+static int voice_send_mvm_cvd_version_cmd(struct voice_data *v);
+static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
+static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v);
+static int voice_set_packet_exchange_mode_and_config(uint32_t session_id,
+ uint32_t mode);
+
+static int voice_send_cvs_register_cal_cmd(struct voice_data *v);
+static int voice_send_cvs_deregister_cal_cmd(struct voice_data *v);
+static int voice_send_cvp_create_cmd(struct voice_data *v);
+static int voice_send_cvp_register_dev_cfg_cmd(struct voice_data *v);
+static int voice_send_cvp_deregister_dev_cfg_cmd(struct voice_data *v);
+static int voice_send_cvp_register_cal_cmd(struct voice_data *v);
+static int voice_send_cvp_deregister_cal_cmd(struct voice_data *v);
+static int voice_send_cvp_register_vol_cal_cmd(struct voice_data *v);
+static int voice_send_cvp_deregister_vol_cal_cmd(struct voice_data *v);
+static int voice_send_cvp_device_channels_cmd(struct voice_data *v);
+static int voice_send_cvp_topology_commit_cmd(struct voice_data *v);
+
+static int voice_cvs_stop_playback(struct voice_data *v);
+static int voice_cvs_start_playback(struct voice_data *v);
+static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
+static int voice_cvs_stop_record(struct voice_data *v);
+
+static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv);
+static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
+static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv);
+
+static int voice_send_set_pp_enable_cmd(struct voice_data *v,
+ uint32_t module_id, int enable);
+static int is_cal_memory_allocated(void);
+static bool is_cvd_version_queried(void);
+static int is_voip_memory_allocated(void);
+static int voice_get_cvd_int_version(char *cvd_ver_string);
+static int voice_alloc_cal_mem_map_table(void);
+static int voice_alloc_rtac_mem_map_table(void);
+static int voice_alloc_oob_shared_mem(void);
+static int voice_free_oob_shared_mem(void);
+static int voice_alloc_oob_mem_table(void);
+static int voice_alloc_and_map_oob_mem(struct voice_data *v);
+static void voice_vote_powerstate_to_bms(struct voice_data *v, bool state);
+
+static struct voice_data *voice_get_session_by_idx(int idx);
+
+static int remap_cal_data(struct cal_block_data *cal_block,
+ uint32_t session_id);
+static int voice_unmap_cal_memory(int32_t cal_type,
+ struct cal_block_data *cal_block);
+
+static int is_source_tracking_shared_memomry_allocated(void);
+static int voice_alloc_source_tracking_shared_memory(void);
+static int voice_alloc_and_map_source_tracking_shared_memory(
+ struct voice_data *v);
+static int voice_unmap_and_free_source_tracking_shared_memory(
+ struct voice_data *v);
+static int voice_send_set_sound_focus_cmd(struct voice_data *v,
+ struct sound_focus_param soundFocusData);
+static int voice_send_get_sound_focus_cmd(struct voice_data *v,
+ struct sound_focus_param *soundFocusData);
+static int voice_send_get_source_tracking_cmd(struct voice_data *v,
+ struct source_tracking_param *sourceTrackingData);
+
+static void voice_itr_init(struct voice_session_itr *itr,
+ u32 session_id)
+{
+ if (itr == NULL)
+ return;
+ itr->session_idx = voice_get_idx_for_session(session_id);
+ if (session_id == ALL_SESSION_VSID)
+ itr->cur_idx = 0;
+ else
+ itr->cur_idx = itr->session_idx;
+
+}
+
+static bool voice_itr_get_next_session(struct voice_session_itr *itr,
+ struct voice_data **voice)
+{
+ bool ret = false;
+
+ if (itr == NULL)
+ return false;
+ pr_debug("%s : cur idx = %d session idx = %d\n",
+ __func__, itr->cur_idx, itr->session_idx);
+
+ if (itr->cur_idx <= itr->session_idx) {
+ ret = true;
+ *voice = voice_get_session_by_idx(itr->cur_idx);
+ itr->cur_idx++;
+ } else {
+ *voice = NULL;
+ }
+
+ return ret;
+}
+
+static bool voice_is_valid_session_id(uint32_t session_id)
+{
+ bool ret = false;
+
+ switch (session_id) {
+ case VOICE_SESSION_VSID:
+ case VOICE2_SESSION_VSID:
+ case VOLTE_SESSION_VSID:
+ case VOIP_SESSION_VSID:
+ case QCHAT_SESSION_VSID:
+ case VOWLAN_SESSION_VSID:
+ case VOICEMMODE1_VSID:
+ case VOICEMMODE2_VSID:
+ case ALL_SESSION_VSID:
+ ret = true;
+ break;
+ default:
+ pr_err("%s: Invalid session_id : %x\n", __func__, session_id);
+
+ break;
+ }
+
+ return ret;
+}
+
+static u16 voice_get_mvm_handle(struct voice_data *v)
+{
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return 0;
+ }
+
+ pr_debug("%s: mvm_handle %d\n", __func__, v->mvm_handle);
+
+ return v->mvm_handle;
+}
+
+static void voice_set_mvm_handle(struct voice_data *v, u16 mvm_handle)
+{
+ pr_debug("%s: mvm_handle %d\n", __func__, mvm_handle);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return;
+ }
+
+ v->mvm_handle = mvm_handle;
+}
+
+static u16 voice_get_cvs_handle(struct voice_data *v)
+{
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return 0;
+ }
+
+ pr_debug("%s: cvs_handle %d\n", __func__, v->cvs_handle);
+
+ return v->cvs_handle;
+}
+
+static void voice_set_cvs_handle(struct voice_data *v, u16 cvs_handle)
+{
+ pr_debug("%s: cvs_handle %d\n", __func__, cvs_handle);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return;
+ }
+
+ v->cvs_handle = cvs_handle;
+}
+
+static u16 voice_get_cvp_handle(struct voice_data *v)
+{
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return 0;
+ }
+
+ pr_debug("%s: cvp_handle %d\n", __func__, v->cvp_handle);
+
+ return v->cvp_handle;
+}
+
+static void voice_set_cvp_handle(struct voice_data *v, u16 cvp_handle)
+{
+ pr_debug("%s: cvp_handle %d\n", __func__, cvp_handle);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return;
+ }
+
+ v->cvp_handle = cvp_handle;
+}
+
+char *voc_get_session_name(u32 session_id)
+{
+ char *session_name = NULL;
+
+ if (session_id == common.voice[VOC_PATH_PASSIVE].session_id) {
+ session_name = VOICE_SESSION_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_VOLTE_PASSIVE].session_id) {
+ session_name = VOLTE_SESSION_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id) {
+ session_name = QCHAT_SESSION_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id) {
+ session_name = VOWLAN_SESSION_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_VOICEMMODE1_PASSIVE].session_id) {
+ session_name = VOICEMMODE1_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_VOICEMMODE2_PASSIVE].session_id) {
+ session_name = VOICEMMODE2_NAME;
+ } else if (session_id == common.voice[VOC_PATH_FULL].session_id) {
+ session_name = VOIP_SESSION_NAME;
+ }
+ return session_name;
+}
+
+uint32_t voc_get_session_id(char *name)
+{
+ u32 session_id = 0;
+
+ if (name != NULL) {
+ if (!strcmp(name, "Voice session"))
+ session_id = common.voice[VOC_PATH_PASSIVE].session_id;
+ else if (!strcmp(name, "Voice2 session"))
+ session_id =
+ common.voice[VOC_PATH_VOICE2_PASSIVE].session_id;
+ else if (!strcmp(name, "VoLTE session"))
+ session_id =
+ common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
+ else if (!strcmp(name, "QCHAT session"))
+ session_id =
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id;
+ else if (!strcmp(name, "VoWLAN session"))
+ session_id =
+ common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id;
+ else if (!strcmp(name, "VoiceMMode1"))
+ session_id =
+ common.voice[VOC_PATH_VOICEMMODE1_PASSIVE].session_id;
+ else if (!strcmp(name, "VoiceMMode2"))
+ session_id =
+ common.voice[VOC_PATH_VOICEMMODE2_PASSIVE].session_id;
+ else
+ session_id = common.voice[VOC_PATH_FULL].session_id;
+
+ pr_debug("%s: %s has session id 0x%x\n", __func__, name,
+ session_id);
+ }
+
+ return session_id;
+}
+
+static struct voice_data *voice_get_session(u32 session_id)
+{
+ struct voice_data *v = NULL;
+
+ switch (session_id) {
+ case VOICE_SESSION_VSID:
+ v = &common.voice[VOC_PATH_PASSIVE];
+ break;
+
+ case VOICE2_SESSION_VSID:
+ v = &common.voice[VOC_PATH_VOICE2_PASSIVE];
+ break;
+
+ case VOLTE_SESSION_VSID:
+ v = &common.voice[VOC_PATH_VOLTE_PASSIVE];
+ break;
+
+ case VOIP_SESSION_VSID:
+ v = &common.voice[VOC_PATH_FULL];
+ break;
+
+ case QCHAT_SESSION_VSID:
+ v = &common.voice[VOC_PATH_QCHAT_PASSIVE];
+ break;
+
+ case VOWLAN_SESSION_VSID:
+ v = &common.voice[VOC_PATH_VOWLAN_PASSIVE];
+ break;
+
+ case VOICEMMODE1_VSID:
+ v = &common.voice[VOC_PATH_VOICEMMODE1_PASSIVE];
+ break;
+
+ case VOICEMMODE2_VSID:
+ v = &common.voice[VOC_PATH_VOICEMMODE2_PASSIVE];
+ break;
+
+ case ALL_SESSION_VSID:
+ break;
+
+ default:
+ pr_err("%s: Invalid session_id : %x\n", __func__, session_id);
+
+ break;
+ }
+
+ pr_debug("%s:session_id 0x%x session handle %pK\n",
+ __func__, session_id, v);
+
+ return v;
+}
+
+int voice_get_idx_for_session(u32 session_id)
+{
+ int idx = 0;
+
+ switch (session_id) {
+ case VOICE_SESSION_VSID:
+ idx = VOC_PATH_PASSIVE;
+ break;
+
+ case VOICE2_SESSION_VSID:
+ idx = VOC_PATH_VOICE2_PASSIVE;
+ break;
+
+ case VOLTE_SESSION_VSID:
+ idx = VOC_PATH_VOLTE_PASSIVE;
+ break;
+
+ case VOIP_SESSION_VSID:
+ idx = VOC_PATH_FULL;
+ break;
+
+ case QCHAT_SESSION_VSID:
+ idx = VOC_PATH_QCHAT_PASSIVE;
+ break;
+
+ case VOWLAN_SESSION_VSID:
+ idx = VOC_PATH_VOWLAN_PASSIVE;
+ break;
+
+ case VOICEMMODE1_VSID:
+ idx = VOC_PATH_VOICEMMODE1_PASSIVE;
+ break;
+
+ case VOICEMMODE2_VSID:
+ idx = VOC_PATH_VOICEMMODE2_PASSIVE;
+ break;
+
+ case ALL_SESSION_VSID:
+ idx = MAX_VOC_SESSIONS - 1;
+ break;
+
+ default:
+ pr_err("%s: Invalid session_id : %x\n", __func__, session_id);
+
+ break;
+ }
+
+ return idx;
+}
+
+static struct voice_data *voice_get_session_by_idx(int idx)
+{
+ return ((idx < 0 || idx >= MAX_VOC_SESSIONS) ?
+ NULL : &common.voice[idx]);
+}
+
+static bool is_voip_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_FULL].session_id);
+}
+
+static bool is_volte_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_VOLTE_PASSIVE].session_id);
+}
+
+static bool is_voice2_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
+}
+
+static bool is_qchat_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_QCHAT_PASSIVE].session_id);
+}
+
+static bool is_vowlan_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id);
+}
+
+static bool is_voicemmode1(u32 session_id)
+{
+ return session_id ==
+ common.voice[VOC_PATH_VOICEMMODE1_PASSIVE].session_id;
+}
+
+static bool is_voicemmode2(u32 session_id)
+{
+ return session_id ==
+ common.voice[VOC_PATH_VOICEMMODE2_PASSIVE].session_id;
+}
+
+static bool is_voc_state_active(int voc_state)
+{
+ if ((voc_state == VOC_RUN) ||
+ (voc_state == VOC_CHANGE) ||
+ (voc_state == VOC_STANDBY))
+ return true;
+
+ return false;
+}
+
+static void voc_set_error_state(uint16_t reset_proc)
+{
+ struct voice_data *v = NULL;
+ int i;
+
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ v = &common.voice[i];
+ if (v != NULL)
+ v->voc_state = VOC_ERROR;
+ }
+}
+
+static bool is_other_session_active(u32 session_id)
+{
+ int i;
+ bool ret = false;
+
+ /* Check if there is other active session except the input one */
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ if (common.voice[i].session_id == session_id)
+ continue;
+
+ if (is_voc_state_active(common.voice[i].voc_state)) {
+ ret = true;
+ break;
+ }
+ }
+ pr_debug("%s: ret %d\n", __func__, ret);
+
+ return ret;
+}
+
+static bool is_sub1_vsid(u32 session_id)
+{
+ bool ret;
+
+ switch (session_id) {
+ case VOICE_SESSION_VSID:
+ case VOLTE_SESSION_VSID:
+ case VOWLAN_SESSION_VSID:
+ case VOICEMMODE1_VSID:
+ ret = true;
+ break;
+ default:
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool is_sub2_vsid(u32 session_id)
+{
+ bool ret;
+
+ switch (session_id) {
+ case VOICE2_SESSION_VSID:
+ case VOICEMMODE2_VSID:
+ ret = true;
+ break;
+ default:
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool is_voice_app_id(u32 session_id)
+{
+ return is_sub1_vsid(session_id) || is_sub2_vsid(session_id);
+}
+
+static void init_session_id(void)
+{
+ common.voice[VOC_PATH_PASSIVE].session_id = VOICE_SESSION_VSID;
+ common.voice[VOC_PATH_VOLTE_PASSIVE].session_id = VOLTE_SESSION_VSID;
+ common.voice[VOC_PATH_VOICE2_PASSIVE].session_id = VOICE2_SESSION_VSID;
+ common.voice[VOC_PATH_FULL].session_id = VOIP_SESSION_VSID;
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id = QCHAT_SESSION_VSID;
+ common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id = VOWLAN_SESSION_VSID;
+ common.voice[VOC_PATH_VOICEMMODE1_PASSIVE].session_id =
+ VOICEMMODE1_VSID;
+ common.voice[VOC_PATH_VOICEMMODE2_PASSIVE].session_id =
+ VOICEMMODE2_VSID;
+}
+
+static bool is_cvd_version_queried(void)
+{
+ bool ret = 0;
+
+ if (!strcmp(common.cvd_version, CVD_VERSION_DEFAULT))
+ ret = false;
+ else
+ ret = true;
+
+ return ret;
+}
+
+static int voice_get_cvd_int_version(char *cvd_ver_string)
+{
+ unsigned int idx;
+ int cvd_int_ver = CVD_INT_VERSION_DEFAULT;
+
+ for (idx = 0; idx < CVD_INT_VERSION_MAX; idx++) {
+ if (strcmp((char *)cvd_ver_string,
+ cvd_version_table_mapping[idx].cvd_ver) == 0) {
+ cvd_int_ver =
+ cvd_version_table_mapping[idx].cvd_ver_int;
+ break;
+ }
+ }
+ return cvd_int_ver;
+}
+
+static int voice_apr_register(uint32_t session_id)
+{
+
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&common.common_lock);
+
+ /* register callback to APR */
+ if (common.apr_q6_mvm == NULL) {
+ pr_debug("%s: Start to register MVM callback\n", __func__);
+
+ common.apr_q6_mvm = apr_register("ADSP", "MVM",
+ qdsp_mvm_callback,
+ 0xFFFFFFFF, &common);
+
+ if (common.apr_q6_mvm == NULL) {
+ pr_err("%s: Unable to register MVM\n", __func__);
+ goto err;
+ }
+ }
+
+ if (common.apr_q6_cvs == NULL) {
+ pr_debug("%s: Start to register CVS callback\n", __func__);
+
+ common.apr_q6_cvs = apr_register("ADSP", "CVS",
+ qdsp_cvs_callback,
+ 0xFFFFFFFF, &common);
+
+ if (common.apr_q6_cvs == NULL) {
+ pr_err("%s: Unable to register CVS\n", __func__);
+ goto err;
+ }
+ rtac_set_voice_handle(RTAC_CVS, common.apr_q6_cvs);
+ }
+
+ if (common.apr_q6_cvp == NULL) {
+ pr_debug("%s: Start to register CVP callback\n", __func__);
+
+ common.apr_q6_cvp = apr_register("ADSP", "CVP",
+ qdsp_cvp_callback,
+ 0xFFFFFFFF, &common);
+
+ if (common.apr_q6_cvp == NULL) {
+ pr_err("%s: Unable to register CVP\n", __func__);
+ goto err;
+ }
+ rtac_set_voice_handle(RTAC_CVP, common.apr_q6_cvp);
+ }
+
+ mutex_unlock(&common.common_lock);
+
+ return 0;
+
+err:
+ if (common.apr_q6_cvs != NULL) {
+ apr_deregister(common.apr_q6_cvs);
+ common.apr_q6_cvs = NULL;
+ rtac_set_voice_handle(RTAC_CVS, NULL);
+ }
+ if (common.apr_q6_mvm != NULL) {
+ apr_deregister(common.apr_q6_mvm);
+ common.apr_q6_mvm = NULL;
+ }
+
+ mutex_unlock(&common.common_lock);
+
+ return -ENODEV;
+}
+
+static int voice_send_mvm_cvd_version_cmd(struct voice_data *v)
+{
+ int ret;
+ struct apr_hdr cvd_version_get_cmd;
+ void *apr_mvm;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_mvm = common.apr_q6_mvm;
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Send command to CVD to retrieve Version */
+ cvd_version_get_cmd.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvd_version_get_cmd.pkt_size = APR_PKT_SIZE(
+ APR_HDR_SIZE,
+ sizeof(cvd_version_get_cmd) -
+ APR_HDR_SIZE);
+ cvd_version_get_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvd_version_get_cmd.dest_port = 0;
+ cvd_version_get_cmd.token = 0;
+ cvd_version_get_cmd.opcode = VSS_IVERSION_CMD_GET;
+
+ pr_debug("%s: send CVD version get cmd, pkt size = %d\n",
+ __func__, cvd_version_get_cmd.pkt_size);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *) &cvd_version_get_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error sending command\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout, fall back to default\n",
+ __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+ ret = 0;
+
+done:
+ if (ret) {
+ strlcpy(common.cvd_version, CVD_VERSION_0_0,
+ sizeof(common.cvd_version));
+ }
+ pr_debug("%s: CVD Version retrieved=%s\n",
+ __func__, common.cvd_version);
+
+ return ret;
+}
+
+static int voice_send_dual_control_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ struct mvm_modem_dual_control_session_cmd mvm_voice_ctl_cmd;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: Send Dual Control command to MVM\n", __func__);
+ if (!is_voip_session(v->session_id)) {
+ mvm_handle = voice_get_mvm_handle(v);
+ mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_voice_ctl_cmd.hdr.pkt_size = APR_PKT_SIZE(
+ APR_HDR_SIZE,
+ sizeof(mvm_voice_ctl_cmd) -
+ APR_HDR_SIZE);
+ pr_debug("%s: send mvm Voice Ctl pkt size = %d\n",
+ __func__, mvm_voice_ctl_cmd.hdr.pkt_size);
+ mvm_voice_ctl_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_voice_ctl_cmd.hdr.dest_port = mvm_handle;
+ mvm_voice_ctl_cmd.hdr.token = 0;
+ mvm_voice_ctl_cmd.hdr.opcode =
+ VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL;
+ mvm_voice_ctl_cmd.voice_ctl.enable_flag = true;
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_voice_ctl_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error sending MVM Voice CTL CMD\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ }
+ ret = 0;
+fail:
+ return ret;
+}
+
+
+static int voice_create_mvm_cvs_session(struct voice_data *v)
+{
+ int ret = 0;
+ struct mvm_create_ctl_session_cmd mvm_session_cmd;
+ struct cvs_create_passive_ctl_session_cmd cvs_session_cmd;
+ struct cvs_create_full_ctl_session_cmd cvs_full_ctl_cmd;
+ struct mvm_attach_stream_cmd attach_stream_cmd;
+ void *apr_mvm, *apr_cvs, *apr_cvp;
+ u16 mvm_handle, cvs_handle, cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+ apr_cvs = common.apr_q6_cvs;
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_mvm || !apr_cvs || !apr_cvp) {
+ pr_err("%s: apr_mvm or apr_cvs or apr_cvp is NULL\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ cvs_handle = voice_get_cvs_handle(v);
+ cvp_handle = voice_get_cvp_handle(v);
+
+ pr_debug("%s: mvm_hdl=%d, cvs_hdl=%d\n", __func__,
+ mvm_handle, cvs_handle);
+ /* send cmd to create mvm session and wait for response */
+
+ if (!mvm_handle) {
+ memset(mvm_session_cmd.mvm_session.name, 0,
+ sizeof(mvm_session_cmd.mvm_session.name));
+ if (!is_voip_session(v->session_id)) {
+ mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_session_cmd.hdr.pkt_size = APR_PKT_SIZE(
+ APR_HDR_SIZE,
+ sizeof(mvm_session_cmd) -
+ APR_HDR_SIZE);
+ pr_debug("%s: send mvm create session pkt size = %d\n",
+ __func__, mvm_session_cmd.hdr.pkt_size);
+ mvm_session_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_session_cmd.hdr.dest_port = 0;
+ mvm_session_cmd.hdr.token = 0;
+ mvm_session_cmd.hdr.opcode =
+ VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+ if (is_volte_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ "default volte voice",
+ strlen("default volte voice")+1);
+ } else if (is_voice2_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ VOICE2_SESSION_VSID_STR,
+ strlen(VOICE2_SESSION_VSID_STR)+1);
+ } else if (is_qchat_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ QCHAT_SESSION_VSID_STR,
+ strlen(QCHAT_SESSION_VSID_STR)+1);
+ } else if (is_vowlan_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ VOWLAN_SESSION_VSID_STR,
+ strlen(VOWLAN_SESSION_VSID_STR)+1);
+ } else if (is_voicemmode1(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ VOICEMMODE1_VSID_STR,
+ strlen(VOICEMMODE1_VSID_STR) + 1);
+ } else if (is_voicemmode2(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ VOICEMMODE2_VSID_STR,
+ strlen(VOICEMMODE2_VSID_STR) + 1);
+ } else {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ "default modem voice",
+ strlen("default modem voice")+1);
+ }
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *) &mvm_session_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error sending MVM_CONTROL_SESSION\n",
+ __func__);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ } else {
+ pr_debug("%s: creating MVM full ctrl\n", __func__);
+ mvm_session_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mvm_session_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_session_cmd) -
+ APR_HDR_SIZE);
+ mvm_session_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_session_cmd.hdr.dest_port = 0;
+ mvm_session_cmd.hdr.token = 0;
+ mvm_session_cmd.hdr.opcode =
+ VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION;
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ "default voip",
+ strlen("default voip")+1);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *) &mvm_session_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending MVM_CONTROL_SESSION\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ }
+ /* Get the created MVM handle. */
+ mvm_handle = voice_get_mvm_handle(v);
+ }
+ /* send cmd to create cvs session */
+ if (!cvs_handle) {
+ memset(cvs_session_cmd.cvs_session.name, 0,
+ sizeof(cvs_session_cmd.cvs_session.name));
+ if (!is_voip_session(v->session_id)) {
+ pr_debug("%s: creating CVS passive session\n",
+ __func__);
+
+ cvs_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_session_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_session_cmd) -
+ APR_HDR_SIZE);
+ cvs_session_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_session_cmd.hdr.dest_port = 0;
+ cvs_session_cmd.hdr.token = 0;
+ cvs_session_cmd.hdr.opcode =
+ VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+ if (is_volte_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ "default volte voice",
+ strlen("default volte voice")+1);
+ } else if (is_voice2_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ VOICE2_SESSION_VSID_STR,
+ strlen(VOICE2_SESSION_VSID_STR)+1);
+ } else if (is_qchat_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ QCHAT_SESSION_VSID_STR,
+ strlen(QCHAT_SESSION_VSID_STR)+1);
+ } else if (is_vowlan_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ VOWLAN_SESSION_VSID_STR,
+ strlen(VOWLAN_SESSION_VSID_STR)+1);
+ } else if (is_voicemmode1(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ VOICEMMODE1_VSID_STR,
+ strlen(VOICEMMODE1_VSID_STR) + 1);
+ } else if (is_voicemmode2(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ VOICEMMODE2_VSID_STR,
+ strlen(VOICEMMODE2_VSID_STR) + 1);
+ } else {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ "default modem voice",
+ strlen("default modem voice")+1);
+ }
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs,
+ (uint32_t *) &cvs_session_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending STREAM_CONTROL_SESSION\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ /* Get the created CVS handle. */
+ cvs_handle = voice_get_cvs_handle(v);
+
+ } else {
+ pr_debug("%s: creating CVS full session\n", __func__);
+
+ cvs_full_ctl_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+
+ cvs_full_ctl_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_full_ctl_cmd) -
+ APR_HDR_SIZE);
+
+ cvs_full_ctl_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_full_ctl_cmd.hdr.dest_port = 0;
+ cvs_full_ctl_cmd.hdr.token = 0;
+ cvs_full_ctl_cmd.hdr.opcode =
+ VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION;
+ cvs_full_ctl_cmd.cvs_session.direction = 2;
+ cvs_full_ctl_cmd.cvs_session.enc_media_type =
+ common.mvs_info.media_type;
+ cvs_full_ctl_cmd.cvs_session.dec_media_type =
+ common.mvs_info.media_type;
+ cvs_full_ctl_cmd.cvs_session.network_id =
+ common.mvs_info.network_type;
+ strlcpy(cvs_full_ctl_cmd.cvs_session.name,
+ "default q6 voice",
+ strlen("default q6 voice")+1);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs,
+ (uint32_t *) &cvs_full_ctl_cmd);
+
+ if (ret < 0) {
+ pr_err("%s: Err %d sending CREATE_FULL_CTRL\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ /* Get the created CVS handle. */
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* Attach MVM to CVS. */
+ pr_debug("%s: Attach MVM to stream\n", __func__);
+
+ attach_stream_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ attach_stream_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(attach_stream_cmd) -
+ APR_HDR_SIZE);
+ attach_stream_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ attach_stream_cmd.hdr.dest_port = mvm_handle;
+ attach_stream_cmd.hdr.token = 0;
+ attach_stream_cmd.hdr.opcode =
+ VSS_IMVM_CMD_ATTACH_STREAM;
+ attach_stream_cmd.attach_stream.handle = cvs_handle;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *) &attach_stream_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending ATTACH_STREAM\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ }
+ }
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_unmap_cal_block(struct voice_data *v, int cal_index)
+{
+ int result = 0;
+ struct cal_block_data *cal_block;
+
+ if (common.cal_data[cal_index] == NULL) {
+ pr_err("%s: Cal type is NULL, index %d!\n",
+ __func__, cal_index);
+
+ goto done;
+ }
+
+ mutex_lock(&common.cal_data[cal_index]->lock);
+ cal_block = cal_utils_get_only_cal_block(
+ common.cal_data[cal_index]);
+ if (cal_block == NULL) {
+ pr_err("%s: Cal block is NULL, index %d!\n",
+ __func__, cal_index);
+
+ result = -EINVAL;
+ goto unlock;
+ }
+
+ if (cal_block->map_data.q6map_handle == 0) {
+ pr_debug("%s: Q6 handle is not set!\n", __func__);
+
+ result = -EINVAL;
+ goto unlock;
+ }
+
+ mutex_lock(&common.common_lock);
+ result = voice_send_mvm_unmap_memory_physical_cmd(
+ v, cal_block->map_data.q6map_handle);
+ if (result)
+ pr_err("%s: Voice_send_mvm_unmap_memory_physical_cmd failed for session 0x%x, err %d!\n",
+ __func__, v->session_id, result);
+
+ cal_block->map_data.q6map_handle = 0;
+ mutex_unlock(&common.common_lock);
+unlock:
+ mutex_unlock(&common.cal_data[cal_index]->lock);
+done:
+ return result;
+}
+
+static int voice_destroy_mvm_cvs_session(struct voice_data *v)
+{
+ int ret = 0;
+ struct mvm_detach_stream_cmd detach_stream;
+ struct apr_hdr mvm_destroy;
+ struct apr_hdr cvs_destroy;
+ void *apr_mvm, *apr_cvs;
+ u16 mvm_handle, cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_mvm || !apr_cvs) {
+ pr_err("%s: apr_mvm or apr_cvs is NULL\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* MVM, CVS sessions are destroyed only for Full control sessions. */
+ if (is_voip_session(v->session_id)) {
+ pr_debug("%s: MVM detach stream, VOC_STATE: %d\n", __func__,
+ v->voc_state);
+
+ /* Detach voice stream. */
+ detach_stream.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ detach_stream.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(detach_stream) - APR_HDR_SIZE);
+ detach_stream.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ detach_stream.hdr.dest_port = mvm_handle;
+ detach_stream.hdr.token = 0;
+ detach_stream.hdr.opcode = VSS_IMVM_CMD_DETACH_STREAM;
+ detach_stream.detach_stream.handle = cvs_handle;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &detach_stream);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending DETACH_STREAM\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait event timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ /* Unmap memory */
+ if (v->shmem_info.mem_handle != 0) {
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ v->shmem_info.mem_handle);
+ if (ret < 0) {
+ pr_err("%s Memory_unmap for voip failed %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ v->shmem_info.mem_handle = 0;
+ }
+ }
+
+ /* Unmap Source Tracking shared memory if mapped earlier */
+ voice_unmap_and_free_source_tracking_shared_memory(v);
+
+ if (is_voip_session(v->session_id) ||
+ is_qchat_session(v->session_id) ||
+ is_volte_session(v->session_id) ||
+ is_vowlan_session(v->session_id) ||
+ v->voc_state == VOC_ERROR || common.is_destroy_cvd) {
+ /* Destroy CVS. */
+ pr_debug("%s: CVS destroy session\n", __func__);
+
+ cvs_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_destroy) - APR_HDR_SIZE);
+ cvs_destroy.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_destroy.dest_port = cvs_handle;
+ cvs_destroy.token = 0;
+ cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_destroy);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending CVS DESTROY\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait event timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ cvs_handle = 0;
+ voice_set_cvs_handle(v, cvs_handle);
+
+ /* Unmap physical memory for all calibration buffers */
+ if (!is_other_session_active(v->session_id)) {
+ if (voice_unmap_cal_block(v, CVP_VOCPROC_CAL))
+ pr_err("%s: Unmap VOCPROC cal failed\n",
+ __func__);
+ if (voice_unmap_cal_block(v, CVP_VOCVOL_CAL))
+ pr_err("%s: Unmap VOCVOL cal failed\n",
+ __func__);
+ if (voice_unmap_cal_block(v, CVP_VOCDEV_CFG_CAL))
+ pr_err("%s: Unmap VOCDEV_CFG cal failed\n",
+ __func__);
+ if (voice_unmap_cal_block(v, CVS_VOCSTRM_CAL))
+ pr_err("%s: Unmap VOCSTRM cal failed\n",
+ __func__);
+ }
+
+ /* Destroy MVM. */
+ pr_debug("%s: MVM destroy session\n", __func__);
+
+ mvm_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_destroy) - APR_HDR_SIZE);
+ mvm_destroy.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_destroy.dest_port = mvm_handle;
+ mvm_destroy.token = 0;
+ mvm_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_destroy);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending MVM DESTROY\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ mvm_handle = 0;
+ voice_set_mvm_handle(v, mvm_handle);
+ }
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_tty_mode_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ struct mvm_set_tty_mode_cmd mvm_tty_mode_cmd;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ /* send tty mode cmd to mvm */
+ mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_tty_mode_cmd) -
+ APR_HDR_SIZE);
+ pr_debug("%s: pkt size = %d\n",
+ __func__, mvm_tty_mode_cmd.hdr.pkt_size);
+ mvm_tty_mode_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
+ mvm_tty_mode_cmd.hdr.token = 0;
+ mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
+ mvm_tty_mode_cmd.tty_mode.mode = v->tty_mode;
+ pr_debug("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_TTY_MODE\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_set_pp_enable_cmd(struct voice_data *v,
+ uint32_t module_id, int enable)
+{
+ struct cvs_set_pp_enable_cmd cvs_set_pp_cmd;
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ cvs_set_pp_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_pp_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_pp_cmd) -
+ APR_HDR_SIZE);
+ cvs_set_pp_cmd.hdr.src_port = voice_get_idx_for_session(v->session_id);
+ cvs_set_pp_cmd.hdr.dest_port = cvs_handle;
+ cvs_set_pp_cmd.hdr.token = 0;
+ cvs_set_pp_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
+
+ cvs_set_pp_cmd.vss_set_pp.module_id = module_id;
+ cvs_set_pp_cmd.vss_set_pp.param_id = VOICE_PARAM_MOD_ENABLE;
+ cvs_set_pp_cmd.vss_set_pp.param_size = MOD_ENABLE_PARAM_LEN;
+ cvs_set_pp_cmd.vss_set_pp.reserved = 0;
+ cvs_set_pp_cmd.vss_set_pp.enable = enable;
+ cvs_set_pp_cmd.vss_set_pp.reserved_field = 0;
+ pr_debug("voice_send_set_pp_enable_cmd, module_id=%d, enable=%d\n",
+ module_id, enable);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_pp_cmd);
+ if (ret < 0) {
+ pr_err("Fail: sending cvs set pp enable,\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_hd_cmd(struct voice_data *v, int enable)
+{
+ struct mvm_set_hd_enable_cmd mvm_set_hd_cmd;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_mvm = common.apr_q6_mvm;
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mvm_handle = voice_get_mvm_handle(v);
+ if (!mvm_handle) {
+ pr_err("%s: mvm_handle is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mvm_set_hd_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_hd_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_hd_cmd) -
+ APR_HDR_SIZE);
+ mvm_set_hd_cmd.hdr.src_port = voice_get_idx_for_session(v->session_id);
+ mvm_set_hd_cmd.hdr.dest_port = mvm_handle;
+ mvm_set_hd_cmd.hdr.token = 0;
+
+ if (enable)
+ mvm_set_hd_cmd.hdr.opcode = VSS_IHDVOICE_CMD_ENABLE;
+ else
+ mvm_set_hd_cmd.hdr.opcode = VSS_IHDVOICE_CMD_DISABLE;
+
+ pr_debug("%s: enable=%d\n", __func__, enable);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_hd_cmd);
+ if (ret < 0) {
+ pr_err("%s: Failed to sending mvm set HD Voice enable %d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int voice_set_dtx(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* Set DTX */
+ cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+ cvs_set_dtx.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_set_dtx.hdr.dest_port = cvs_handle;
+ cvs_set_dtx.hdr.token = 0;
+ cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+ cvs_set_dtx.dtx_mode.enable = common.mvs_info.dtx_mode;
+
+ pr_debug("%s: Setting DTX %d\n", __func__, common.mvs_info.dtx_mode);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_DTX\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ return -EINVAL;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int voice_send_mvm_media_type_cmd(struct voice_data *v)
+{
+ struct vss_imvm_cmd_set_cal_media_type_t mvm_set_cal_media_type;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_set_cal_media_type.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_cal_media_type.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_cal_media_type) -
+ APR_HDR_SIZE);
+ mvm_set_cal_media_type.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_set_cal_media_type.hdr.dest_port = mvm_handle;
+ mvm_set_cal_media_type.hdr.token = 0;
+ mvm_set_cal_media_type.hdr.opcode = VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE;
+ mvm_set_cal_media_type.media_id = common.mvs_info.media_type;
+ pr_debug("%s: setting media_id as %x\n",
+ __func__, mvm_set_cal_media_type.media_id);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_cal_media_type);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending media type\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_dtmf_rx_detection_cmd(struct voice_data *v,
+ uint32_t enable)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct cvs_set_rx_dtmf_detection_cmd cvs_dtmf_rx_detection;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* Set SET_DTMF_RX_DETECTION */
+ cvs_dtmf_rx_detection.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_dtmf_rx_detection.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_dtmf_rx_detection) - APR_HDR_SIZE);
+ cvs_dtmf_rx_detection.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_dtmf_rx_detection.hdr.dest_port = cvs_handle;
+ cvs_dtmf_rx_detection.hdr.token = 0;
+ cvs_dtmf_rx_detection.hdr.opcode =
+ VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION;
+ cvs_dtmf_rx_detection.cvs_dtmf_det.enable = enable;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_dtmf_rx_detection);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_DTMF_RX_DETECTION\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ return -EINVAL;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void voice_vote_powerstate_to_bms(struct voice_data *v, bool state)
+{
+ union power_supply_propval pval = {0, };
+
+ if (!v->psy)
+ v->psy = power_supply_get_by_name("bms");
+ if (v->psy && !(is_voip_session(v->session_id) ||
+ is_vowlan_session(v->session_id))) {
+ pval.intval = VMBMS_VOICE_CALL_BIT;
+ if (state) {
+ power_supply_set_property(v->psy,
+ POWER_SUPPLY_PROP_HI_POWER,
+ &pval);
+ pr_debug("%s : Vote High power to BMS\n",
+ __func__);
+ } else {
+ power_supply_set_property(v->psy,
+ POWER_SUPPLY_PROP_LOW_POWER,
+ &pval);
+ pr_debug("%s: Vote low power to BMS\n",
+ __func__);
+ }
+ } else {
+ pr_debug("%s: No OP", __func__);
+ }
+
+}
+
+void voc_disable_dtmf_det_on_active_sessions(void)
+{
+ struct voice_data *v = NULL;
+ int i;
+
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ v = &common.voice[i];
+ if ((v->dtmf_rx_detect_en) &&
+ is_voc_state_active(v->voc_state)) {
+
+ pr_debug("disable dtmf det on ses_id=%d\n",
+ v->session_id);
+ voice_send_dtmf_rx_detection_cmd(v, 0);
+ }
+ }
+}
+
+int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+ v->dtmf_rx_detect_en = enable;
+
+ if (is_voc_state_active(v->voc_state))
+ ret = voice_send_dtmf_rx_detection_cmd(v,
+ v->dtmf_rx_detect_en);
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+void voc_set_destroy_cvd_flag(bool is_destroy_cvd)
+{
+ pr_debug("%s: %d\n", __func__, is_destroy_cvd);
+ common.is_destroy_cvd = is_destroy_cvd;
+}
+
+void voc_set_vote_bms_flag(bool is_vote_bms)
+{
+ pr_debug("%s: flag value: %d\n", __func__, is_vote_bms);
+ common.is_vote_bms = is_vote_bms;
+}
+
+int voc_alloc_cal_shared_memory(void)
+{
+ int rc = 0;
+
+ mutex_lock(&common.common_lock);
+ if (is_cal_memory_allocated()) {
+ pr_debug("%s: Calibration shared buffer already allocated",
+ __func__);
+ } else {
+ /* Allocate memory for calibration memory map table. */
+ rc = voice_alloc_cal_mem_map_table();
+ if ((rc < 0) && (rc != -EPROBE_DEFER)) {
+ pr_err("%s: Failed to allocate cal memory, err=%d",
+ __func__, rc);
+ }
+ }
+ mutex_unlock(&common.common_lock);
+
+ return rc;
+}
+
+int voc_alloc_voip_shared_memory(void)
+{
+ int rc = 0;
+
+ /* Allocate shared memory for OOB Voip */
+ rc = voice_alloc_oob_shared_mem();
+ if (rc < 0) {
+ pr_err("%s: Failed to alloc shared memory for OOB rc:%d\n",
+ __func__, rc);
+ } else {
+ /* Allocate mem map table for OOB */
+ rc = voice_alloc_oob_mem_table();
+ if (rc < 0) {
+ pr_err("%s: Failed to alloc mem map talbe rc:%d\n",
+ __func__, rc);
+
+ voice_free_oob_shared_mem();
+ }
+ }
+
+ return rc;
+}
+
+static int is_cal_memory_allocated(void)
+{
+ bool ret;
+
+ if (common.cal_mem_map_table.client != NULL &&
+ common.cal_mem_map_table.handle != NULL)
+ ret = true;
+ else
+ ret = false;
+
+ return ret;
+}
+
+
+static int free_cal_map_table(void)
+{
+ int ret = 0;
+
+ if ((common.cal_mem_map_table.client == NULL) ||
+ (common.cal_mem_map_table.handle == NULL))
+ goto done;
+
+ ret = msm_audio_ion_free(common.cal_mem_map_table.client,
+ common.cal_mem_map_table.handle);
+ if (ret < 0)
+ pr_err("%s: msm_audio_ion_free failed:\n", __func__);
+
+done:
+ common.cal_mem_map_table.client = NULL;
+ common.cal_mem_map_table.handle = NULL;
+ return ret;
+}
+
+static int is_rtac_memory_allocated(void)
+{
+ bool ret;
+
+ if (common.rtac_mem_map_table.client != NULL &&
+ common.rtac_mem_map_table.handle != NULL)
+ ret = true;
+ else
+ ret = false;
+
+ return ret;
+}
+
+static int free_rtac_map_table(void)
+{
+ int ret = 0;
+
+ if ((common.rtac_mem_map_table.client == NULL) ||
+ (common.rtac_mem_map_table.handle == NULL))
+ goto done;
+
+ ret = msm_audio_ion_free(common.rtac_mem_map_table.client,
+ common.rtac_mem_map_table.handle);
+ if (ret < 0)
+ pr_err("%s: msm_audio_ion_free failed:\n", __func__);
+
+done:
+ common.rtac_mem_map_table.client = NULL;
+ common.rtac_mem_map_table.handle = NULL;
+ return ret;
+}
+
+
+static int is_voip_memory_allocated(void)
+{
+ bool ret;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL, session_id:%d\n", __func__,
+ common.voice[VOC_PATH_FULL].session_id);
+
+ ret = false;
+ goto done;
+ }
+
+ mutex_lock(&common.common_lock);
+ if (v->shmem_info.sh_buf.client != NULL &&
+ v->shmem_info.sh_buf.handle != NULL)
+ ret = true;
+ else
+ ret = false;
+ mutex_unlock(&common.common_lock);
+
+done:
+ return ret;
+}
+
+static int voice_config_cvs_vocoder_amr_rate(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ pr_debug("%s: Setting AMR rate. Media Type: %d\n", __func__,
+ common.mvs_info.media_type);
+
+ cvs_set_amr_rate.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
+ cvs_set_amr_rate.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_set_amr_rate.hdr.dest_port = cvs_handle;
+ cvs_set_amr_rate.hdr.token = 0;
+
+ if (common.mvs_info.media_type == VSS_MEDIA_ID_AMR_NB_MODEM)
+ cvs_set_amr_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
+ else if (common.mvs_info.media_type == VSS_MEDIA_ID_AMR_WB_MODEM)
+ cvs_set_amr_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
+
+ cvs_set_amr_rate.amr_rate.mode = common.mvs_info.rate;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_AMR_RATE\n",
+ __func__, ret);
+
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+ return 0;
+done:
+ return ret;
+}
+
+static int voice_config_cvs_vocoder(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ /* Set media type. */
+ struct cvs_set_media_type_cmd cvs_set_media_cmd;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ cvs_set_media_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_media_cmd) -
+ APR_HDR_SIZE);
+ cvs_set_media_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_set_media_cmd.hdr.dest_port = cvs_handle;
+ cvs_set_media_cmd.hdr.token = 0;
+ cvs_set_media_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MEDIA_TYPE;
+ cvs_set_media_cmd.media_type.tx_media_id = common.mvs_info.media_type;
+ cvs_set_media_cmd.media_type.rx_media_id = common.mvs_info.media_type;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_media_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_MEDIA_TYPE\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ /* Set encoder properties. */
+ switch (common.mvs_info.media_type) {
+ case VSS_MEDIA_ID_EVRC_MODEM:
+ case VSS_MEDIA_ID_4GV_NB_MODEM:
+ case VSS_MEDIA_ID_4GV_WB_MODEM:
+ case VSS_MEDIA_ID_4GV_NW_MODEM: {
+ struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
+
+ pr_debug("Setting EVRC min-max rate\n");
+
+ cvs_set_cdma_rate.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_cdma_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_cdma_rate) - APR_HDR_SIZE);
+ cvs_set_cdma_rate.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_set_cdma_rate.hdr.dest_port = cvs_handle;
+ cvs_set_cdma_rate.hdr.token = 0;
+ cvs_set_cdma_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE;
+ cvs_set_cdma_rate.cdma_rate.min_rate =
+ common.mvs_info.evrc_min_rate;
+ cvs_set_cdma_rate.cdma_rate.max_rate =
+ common.mvs_info.evrc_max_rate;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_cdma_rate);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_EVRC_MINMAX_RATE\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ if (common.mvs_info.media_type != VSS_MEDIA_ID_EVRC_MODEM) {
+ ret = voice_set_dtx(v);
+ if (ret < 0)
+ goto fail;
+ }
+
+ break;
+ }
+ case VSS_MEDIA_ID_AMR_NB_MODEM:
+ case VSS_MEDIA_ID_AMR_WB_MODEM: {
+ ret = voice_config_cvs_vocoder_amr_rate(v);
+ if (ret) {
+ pr_err("%s: Failed to update vocoder rate. %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+
+ ret = voice_set_dtx(v);
+ if (ret < 0)
+ goto fail;
+
+ break;
+ }
+ case VSS_MEDIA_ID_G729:
+ case VSS_MEDIA_ID_G711_ALAW:
+ case VSS_MEDIA_ID_G711_MULAW: {
+ ret = voice_set_dtx(v);
+
+ break;
+ }
+ default:
+ /* Do nothing. */
+ break;
+ }
+ return 0;
+
+fail:
+ return ret;
+}
+
+int voc_update_amr_vocoder_rate(uint32_t session_id)
+{
+ int ret = 0;
+ struct voice_data *v;
+
+ pr_debug("%s: session_id:%d", __func__, session_id);
+
+ v = voice_get_session(session_id);
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL, session_id:%d\n", __func__,
+ session_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&v->lock);
+ ret = voice_config_cvs_vocoder_amr_rate(v);
+ mutex_unlock(&v->lock);
+
+done:
+ return ret;
+}
+
+static int voice_send_start_voice_cmd(struct voice_data *v)
+{
+ struct apr_hdr mvm_start_voice_cmd;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_start_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_start_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_start_voice_cmd) - APR_HDR_SIZE);
+ pr_debug("send mvm_start_voice_cmd pkt size = %d\n",
+ mvm_start_voice_cmd.pkt_size);
+ mvm_start_voice_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_start_voice_cmd.dest_port = mvm_handle;
+ mvm_start_voice_cmd.token = 0;
+ mvm_start_voice_cmd.opcode = VSS_IMVM_CMD_START_VOICE;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_start_voice_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_START_VOICE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ } else {
+ if (common.is_vote_bms) {
+ /* vote high power to BMS during call start */
+ voice_vote_powerstate_to_bms(v, true);
+ }
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ return 0;
+fail:
+ return ret;
+}
+
+static void voc_get_tx_rx_topology(struct voice_data *v,
+ uint32_t *tx_topology_id,
+ uint32_t *rx_topology_id)
+{
+ uint32_t tx_id = 0;
+ uint32_t rx_id = 0;
+
+ if (v->lch_mode == VOICE_LCH_START || v->disable_topology) {
+ pr_debug("%s: Setting TX and RX topology to NONE for LCH\n",
+ __func__);
+
+ tx_id = VSS_IVOCPROC_TOPOLOGY_ID_NONE;
+ rx_id = VSS_IVOCPROC_TOPOLOGY_ID_NONE;
+ } else {
+ tx_id = voice_get_topology(CVP_VOC_TX_TOPOLOGY_CAL);
+ rx_id = voice_get_topology(CVP_VOC_RX_TOPOLOGY_CAL);
+ }
+
+ *tx_topology_id = tx_id;
+ *rx_topology_id = rx_id;
+}
+
+static int voice_send_set_device_cmd(struct voice_data *v)
+{
+ struct cvp_set_device_cmd cvp_setdev_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* set device and wait for response */
+ cvp_setdev_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_setdev_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_setdev_cmd) - APR_HDR_SIZE);
+ pr_debug(" send create cvp setdev, pkt size = %d\n",
+ cvp_setdev_cmd.hdr.pkt_size);
+ cvp_setdev_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_setdev_cmd.hdr.dest_port = cvp_handle;
+ cvp_setdev_cmd.hdr.token = 0;
+
+ if (voice_get_cvd_int_version(common.cvd_version) >=
+ CVD_INT_VERSION_2_2)
+ cvp_setdev_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_SET_DEVICE_V3;
+ else
+ cvp_setdev_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_SET_DEVICE_V2;
+
+ voc_get_tx_rx_topology(v,
+ &cvp_setdev_cmd.cvp_set_device_v2.tx_topology_id,
+ &cvp_setdev_cmd.cvp_set_device_v2.rx_topology_id);
+
+ cvp_setdev_cmd.cvp_set_device_v2.tx_port_id = v->dev_tx.port_id;
+ cvp_setdev_cmd.cvp_set_device_v2.rx_port_id = v->dev_rx.port_id;
+
+ if (common.ec_ref_ext) {
+ cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING;
+ cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
+ common.ec_port_id;
+ } else {
+ cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
+ cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
+ VSS_IVOCPROC_PORT_ID_NONE;
+ }
+ pr_debug("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
+ cvp_setdev_cmd.cvp_set_device_v2.tx_topology_id,
+ cvp_setdev_cmd.cvp_set_device_v2.tx_port_id,
+ cvp_setdev_cmd.cvp_set_device_v2.rx_port_id);
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_setdev_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IVOCPROC_CMD_SET_DEVICE\n");
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_stop_voice_cmd(struct voice_data *v)
+{
+ struct apr_hdr mvm_stop_voice_cmd;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_stop_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_stop_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_stop_voice_cmd) - APR_HDR_SIZE);
+ pr_debug("send mvm_stop_voice_cmd pkt size = %d\n",
+ mvm_stop_voice_cmd.pkt_size);
+ mvm_stop_voice_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_stop_voice_cmd.dest_port = mvm_handle;
+ mvm_stop_voice_cmd.token = 0;
+ mvm_stop_voice_cmd.opcode = VSS_IMVM_CMD_STOP_VOICE;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_stop_voice_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_STOP_VOICE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return ret;
+}
+static int voice_get_cal(struct cal_block_data **cal_block,
+ int cal_block_idx,
+ struct cal_block_data **col_data,
+ int col_data_idx, int session_id)
+{
+ int ret = 0;
+
+ *cal_block = cal_utils_get_only_cal_block(
+ common.cal_data[cal_block_idx]);
+ if (*cal_block == NULL) {
+ pr_err("%s: No cal data for cal %d!\n",
+ __func__, cal_block_idx);
+
+ ret = -ENODEV;
+ goto done;
+ }
+ ret = remap_cal_data(*cal_block, session_id);
+ if (ret < 0) {
+ pr_err("%s: Remap_cal_data failed for cal %d!\n",
+ __func__, cal_block_idx);
+
+ ret = -ENODEV;
+ goto done;
+ }
+
+ if (col_data == NULL)
+ goto done;
+
+ *col_data = cal_utils_get_only_cal_block(
+ common.cal_data[col_data_idx]);
+ if (*col_data == NULL) {
+ pr_err("%s: No cal data for cal %d!\n",
+ __func__, col_data_idx);
+
+ ret = -ENODEV;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int voice_send_cvs_register_cal_cmd(struct voice_data *v)
+{
+ struct cvs_register_cal_data_cmd cvs_reg_cal_cmd;
+ struct cal_block_data *cal_block = NULL;
+ struct cal_block_data *col_data = NULL;
+ int ret = 0;
+
+ memset(&cvs_reg_cal_cmd, 0, sizeof(cvs_reg_cal_cmd));
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.apr_q6_cvs) {
+ pr_err("%s: apr_cvs is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&common.cal_data[CVS_VOCSTRM_CAL]->lock);
+ mutex_lock(&common.cal_data[CVS_VOCSTRM_COL_CAL]->lock);
+
+ ret = voice_get_cal(&cal_block, CVS_VOCSTRM_CAL, &col_data,
+ CVS_VOCSTRM_COL_CAL, v->session_id);
+ if (ret < 0) {
+ pr_err("%s: Voice_get_cal failed for cal %d!\n",
+ __func__, CVS_VOCSTRM_CAL);
+
+ goto unlock;
+ }
+
+ memcpy(&cvs_reg_cal_cmd.cvs_cal_data.column_info[0],
+ (void *) &((struct audio_cal_info_voc_col *)
+ col_data->cal_info)->data,
+ col_data->cal_data.size);
+
+ cvs_reg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvs_reg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_reg_cal_cmd) - APR_HDR_SIZE);
+ cvs_reg_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_reg_cal_cmd.hdr.dest_port = voice_get_cvs_handle(v);
+ cvs_reg_cal_cmd.hdr.token = 0;
+ if (common.is_per_vocoder_cal_enabled)
+ cvs_reg_cal_cmd.hdr.opcode =
+ VSS_ISTREAM_CMD_REGISTER_STATIC_CALIBRATION_DATA;
+ else
+ cvs_reg_cal_cmd.hdr.opcode =
+ VSS_ISTREAM_CMD_REGISTER_CALIBRATION_DATA_V2;
+
+ cvs_reg_cal_cmd.cvs_cal_data.cal_mem_handle =
+ cal_block->map_data.q6map_handle;
+ cvs_reg_cal_cmd.cvs_cal_data.cal_mem_address_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ cvs_reg_cal_cmd.cvs_cal_data.cal_mem_address_msw =
+ msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
+ cvs_reg_cal_cmd.cvs_cal_data.cal_mem_size =
+ cal_block->cal_data.size;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_reg_cal_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d registering CVS cal\n", __func__, ret);
+
+ ret = -EINVAL;
+ goto unlock;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto unlock;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto unlock;
+ }
+unlock:
+ mutex_unlock(&common.cal_data[CVS_VOCSTRM_COL_CAL]->lock);
+ mutex_unlock(&common.cal_data[CVS_VOCSTRM_CAL]->lock);
+done:
+ return ret;
+}
+
+static int voice_send_cvs_deregister_cal_cmd(struct voice_data *v)
+{
+ struct cvs_deregister_cal_data_cmd cvs_dereg_cal_cmd;
+ int ret = 0;
+
+ memset(&cvs_dereg_cal_cmd, 0, sizeof(cvs_dereg_cal_cmd));
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.apr_q6_cvs) {
+ pr_err("%s: apr_cvs is NULL\n", __func__);
+
+ ret = -EPERM;
+ goto done;
+ }
+
+ cvs_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvs_dereg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_dereg_cal_cmd) - APR_HDR_SIZE);
+ cvs_dereg_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_dereg_cal_cmd.hdr.dest_port = voice_get_cvs_handle(v);
+ cvs_dereg_cal_cmd.hdr.token = 0;
+ if (common.is_per_vocoder_cal_enabled)
+ cvs_dereg_cal_cmd.hdr.opcode =
+ VSS_ISTREAM_CMD_DEREGISTER_STATIC_CALIBRATION_DATA;
+ else
+ cvs_dereg_cal_cmd.hdr.opcode =
+ VSS_ISTREAM_CMD_DEREGISTER_CALIBRATION_DATA;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_dereg_cal_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d de-registering CVS cal\n", __func__, ret);
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+
+}
+
+static int voice_send_cvp_create_cmd(struct voice_data *v)
+{
+ struct cvp_create_full_ctl_session_cmd cvp_session_cmd;
+ void *apr_cvp;
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_cvp = common.apr_q6_cvp;
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* create cvp session and wait for response */
+ cvp_session_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_session_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_session_cmd) - APR_HDR_SIZE);
+ pr_debug("%s: send create cvp session, pkt size = %d\n",
+ __func__, cvp_session_cmd.hdr.pkt_size);
+ cvp_session_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_session_cmd.hdr.dest_port = 0;
+ cvp_session_cmd.hdr.token = 0;
+
+ if (voice_get_cvd_int_version(common.cvd_version) >=
+ CVD_INT_VERSION_2_2)
+ cvp_session_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V3;
+ else
+ cvp_session_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2;
+
+ voc_get_tx_rx_topology(v,
+ &cvp_session_cmd.cvp_session.tx_topology_id,
+ &cvp_session_cmd.cvp_session.rx_topology_id);
+
+ cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
+ cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.port_id;
+ cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.port_id;
+ cvp_session_cmd.cvp_session.profile_id =
+ VSS_ICOMMON_CAL_NETWORK_ID_NONE;
+ if (common.ec_ref_ext) {
+ cvp_session_cmd.cvp_session.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING;
+ cvp_session_cmd.cvp_session.ec_ref_port_id =
+ common.ec_port_id;
+ } else {
+ cvp_session_cmd.cvp_session.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
+ cvp_session_cmd.cvp_session.ec_ref_port_id =
+ VSS_IVOCPROC_PORT_ID_NONE;
+ }
+
+ pr_debug("tx_topology: %d tx_port_id=%d, rx_port_id=%d, mode: 0x%x\n",
+ cvp_session_cmd.cvp_session.tx_topology_id,
+ cvp_session_cmd.cvp_session.tx_port_id,
+ cvp_session_cmd.cvp_session.rx_port_id,
+ cvp_session_cmd.cvp_session.vocproc_mode);
+ pr_debug("rx_topology: %d, profile_id: 0x%x, pkt_size: %d\n",
+ cvp_session_cmd.cvp_session.rx_topology_id,
+ cvp_session_cmd.cvp_session.profile_id,
+ cvp_session_cmd.hdr.pkt_size);
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_session_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int voice_send_cvp_register_dev_cfg_cmd(struct voice_data *v)
+{
+ struct cvp_register_dev_cfg_cmd cvp_reg_dev_cfg_cmd;
+ struct cal_block_data *cal_block = NULL;
+ int ret = 0;
+
+ memset(&cvp_reg_dev_cfg_cmd, 0, sizeof(cvp_reg_dev_cfg_cmd));
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.apr_q6_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+
+ ret = -EPERM;
+ goto done;
+ }
+
+ mutex_lock(&common.cal_data[CVP_VOCDEV_CFG_CAL]->lock);
+
+ ret = voice_get_cal(&cal_block, CVP_VOCDEV_CFG_CAL, NULL,
+ 0, v->session_id);
+ if (ret < 0) {
+ pr_err("%s: Voice_get_cal failed for cal %d!\n",
+ __func__, CVP_VOCDEV_CFG_CAL);
+
+ goto unlock;
+ }
+
+ cvp_reg_dev_cfg_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvp_reg_dev_cfg_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_reg_dev_cfg_cmd) - APR_HDR_SIZE);
+ cvp_reg_dev_cfg_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_reg_dev_cfg_cmd.hdr.dest_port = voice_get_cvp_handle(v);
+ cvp_reg_dev_cfg_cmd.hdr.token = 0;
+ cvp_reg_dev_cfg_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_REGISTER_DEVICE_CONFIG;
+
+ cvp_reg_dev_cfg_cmd.cvp_dev_cfg_data.mem_handle =
+ cal_block->map_data.q6map_handle;
+ cvp_reg_dev_cfg_cmd.cvp_dev_cfg_data.mem_address_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ cvp_reg_dev_cfg_cmd.cvp_dev_cfg_data.mem_address_msw =
+ msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
+ cvp_reg_dev_cfg_cmd.cvp_dev_cfg_data.mem_size =
+ cal_block->cal_data.size;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvp,
+ (uint32_t *) &cvp_reg_dev_cfg_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d registering CVP dev cfg cal\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto unlock;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto unlock;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto unlock;
+ }
+unlock:
+ mutex_unlock(&common.cal_data[CVP_VOCDEV_CFG_CAL]->lock);
+done:
+ return ret;
+}
+
+static int voice_send_cvp_deregister_dev_cfg_cmd(struct voice_data *v)
+{
+ struct cvp_deregister_dev_cfg_cmd cvp_dereg_dev_cfg_cmd;
+ int ret = 0;
+
+ memset(&cvp_dereg_dev_cfg_cmd, 0, sizeof(cvp_dereg_dev_cfg_cmd));
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.apr_q6_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+
+ ret = -EPERM;
+ goto done;
+ }
+
+ cvp_dereg_dev_cfg_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvp_dereg_dev_cfg_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_dereg_dev_cfg_cmd) - APR_HDR_SIZE);
+ cvp_dereg_dev_cfg_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_dereg_dev_cfg_cmd.hdr.dest_port = voice_get_cvp_handle(v);
+ cvp_dereg_dev_cfg_cmd.hdr.token = 0;
+ cvp_dereg_dev_cfg_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_DEREGISTER_DEVICE_CONFIG;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvp,
+ (uint32_t *) &cvp_dereg_dev_cfg_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d de-registering CVP dev cfg cal\n",
+ __func__, ret);
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int voice_send_cvp_register_cal_cmd(struct voice_data *v)
+{
+ struct cvp_register_cal_data_cmd cvp_reg_cal_cmd;
+ struct cal_block_data *cal_block = NULL;
+ struct cal_block_data *col_data = NULL;
+ int ret = 0;
+
+ memset(&cvp_reg_cal_cmd, 0, sizeof(cvp_reg_cal_cmd));
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.apr_q6_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&common.cal_data[CVP_VOCPROC_CAL]->lock);
+ mutex_lock(&common.cal_data[CVP_VOCPROC_COL_CAL]->lock);
+
+ ret = voice_get_cal(&cal_block, CVP_VOCPROC_CAL, &col_data,
+ CVP_VOCPROC_COL_CAL, v->session_id);
+ if (ret < 0) {
+ pr_err("%s: Voice_get_cal failed for cal %d!\n",
+ __func__, CVP_VOCPROC_CAL);
+
+ goto unlock;
+ }
+
+ v->dev_tx.dev_id = ((struct audio_cal_info_vocproc *)
+ cal_block->cal_info)->tx_acdb_id;
+ v->dev_rx.dev_id = ((struct audio_cal_info_vocproc *)
+ cal_block->cal_info)->rx_acdb_id;
+ pr_debug("%s: %s: Tx acdb id = %d and Rx acdb id = %d", __func__,
+ voc_get_session_name(v->session_id), v->dev_tx.dev_id,
+ v->dev_rx.dev_id);
+
+ memcpy(&cvp_reg_cal_cmd.cvp_cal_data.column_info[0],
+ (void *) &((struct audio_cal_info_voc_col *)
+ col_data->cal_info)->data,
+ col_data->cal_data.size);
+
+ cvp_reg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvp_reg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_reg_cal_cmd) - APR_HDR_SIZE);
+ cvp_reg_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_reg_cal_cmd.hdr.dest_port = voice_get_cvp_handle(v);
+ cvp_reg_cal_cmd.hdr.token = 0;
+ if (common.is_per_vocoder_cal_enabled)
+ cvp_reg_cal_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_REGISTER_STATIC_CALIBRATION_DATA;
+ else
+ cvp_reg_cal_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_REGISTER_CALIBRATION_DATA_V2;
+
+ cvp_reg_cal_cmd.cvp_cal_data.cal_mem_handle =
+ cal_block->map_data.q6map_handle;
+ cvp_reg_cal_cmd.cvp_cal_data.cal_mem_address_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ cvp_reg_cal_cmd.cvp_cal_data.cal_mem_address_msw =
+ msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
+ cvp_reg_cal_cmd.cvp_cal_data.cal_mem_size =
+ cal_block->cal_data.size;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_reg_cal_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d registering CVP cal\n", __func__, ret);
+
+ ret = -EINVAL;
+ goto unlock;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto unlock;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto unlock;
+ }
+unlock:
+ mutex_unlock(&common.cal_data[CVP_VOCPROC_COL_CAL]->lock);
+ mutex_unlock(&common.cal_data[CVP_VOCPROC_CAL]->lock);
+done:
+ return ret;
+}
+
+static int voice_send_cvp_deregister_cal_cmd(struct voice_data *v)
+{
+ struct cvp_deregister_cal_data_cmd cvp_dereg_cal_cmd;
+ int ret = 0;
+
+ memset(&cvp_dereg_cal_cmd, 0, sizeof(cvp_dereg_cal_cmd));
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.apr_q6_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+
+ ret = -EPERM;
+ goto done;
+ }
+
+ cvp_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvp_dereg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_dereg_cal_cmd) - APR_HDR_SIZE);
+ cvp_dereg_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_dereg_cal_cmd.hdr.dest_port = voice_get_cvp_handle(v);
+ cvp_dereg_cal_cmd.hdr.token = 0;
+ if (common.is_per_vocoder_cal_enabled)
+ cvp_dereg_cal_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_DEREGISTER_STATIC_CALIBRATION_DATA;
+ else
+ cvp_dereg_cal_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_DEREGISTER_CALIBRATION_DATA;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_dereg_cal_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d de-registering CVP cal\n", __func__, ret);
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int voice_send_cvp_register_vol_cal_cmd(struct voice_data *v)
+{
+ struct cvp_register_vol_cal_data_cmd cvp_reg_vol_cal_cmd;
+ struct cal_block_data *cal_block = NULL;
+ struct cal_block_data *col_data = NULL;
+ int ret = 0;
+
+ memset(&cvp_reg_vol_cal_cmd, 0, sizeof(cvp_reg_vol_cal_cmd));
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.apr_q6_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&common.cal_data[CVP_VOCVOL_CAL]->lock);
+ mutex_lock(&common.cal_data[CVP_VOCVOL_COL_CAL]->lock);
+
+ ret = voice_get_cal(&cal_block, CVP_VOCVOL_CAL, &col_data,
+ CVP_VOCVOL_COL_CAL, v->session_id);
+ if (ret < 0) {
+ pr_err("%s: Voice_get_cal failed for cal %d!\n",
+ __func__, CVP_VOCVOL_CAL);
+
+ goto unlock;
+ }
+
+ memcpy(&cvp_reg_vol_cal_cmd.cvp_vol_cal_data.column_info[0],
+ (void *) &((struct audio_cal_info_voc_col *)
+ col_data->cal_info)->data,
+ col_data->cal_data.size);
+
+ cvp_reg_vol_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvp_reg_vol_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_reg_vol_cal_cmd) - APR_HDR_SIZE);
+ cvp_reg_vol_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_reg_vol_cal_cmd.hdr.dest_port = voice_get_cvp_handle(v);
+ cvp_reg_vol_cal_cmd.hdr.token = 0;
+ if (common.is_per_vocoder_cal_enabled)
+ cvp_reg_vol_cal_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_REGISTER_DYNAMIC_CALIBRATION_DATA;
+ else
+ cvp_reg_vol_cal_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_REGISTER_VOL_CALIBRATION_DATA;
+
+ cvp_reg_vol_cal_cmd.cvp_vol_cal_data.cal_mem_handle =
+ cal_block->map_data.q6map_handle;
+ cvp_reg_vol_cal_cmd.cvp_vol_cal_data.cal_mem_address_lsw =
+ lower_32_bits(cal_block->cal_data.paddr);
+ cvp_reg_vol_cal_cmd.cvp_vol_cal_data.cal_mem_address_msw =
+ msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
+ cvp_reg_vol_cal_cmd.cvp_vol_cal_data.cal_mem_size =
+ cal_block->cal_data.size;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvp,
+ (uint32_t *) &cvp_reg_vol_cal_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d registering CVP vol cal\n", __func__, ret);
+
+ ret = -EINVAL;
+ goto unlock;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto unlock;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto unlock;
+ }
+unlock:
+ mutex_unlock(&common.cal_data[CVP_VOCVOL_COL_CAL]->lock);
+ mutex_unlock(&common.cal_data[CVP_VOCVOL_CAL]->lock);
+done:
+ return ret;
+}
+
+static int voice_send_cvp_deregister_vol_cal_cmd(struct voice_data *v)
+{
+ struct cvp_deregister_vol_cal_data_cmd cvp_dereg_vol_cal_cmd;
+ int ret = 0;
+
+ memset(&cvp_dereg_vol_cal_cmd, 0, sizeof(cvp_dereg_vol_cal_cmd));
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.apr_q6_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+
+ ret = -EPERM;
+ goto done;
+ }
+
+ cvp_dereg_vol_cal_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvp_dereg_vol_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_dereg_vol_cal_cmd) - APR_HDR_SIZE);
+ cvp_dereg_vol_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_dereg_vol_cal_cmd.hdr.dest_port = voice_get_cvp_handle(v);
+ cvp_dereg_vol_cal_cmd.hdr.token = 0;
+ if (common.is_per_vocoder_cal_enabled)
+ cvp_dereg_vol_cal_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_DEREGISTER_DYNAMIC_CALIBRATION_DATA;
+ else
+ cvp_dereg_vol_cal_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_DEREGISTER_VOL_CALIBRATION_DATA;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvp,
+ (uint32_t *) &cvp_dereg_vol_cal_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d de-registering CVP vol cal\n",
+ __func__, ret);
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int voice_map_memory_physical_cmd(struct voice_data *v,
+ struct mem_map_table *table_info,
+ dma_addr_t phys,
+ uint32_t size,
+ uint32_t token)
+{
+ struct vss_imemory_cmd_map_physical_t mvm_map_phys_cmd;
+ uint32_t *memtable;
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (!common.apr_q6_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (!table_info->data) {
+ pr_err("%s: memory table is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ memtable = (uint32_t *) table_info->data;
+
+ /*
+ * Store next table descriptor's address(64 bit) as NULL as there
+ * is only one memory block
+ */
+ memtable[0] = 0;
+ memtable[1] = 0;
+
+ /* Store next table descriptor's size */
+ memtable[2] = 0;
+
+ /* Store shared mem adddress (64 bit) */
+ memtable[3] = lower_32_bits(phys);
+ memtable[4] = msm_audio_populate_upper_32_bits(phys);
+
+ /* Store shared memory size */
+ memtable[5] = size;
+
+ mvm_map_phys_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mvm_map_phys_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_map_phys_cmd) - APR_HDR_SIZE);
+ mvm_map_phys_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_map_phys_cmd.hdr.dest_port = voice_get_mvm_handle(v);
+ mvm_map_phys_cmd.hdr.token = token;
+ mvm_map_phys_cmd.hdr.opcode = VSS_IMEMORY_CMD_MAP_PHYSICAL;
+
+ mvm_map_phys_cmd.table_descriptor.mem_address_lsw =
+ lower_32_bits(table_info->phys);
+ mvm_map_phys_cmd.table_descriptor.mem_address_msw =
+ msm_audio_populate_upper_32_bits(table_info->phys);
+ mvm_map_phys_cmd.table_descriptor.mem_size =
+ sizeof(struct vss_imemory_block_t) +
+ sizeof(struct vss_imemory_table_descriptor_t);
+ mvm_map_phys_cmd.is_cached = true;
+ mvm_map_phys_cmd.cache_line_size = 128;
+ mvm_map_phys_cmd.access_mask = 3;
+ mvm_map_phys_cmd.page_align = 4096;
+ mvm_map_phys_cmd.min_data_width = 8;
+ mvm_map_phys_cmd.max_data_width = 64;
+
+ pr_debug("%s: next table desc: add: %lld, size: %d\n",
+ __func__, *((uint64_t *) memtable),
+ *(((uint32_t *) memtable) + 2));
+ pr_debug("%s: phy add of of mem being mapped LSW:0x%x, MSW:0x%x size: %d\n",
+ __func__, *(((uint32_t *) memtable) + 3),
+ *(((uint32_t *) memtable) + 4), *(((uint32_t *) memtable) + 5));
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_mvm, (uint32_t *) &mvm_map_phys_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending mvm map phy cmd\n", __func__, ret);
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_pause_voice_call(struct voice_data *v)
+{
+ struct apr_hdr mvm_pause_voice_cmd;
+ void *apr_mvm;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (v == NULL) {
+ pr_err("%s: Voice data is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_mvm = common.apr_q6_mvm;
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mvm_pause_voice_cmd.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mvm_pause_voice_cmd.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_pause_voice_cmd) - APR_HDR_SIZE);
+ mvm_pause_voice_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_pause_voice_cmd.dest_port = voice_get_mvm_handle(v);
+ mvm_pause_voice_cmd.token = 0;
+ mvm_pause_voice_cmd.opcode = VSS_IMVM_CMD_PAUSE_VOICE;
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ pr_debug("%s: send mvm_pause_voice_cmd pkt size = %d\n",
+ __func__, mvm_pause_voice_cmd.pkt_size);
+
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *)&mvm_pause_voice_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_PAUSE_VOICE\n");
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int voice_map_cal_memory(struct cal_block_data *cal_block,
+ uint32_t session_id)
+{
+ int result = 0;
+ int voc_index;
+ struct voice_data *v = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("%s: Cal block is NULL!\n", __func__);
+
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->cal_data.paddr == 0) {
+ pr_debug("%s: No address to map!\n", __func__);
+
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->map_data.map_size == 0) {
+ pr_debug("%s: Map size is 0!\n", __func__);
+
+ result = -EINVAL;
+ goto done;
+ }
+
+ voc_index = voice_get_idx_for_session(session_id);
+ if (voc_index < 0) {
+ pr_err("%s: Invalid session ID %d\n", __func__, session_id);
+
+ goto done;
+ }
+
+ mutex_lock(&common.common_lock);
+ v = &common.voice[voc_index];
+
+ result = voice_map_memory_physical_cmd(v,
+ &common.cal_mem_map_table,
+ (dma_addr_t)cal_block->cal_data.paddr,
+ cal_block->map_data.map_size,
+ VOC_CAL_MEM_MAP_TOKEN);
+ if (result < 0) {
+ pr_err("%s: Mmap did not work! addr = 0x%pK, size = %zd\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+
+ goto done_unlock;
+ }
+
+ cal_block->map_data.q6map_handle = common.cal_mem_handle;
+done_unlock:
+ mutex_unlock(&common.common_lock);
+done:
+ return result;
+}
+
+static int remap_cal_data(struct cal_block_data *cal_block,
+ uint32_t session_id)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_block->map_data.ion_client == NULL) {
+ pr_err("%s: No ION allocation for session_id %d!\n",
+ __func__, session_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((cal_block->map_data.map_size > 0) &&
+ (cal_block->map_data.q6map_handle == 0)) {
+
+ /* cal type not used */
+ ret = voice_map_cal_memory(cal_block, session_id);
+ if (ret < 0) {
+ pr_err("%s: Mmap did not work! size = %zd\n",
+ __func__, cal_block->map_data.map_size);
+
+ goto done;
+ }
+ } else {
+ pr_debug("%s: Cal block 0x%pK, size %zd already mapped. Q6 map handle = %d\n",
+ __func__, &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size,
+ cal_block->map_data.q6map_handle);
+ }
+done:
+ return ret;
+}
+
+static int voice_unmap_cal_memory(int32_t cal_type,
+ struct cal_block_data *cal_block)
+{
+ int result = 0;
+ int result2 = 0;
+ int i;
+ struct voice_data *v = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("%s: Cal block is NULL!\n", __func__);
+
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->map_data.q6map_handle == 0) {
+ pr_debug("%s: Q6 handle is not set!\n", __func__);
+
+ result = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&common.common_lock);
+
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ v = &common.voice[i];
+
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state)) {
+ result2 = voice_pause_voice_call(v);
+ if (result2 < 0) {
+ pr_err("%s: Voice_pause_voice_call failed for session 0x%x, err %d!\n",
+ __func__, v->session_id, result2);
+
+ result = result2;
+ }
+
+ if (cal_type == CVP_VOCPROC_DYNAMIC_CAL_TYPE)
+ voice_send_cvp_deregister_vol_cal_cmd(v);
+ else if (cal_type == CVP_VOCPROC_STATIC_CAL_TYPE)
+ voice_send_cvp_deregister_cal_cmd(v);
+ else if (cal_type == CVP_VOCDEV_CFG_CAL_TYPE)
+ voice_send_cvp_deregister_dev_cfg_cmd(v);
+ else if (cal_type == CVS_VOCSTRM_STATIC_CAL_TYPE)
+ voice_send_cvs_deregister_cal_cmd(v);
+ else
+ pr_err("%s: Invalid cal type %d!\n",
+ __func__, cal_type);
+
+ result2 = voice_send_start_voice_cmd(v);
+ if (result2) {
+ pr_err("%s: Voice_send_start_voice_cmd failed for session 0x%x, err %d!\n",
+ __func__, v->session_id, result2);
+
+ result = result2;
+ }
+ }
+
+ if ((cal_block->map_data.q6map_handle != 0) &&
+ (!is_other_session_active(v->session_id))) {
+
+ result2 = voice_send_mvm_unmap_memory_physical_cmd(
+ v, cal_block->map_data.q6map_handle);
+ if (result2) {
+ pr_err("%s: Voice_send_mvm_unmap_memory_physical_cmd failed for session 0x%x, err %d!\n",
+ __func__, v->session_id, result2);
+
+ result = result2;
+ }
+ cal_block->map_data.q6map_handle = 0;
+ }
+ mutex_unlock(&v->lock);
+ }
+ mutex_unlock(&common.common_lock);
+done:
+ return result;
+}
+
+int voc_register_vocproc_vol_table(void)
+{
+ int result = 0;
+ int result2 = 0;
+ int i;
+ struct voice_data *v = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&common.common_lock);
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ v = &common.voice[i];
+
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state)) {
+ result2 = voice_send_cvp_register_vol_cal_cmd(v);
+ if (result2 < 0) {
+ pr_err("%s: Failed to register vocvol table for session 0x%x!\n",
+ __func__, v->session_id);
+
+ result = result2;
+ /* Still try to register other sessions */
+ }
+ }
+ mutex_unlock(&v->lock);
+ }
+
+ mutex_unlock(&common.common_lock);
+ return result;
+}
+
+int voc_deregister_vocproc_vol_table(void)
+{
+ int result = 0;
+ int success = 0;
+ int i;
+ struct voice_data *v = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&common.common_lock);
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ v = &common.voice[i];
+
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state)) {
+ result = voice_send_cvp_deregister_vol_cal_cmd(v);
+ if (result < 0) {
+ pr_err("%s: Failed to deregister vocvol table for session 0x%x!\n",
+ __func__, v->session_id);
+
+ mutex_unlock(&v->lock);
+ mutex_unlock(&common.common_lock);
+ if (success) {
+ pr_err("%s: Try to re-register all deregistered sessions!\n",
+ __func__);
+
+ voc_register_vocproc_vol_table();
+ }
+ goto done;
+ } else {
+ success = 1;
+ }
+ }
+ mutex_unlock(&v->lock);
+ }
+ mutex_unlock(&common.common_lock);
+done:
+ return result;
+}
+
+int voc_map_rtac_block(struct rtac_cal_block_data *cal_block)
+{
+ int result = 0;
+ struct voice_data *v = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("%s: cal_block is NULL!\n",
+ __func__);
+
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->cal_data.paddr == 0) {
+ pr_debug("%s: No address to map!\n",
+ __func__);
+
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (cal_block->map_data.map_size == 0) {
+ pr_debug("%s: map size is 0!\n",
+ __func__);
+
+ result = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&common.common_lock);
+ /* use first session */
+ v = &common.voice[0];
+ mutex_lock(&v->lock);
+
+ if (!is_rtac_memory_allocated()) {
+ result = voice_alloc_rtac_mem_map_table();
+ if (result < 0) {
+ pr_err("%s: RTAC alloc mem map table did not work! addr = 0x%pK, size = %d\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+
+ goto done_unlock;
+ }
+ }
+
+ result = voice_map_memory_physical_cmd(v,
+ &common.rtac_mem_map_table,
+ (dma_addr_t)cal_block->cal_data.paddr,
+ cal_block->map_data.map_size,
+ VOC_RTAC_MEM_MAP_TOKEN);
+ if (result < 0) {
+ pr_err("%s: RTAC mmap did not work! addr = 0x%pK, size = %d\n",
+ __func__,
+ &cal_block->cal_data.paddr,
+ cal_block->map_data.map_size);
+
+ free_rtac_map_table();
+ goto done_unlock;
+ }
+
+ cal_block->map_data.map_handle = common.rtac_mem_handle;
+done_unlock:
+ mutex_unlock(&v->lock);
+ mutex_unlock(&common.common_lock);
+done:
+ return result;
+}
+
+int voc_unmap_rtac_block(uint32_t *mem_map_handle)
+{
+ int result = 0;
+ struct voice_data *v = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ if (mem_map_handle == NULL) {
+ pr_debug("%s: Map handle is NULL, nothing to unmap\n",
+ __func__);
+
+ goto done;
+ }
+
+ if (*mem_map_handle == 0) {
+ pr_debug("%s: Map handle is 0, nothing to unmap\n",
+ __func__);
+
+ goto done;
+ }
+
+ mutex_lock(&common.common_lock);
+ /* Use first session */
+ /* Only used for apr wait lock */
+ v = &common.voice[0];
+ mutex_lock(&v->lock);
+
+ result = voice_send_mvm_unmap_memory_physical_cmd(
+ v, *mem_map_handle);
+ if (result) {
+ pr_err("%s: voice_send_mvm_unmap_memory_physical_cmd Failed for session 0x%x!\n",
+ __func__, v->session_id);
+ } else {
+ *mem_map_handle = 0;
+ common.rtac_mem_handle = 0;
+ free_rtac_map_table();
+ }
+ mutex_unlock(&v->lock);
+ mutex_unlock(&common.common_lock);
+done:
+ return result;
+}
+
+static int voice_setup_vocproc(struct voice_data *v)
+{
+ int ret = 0;
+
+ ret = voice_send_cvp_create_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: CVP create failed err:%d\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = voice_send_cvp_device_channels_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Set device channels failed err:%d\n",
+ __func__, ret);
+ goto fail;
+ }
+
+ ret = voice_send_cvp_topology_commit_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Set topology commit failed err:%d\n",
+ __func__, ret);
+ goto fail;
+ }
+
+ voice_send_cvs_register_cal_cmd(v);
+ voice_send_cvp_register_dev_cfg_cmd(v);
+ voice_send_cvp_register_cal_cmd(v);
+ voice_send_cvp_register_vol_cal_cmd(v);
+
+ /* enable vocproc */
+ ret = voice_send_enable_vocproc_cmd(v);
+ if (ret < 0)
+ goto fail;
+
+ /* attach vocproc */
+ ret = voice_send_attach_vocproc_cmd(v);
+ if (ret < 0)
+ goto fail;
+
+ /* send tty mode if tty device is used */
+ voice_send_tty_mode_cmd(v);
+
+ if (is_voip_session(v->session_id)) {
+ ret = voice_send_mvm_cal_network_cmd(v);
+ if (ret < 0)
+ pr_err("%s: voice_send_mvm_cal_network_cmd: %d\n",
+ __func__, ret);
+
+ ret = voice_send_mvm_media_type_cmd(v);
+ if (ret < 0)
+ pr_err("%s: voice_send_mvm_media_type_cmd: %d\n",
+ __func__, ret);
+
+ voice_send_netid_timing_cmd(v);
+ }
+
+ if (v->st_enable && !v->tty_mode)
+ voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_ST,
+ v->st_enable);
+ /* Start in-call music delivery if this feature is enabled */
+ if (v->music_info.play_enable)
+ voice_cvs_start_playback(v);
+
+ /* Start in-call recording if this feature is enabled */
+ if (v->rec_info.rec_enable)
+ voice_cvs_start_record(v, v->rec_info.rec_mode);
+
+ if (v->dtmf_rx_detect_en)
+ voice_send_dtmf_rx_detection_cmd(v, v->dtmf_rx_detect_en);
+
+ if (v->hd_enable)
+ voice_send_hd_cmd(v, v->hd_enable);
+
+ rtac_add_voice(voice_get_cvs_handle(v),
+ voice_get_cvp_handle(v),
+ v->dev_rx.port_id, v->dev_tx.port_id,
+ v->dev_rx.dev_id, v->dev_tx.dev_id,
+ v->session_id);
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_send_cvp_device_channels_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ struct cvp_set_dev_channels_cmd cvp_set_dev_channels_cmd;
+ void *apr_cvp;
+ u16 cvp_handle;
+
+ if (!(voice_get_cvd_int_version(common.cvd_version) >=
+ CVD_INT_VERSION_2_2)) {
+ pr_debug("%s CVD ver %s doesn't support send_device_channels cmd\n",
+ __func__, common.cvd_version);
+
+ goto done;
+ }
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_cvp = common.apr_q6_cvp;
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+ cvp_set_dev_channels_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_set_dev_channels_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_set_dev_channels_cmd) - APR_HDR_SIZE);
+ cvp_set_dev_channels_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_set_dev_channels_cmd.hdr.dest_port = cvp_handle;
+ cvp_set_dev_channels_cmd.hdr.token = 0;
+ cvp_set_dev_channels_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_TOPOLOGY_SET_DEV_CHANNELS;
+ cvp_set_dev_channels_cmd.cvp_set_channels.rx_num_channels =
+ VSS_NUM_DEV_CHANNELS_1;
+ cvp_set_dev_channels_cmd.cvp_set_channels.tx_num_channels =
+ v->dev_tx.no_of_channels;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_set_dev_channels_cmd);
+ if (ret < 0) {
+ pr_err("%s: Fail in sending VSS_IVOCPROC_CMD_TOPOLOGY_SET_DEV_CHANNELS\n",
+ __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int voice_send_cvp_topology_commit_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ struct apr_hdr cvp_topology_commit_cmd;
+ void *apr_cvp;
+ u16 cvp_handle;
+
+ if (!(voice_get_cvd_int_version(common.cvd_version) >=
+ CVD_INT_VERSION_2_2)) {
+ pr_debug("%s CVD version string %s doesn't support this command\n",
+ __func__, common.cvd_version);
+
+ goto done;
+ }
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_cvp = common.apr_q6_cvp;
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+ cvp_topology_commit_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_topology_commit_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_topology_commit_cmd) - APR_HDR_SIZE);
+ cvp_topology_commit_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_topology_commit_cmd.dest_port = cvp_handle;
+ cvp_topology_commit_cmd.token = 0;
+ cvp_topology_commit_cmd.opcode = VSS_IVOCPROC_CMD_TOPOLOGY_COMMIT;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_topology_commit_cmd);
+ if (ret < 0) {
+ pr_err("%s: Fail in sending VSS_IVOCPROC_CMD_TOPOLOGY_COMMIT\n",
+ __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int voice_send_enable_vocproc_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ struct apr_hdr cvp_enable_cmd;
+ void *apr_cvp;
+ u16 cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* enable vocproc and wait for respose */
+ cvp_enable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_enable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_enable_cmd) - APR_HDR_SIZE);
+ pr_debug("cvp_enable_cmd pkt size = %d, cvp_handle=%d\n",
+ cvp_enable_cmd.pkt_size, cvp_handle);
+ cvp_enable_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_enable_cmd.dest_port = cvp_handle;
+ cvp_enable_cmd.token = 0;
+ cvp_enable_cmd.opcode = VSS_IVOCPROC_CMD_ENABLE;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_enable_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IVOCPROC_CMD_ENABLE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_mvm_cal_network_cmd(struct voice_data *v)
+{
+ struct vss_imvm_cmd_set_cal_network_t mvm_set_cal_network;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_set_cal_network.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_cal_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_cal_network) - APR_HDR_SIZE);
+ mvm_set_cal_network.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_set_cal_network.hdr.dest_port = mvm_handle;
+ mvm_set_cal_network.hdr.token = 0;
+ mvm_set_cal_network.hdr.opcode = VSS_IMVM_CMD_SET_CAL_NETWORK;
+ mvm_set_cal_network.network_id = VSS_ICOMMON_CAL_NETWORK_ID_NONE;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_cal_network);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_netid_timing_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+ struct mvm_set_network_cmd mvm_set_network;
+ struct mvm_set_voice_timing_cmd mvm_set_voice_timing;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ ret = voice_config_cvs_vocoder(v);
+ if (ret < 0) {
+ pr_err("%s: Error %d configuring CVS voc",
+ __func__, ret);
+ goto fail;
+ }
+ /* Set network ID. */
+ pr_debug("Setting network ID %x\n", common.mvs_info.network_type);
+
+ mvm_set_network.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_network) - APR_HDR_SIZE);
+ mvm_set_network.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_set_network.hdr.dest_port = mvm_handle;
+ mvm_set_network.hdr.token = 0;
+ mvm_set_network.hdr.opcode = VSS_IMVM_CMD_SET_CAL_NETWORK;
+ mvm_set_network.network.network_id = common.mvs_info.network_type;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_network);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ /* Set voice timing. */
+ pr_debug("Setting voice timing\n");
+
+ mvm_set_voice_timing.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_voice_timing.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_voice_timing) -
+ APR_HDR_SIZE);
+ mvm_set_voice_timing.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_set_voice_timing.hdr.dest_port = mvm_handle;
+ mvm_set_voice_timing.hdr.token = 0;
+ mvm_set_voice_timing.hdr.opcode = VSS_ICOMMON_CMD_SET_VOICE_TIMING;
+ mvm_set_voice_timing.timing.mode = 0;
+ mvm_set_voice_timing.timing.enc_offset = 8000;
+ mvm_set_voice_timing.timing.dec_req_offset = 3300;
+ mvm_set_voice_timing.timing.dec_offset = 8300;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_voice_timing);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_TIMING\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_attach_vocproc_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ struct mvm_attach_vocproc_cmd mvm_a_vocproc_cmd;
+ void *apr_mvm;
+ u16 mvm_handle, cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* attach vocproc and wait for response */
+ mvm_a_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_a_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_a_vocproc_cmd) - APR_HDR_SIZE);
+ pr_debug("send mvm_a_vocproc_cmd pkt size = %d\n",
+ mvm_a_vocproc_cmd.hdr.pkt_size);
+ mvm_a_vocproc_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_a_vocproc_cmd.hdr.dest_port = mvm_handle;
+ mvm_a_vocproc_cmd.hdr.token = 0;
+ mvm_a_vocproc_cmd.hdr.opcode = VSS_IMVM_CMD_ATTACH_VOCPROC;
+ mvm_a_vocproc_cmd.mvm_attach_cvp_handle.handle = cvp_handle;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_a_vocproc_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_ATTACH_VOCPROC\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return ret;
+}
+
+static void voc_update_session_params(struct voice_data *v)
+{
+ /* reset LCH mode */
+ v->lch_mode = 0;
+
+ /* clear disable topology setting */
+ v->disable_topology = false;
+
+ /* clear mute setting */
+ v->dev_rx.dev_mute = common.default_mute_val;
+ v->dev_tx.dev_mute = common.default_mute_val;
+ v->stream_rx.stream_mute = common.default_mute_val;
+ v->stream_tx.stream_mute = common.default_mute_val;
+}
+
+static int voice_destroy_vocproc(struct voice_data *v)
+{
+ struct mvm_detach_vocproc_cmd mvm_d_vocproc_cmd;
+ struct apr_hdr cvp_destroy_session_cmd;
+ int ret = 0;
+ void *apr_mvm, *apr_cvp;
+ u16 mvm_handle, cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_mvm || !apr_cvp) {
+ pr_err("%s: apr_mvm or apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* disable slowtalk if st_enable is set */
+ if (v->st_enable)
+ voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_ST, 0);
+
+ /* Disable HD Voice if hd_enable is set */
+ if (v->hd_enable)
+ voice_send_hd_cmd(v, 0);
+
+ /* stop playback or recording */
+ v->music_info.force = 1;
+ voice_cvs_stop_playback(v);
+ voice_cvs_stop_record(v);
+ /* If voice call is active during VoLTE, SRVCC happens.
+ * Start recording on voice session if recording started during VoLTE.
+ */
+ if (is_volte_session(v->session_id) &&
+ ((common.voice[VOC_PATH_PASSIVE].voc_state == VOC_RUN) ||
+ (common.voice[VOC_PATH_PASSIVE].voc_state == VOC_CHANGE))) {
+ if (v->rec_info.rec_enable) {
+ voice_cvs_start_record(
+ &common.voice[VOC_PATH_PASSIVE],
+ v->rec_info.rec_mode);
+ common.srvcc_rec_flag = true;
+
+ pr_debug("%s: switch recording, srvcc_rec_flag %d\n",
+ __func__, common.srvcc_rec_flag);
+ }
+ }
+
+ /* send stop voice cmd */
+ voice_send_stop_voice_cmd(v);
+
+ /* send stop dtmf detecton cmd */
+ if (v->dtmf_rx_detect_en)
+ voice_send_dtmf_rx_detection_cmd(v, 0);
+
+ /* detach VOCPROC and wait for response from mvm */
+ mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_d_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_d_vocproc_cmd) - APR_HDR_SIZE);
+ pr_debug("mvm_d_vocproc_cmd pkt size = %d\n",
+ mvm_d_vocproc_cmd.hdr.pkt_size);
+ mvm_d_vocproc_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_d_vocproc_cmd.hdr.dest_port = mvm_handle;
+ mvm_d_vocproc_cmd.hdr.token = 0;
+ mvm_d_vocproc_cmd.hdr.opcode = VSS_IMVM_CMD_DETACH_VOCPROC;
+ mvm_d_vocproc_cmd.mvm_detach_cvp_handle.handle = cvp_handle;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_d_vocproc_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_DETACH_VOCPROC\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ voice_send_cvp_deregister_vol_cal_cmd(v);
+ voice_send_cvp_deregister_cal_cmd(v);
+ voice_send_cvp_deregister_dev_cfg_cmd(v);
+ voice_send_cvs_deregister_cal_cmd(v);
+
+ /* destrop cvp session */
+ cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_destroy_session_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_destroy_session_cmd) - APR_HDR_SIZE);
+ pr_debug("cvp_destroy_session_cmd pkt size = %d\n",
+ cvp_destroy_session_cmd.pkt_size);
+ cvp_destroy_session_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_destroy_session_cmd.dest_port = cvp_handle;
+ cvp_destroy_session_cmd.token = 0;
+ cvp_destroy_session_cmd.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_destroy_session_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending APRV2_IBASIC_CMD_DESTROY_SESSION\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ rtac_remove_voice(voice_get_cvs_handle(v));
+ cvp_handle = 0;
+ voice_set_cvp_handle(v, cvp_handle);
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
+ uint32_t mem_handle)
+{
+ struct vss_imemory_cmd_unmap_t mem_unmap;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mem_unmap.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mem_unmap.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mem_unmap) - APR_HDR_SIZE);
+ mem_unmap.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mem_unmap.hdr.dest_port = mvm_handle;
+ mem_unmap.hdr.token = 0;
+ mem_unmap.hdr.opcode = VSS_IMEMORY_CMD_UNMAP;
+ mem_unmap.mem_handle = mem_handle;
+
+ pr_debug("%s: mem_handle: 0x%x\n", __func__, mem_unmap.mem_handle);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mem_unmap);
+ if (ret < 0) {
+ pr_err("mem_unmap op[0x%x]ret[%d]\n",
+ mem_unmap.hdr.opcode, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v)
+{
+ struct vss_istream_cmd_set_oob_packet_exchange_config_t
+ packet_exchange_config_pkt;
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ packet_exchange_config_pkt.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ packet_exchange_config_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(packet_exchange_config_pkt) -
+ APR_HDR_SIZE);
+ packet_exchange_config_pkt.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ packet_exchange_config_pkt.hdr.dest_port = cvs_handle;
+ packet_exchange_config_pkt.hdr.token = 0;
+ packet_exchange_config_pkt.hdr.opcode =
+ VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG;
+ packet_exchange_config_pkt.mem_handle = v->shmem_info.mem_handle;
+ /* dec buffer address */
+ packet_exchange_config_pkt.dec_buf_addr_lsw =
+ lower_32_bits(v->shmem_info.sh_buf.buf[0].phys);
+ packet_exchange_config_pkt.dec_buf_addr_msw =
+ msm_audio_populate_upper_32_bits(
+ v->shmem_info.sh_buf.buf[0].phys);
+ packet_exchange_config_pkt.dec_buf_size = 4096;
+ /* enc buffer address */
+ packet_exchange_config_pkt.enc_buf_addr_lsw =
+ lower_32_bits(v->shmem_info.sh_buf.buf[1].phys);
+ packet_exchange_config_pkt.enc_buf_addr_msw =
+ msm_audio_populate_upper_32_bits(
+ v->shmem_info.sh_buf.buf[1].phys);
+ packet_exchange_config_pkt.enc_buf_size = 4096;
+
+ pr_debug("%s: dec buf add: lsw %0x msw %0x, size %d, enc buf add: lsw %0x msw %0x, size %d\n",
+ __func__,
+ packet_exchange_config_pkt.dec_buf_addr_lsw,
+ packet_exchange_config_pkt.dec_buf_addr_msw,
+ packet_exchange_config_pkt.dec_buf_size,
+ packet_exchange_config_pkt.enc_buf_addr_lsw,
+ packet_exchange_config_pkt.enc_buf_addr_msw,
+ packet_exchange_config_pkt.enc_buf_size);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &packet_exchange_config_pkt);
+ if (ret < 0) {
+ pr_err("Failed to send packet exchange config cmd %d\n", ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret)
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v)
+{
+ struct vss_istream_cmd_set_packet_exchange_mode_t data_exchange_pkt;
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ data_exchange_pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ data_exchange_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(data_exchange_pkt) - APR_HDR_SIZE);
+ data_exchange_pkt.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ data_exchange_pkt.hdr.dest_port = cvs_handle;
+ data_exchange_pkt.hdr.token = 0;
+ data_exchange_pkt.hdr.opcode = VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE;
+ data_exchange_pkt.mode = VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &data_exchange_pkt);
+ if (ret < 0) {
+ pr_err("Failed to send data exchange mode %d\n", ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret)
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ return 0;
+fail:
+ return ret;
+}
+
+static int voice_send_stream_mute_cmd(struct voice_data *v, uint16_t direction,
+ uint16_t mute_flag, uint32_t ramp_duration)
+{
+ struct cvs_set_mute_cmd cvs_mute_cmd;
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (!common.apr_q6_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* send mute/unmute to cvs */
+ cvs_mute_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_mute_cmd) - APR_HDR_SIZE);
+ cvs_mute_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_mute_cmd.hdr.dest_port = voice_get_cvs_handle(v);
+ cvs_mute_cmd.hdr.token = 0;
+ cvs_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
+ cvs_mute_cmd.cvs_set_mute.direction = direction;
+ cvs_mute_cmd.cvs_set_mute.mute_flag = mute_flag;
+ cvs_mute_cmd.cvs_set_mute.ramp_duration_ms = ramp_duration;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_mute_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending stream mute\n", __func__, ret);
+
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_send_device_mute_cmd(struct voice_data *v, uint16_t direction,
+ uint16_t mute_flag, uint32_t ramp_duration)
+{
+ struct cvp_set_mute_cmd cvp_mute_cmd;
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (!common.apr_q6_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ cvp_mute_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_mute_cmd) - APR_HDR_SIZE);
+ cvp_mute_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_mute_cmd.hdr.dest_port = voice_get_cvp_handle(v);
+ cvp_mute_cmd.hdr.token = 0;
+ cvp_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
+ cvp_mute_cmd.cvp_set_mute.direction = direction;
+ cvp_mute_cmd.cvp_set_mute.mute_flag = mute_flag;
+ cvp_mute_cmd.cvp_set_mute.ramp_duration_ms = ramp_duration;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_mute_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending rx device cmd\n", __func__, ret);
+
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: Command timeout\n", __func__);
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_send_vol_step_cmd(struct voice_data *v)
+{
+ struct cvp_set_rx_volume_step_cmd cvp_vol_step_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* send volume index to cvp */
+ cvp_vol_step_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_vol_step_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_vol_step_cmd) - APR_HDR_SIZE);
+ cvp_vol_step_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_vol_step_cmd.hdr.dest_port = cvp_handle;
+ cvp_vol_step_cmd.hdr.token = 0;
+ cvp_vol_step_cmd.hdr.opcode = VSS_IVOLUME_CMD_SET_STEP;
+ cvp_vol_step_cmd.cvp_set_vol_step.direction = VSS_IVOLUME_DIRECTION_RX;
+ cvp_vol_step_cmd.cvp_set_vol_step.value = v->dev_rx.volume_step_value;
+ cvp_vol_step_cmd.cvp_set_vol_step.ramp_duration_ms =
+ v->dev_rx.volume_ramp_duration_ms;
+ pr_debug("%s step_value:%d, ramp_duration_ms:%d",
+ __func__,
+ cvp_vol_step_cmd.cvp_set_vol_step.value,
+ cvp_vol_step_cmd.cvp_set_vol_step.ramp_duration_ms);
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_vol_step_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending RX VOL step\n");
+ return -EINVAL;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ return -EINVAL;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ return ret;
+ }
+ return 0;
+}
+
+static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ struct cvs_start_record_cmd cvs_start_record;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (!v->rec_info.recording) {
+ cvs_start_record.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_start_record.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_start_record) - APR_HDR_SIZE);
+ cvs_start_record.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_start_record.hdr.dest_port = cvs_handle;
+ cvs_start_record.hdr.token = 0;
+ cvs_start_record.hdr.opcode = VSS_IRECORD_CMD_START;
+
+ cvs_start_record.rec_mode.port_id =
+ VSS_IRECORD_PORT_ID_DEFAULT;
+ if (rec_mode == VOC_REC_UPLINK) {
+ cvs_start_record.rec_mode.rx_tap_point =
+ VSS_IRECORD_TAP_POINT_NONE;
+ cvs_start_record.rec_mode.tx_tap_point =
+ VSS_IRECORD_TAP_POINT_STREAM_END;
+ } else if (rec_mode == VOC_REC_DOWNLINK) {
+ cvs_start_record.rec_mode.rx_tap_point =
+ VSS_IRECORD_TAP_POINT_STREAM_END;
+ cvs_start_record.rec_mode.tx_tap_point =
+ VSS_IRECORD_TAP_POINT_NONE;
+ } else if (rec_mode == VOC_REC_BOTH) {
+ cvs_start_record.rec_mode.rx_tap_point =
+ VSS_IRECORD_TAP_POINT_STREAM_END;
+ cvs_start_record.rec_mode.tx_tap_point =
+ VSS_IRECORD_TAP_POINT_STREAM_END;
+ } else {
+ pr_err("%s: Invalid in-call rec_mode %d\n", __func__,
+ rec_mode);
+
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_record);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending START_RECORD\n", __func__,
+ ret);
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ v->rec_info.recording = 1;
+ } else {
+ pr_debug("%s: Start record already sent\n", __func__);
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_cvs_stop_record(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct apr_hdr cvs_stop_record;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (v->rec_info.recording) {
+ cvs_stop_record.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvs_stop_record.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_stop_record) - APR_HDR_SIZE);
+ cvs_stop_record.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_stop_record.dest_port = cvs_handle;
+ cvs_stop_record.token = 0;
+ cvs_stop_record.opcode = VSS_IRECORD_CMD_STOP;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_record);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending STOP_RECORD\n",
+ __func__, ret);
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ v->rec_info.recording = 0;
+ } else {
+ pr_debug("%s: Stop record already sent\n", __func__);
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+int voc_start_record(uint32_t port_id, uint32_t set, uint32_t session_id)
+{
+ int ret = 0;
+ int rec_mode = 0;
+ u16 cvs_handle;
+ int rec_set = 0;
+ struct voice_session_itr itr;
+ struct voice_data *v = NULL;
+
+ /* check if session_id is valid */
+ if (!voice_is_valid_session_id(session_id)) {
+ pr_err("%s: Invalid session id:%u\n", __func__,
+ session_id);
+
+ return -EINVAL;
+ }
+
+ voice_itr_init(&itr, session_id);
+ pr_debug("%s: session_id:%u\n", __func__, session_id);
+
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v == NULL) {
+ pr_err("%s: v is NULL, sessionid:%u\n", __func__,
+ session_id);
+
+ break;
+ }
+ pr_debug("%s: port_id: %d, set: %d, v: %pK\n",
+ __func__, port_id, set, v);
+
+ mutex_lock(&v->lock);
+ rec_mode = v->rec_info.rec_mode;
+ rec_set = set;
+ if (set) {
+ if ((v->rec_route_state.ul_flag != 0) &&
+ (v->rec_route_state.dl_flag != 0)) {
+ pr_debug("%s: rec mode already set.\n",
+ __func__);
+
+ mutex_unlock(&v->lock);
+ continue;
+ }
+
+ if (port_id == VOICE_RECORD_TX) {
+ if ((v->rec_route_state.ul_flag == 0)
+ && (v->rec_route_state.dl_flag == 0)) {
+ rec_mode = VOC_REC_UPLINK;
+ v->rec_route_state.ul_flag = 1;
+ } else if ((v->rec_route_state.ul_flag == 0)
+ && (v->rec_route_state.dl_flag != 0)) {
+ voice_cvs_stop_record(v);
+ rec_mode = VOC_REC_BOTH;
+ v->rec_route_state.ul_flag = 1;
+ }
+ } else if (port_id == VOICE_RECORD_RX) {
+ if ((v->rec_route_state.ul_flag == 0)
+ && (v->rec_route_state.dl_flag == 0)) {
+ rec_mode = VOC_REC_DOWNLINK;
+ v->rec_route_state.dl_flag = 1;
+ } else if ((v->rec_route_state.ul_flag != 0)
+ && (v->rec_route_state.dl_flag == 0)) {
+ voice_cvs_stop_record(v);
+ rec_mode = VOC_REC_BOTH;
+ v->rec_route_state.dl_flag = 1;
+ }
+ }
+ rec_set = 1;
+ } else {
+ if ((v->rec_route_state.ul_flag == 0) &&
+ (v->rec_route_state.dl_flag == 0)) {
+ pr_debug("%s: rec already stops.\n",
+ __func__);
+ mutex_unlock(&v->lock);
+ continue;
+ }
+
+ if (port_id == VOICE_RECORD_TX) {
+ if ((v->rec_route_state.ul_flag != 0)
+ && (v->rec_route_state.dl_flag == 0)) {
+ v->rec_route_state.ul_flag = 0;
+ rec_set = 0;
+ } else if ((v->rec_route_state.ul_flag != 0)
+ && (v->rec_route_state.dl_flag != 0)) {
+ voice_cvs_stop_record(v);
+ v->rec_route_state.ul_flag = 0;
+ rec_mode = VOC_REC_DOWNLINK;
+ rec_set = 1;
+ }
+ } else if (port_id == VOICE_RECORD_RX) {
+ if ((v->rec_route_state.ul_flag == 0)
+ && (v->rec_route_state.dl_flag != 0)) {
+ v->rec_route_state.dl_flag = 0;
+ rec_set = 0;
+ } else if ((v->rec_route_state.ul_flag != 0)
+ && (v->rec_route_state.dl_flag != 0)) {
+ voice_cvs_stop_record(v);
+ v->rec_route_state.dl_flag = 0;
+ rec_mode = VOC_REC_UPLINK;
+ rec_set = 1;
+ }
+ }
+ }
+ pr_debug("%s: mode =%d, set =%d\n", __func__,
+ rec_mode, rec_set);
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (cvs_handle != 0) {
+ if (rec_set)
+ ret = voice_cvs_start_record(v, rec_mode);
+ else
+ ret = voice_cvs_stop_record(v);
+ }
+
+ /* During SRVCC, recording will switch from VoLTE session to
+ * voice session.
+ * Then stop recording, need to stop recording on voice session.
+ */
+ if ((!rec_set) && common.srvcc_rec_flag) {
+ pr_debug("%s, srvcc_rec_flag:%d\n", __func__,
+ common.srvcc_rec_flag);
+
+ voice_cvs_stop_record(&common.voice[VOC_PATH_PASSIVE]);
+ common.srvcc_rec_flag = false;
+ }
+
+ /* Cache the value */
+ v->rec_info.rec_enable = rec_set;
+ v->rec_info.rec_mode = rec_mode;
+
+ mutex_unlock(&v->lock);
+ }
+
+ return ret;
+}
+
+static int voice_cvs_start_playback(struct voice_data *v)
+{
+ int ret = 0;
+ struct cvs_start_playback_cmd cvs_start_playback;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (!v->music_info.playing && v->music_info.count) {
+ cvs_start_playback.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_start_playback.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_start_playback) - APR_HDR_SIZE);
+ cvs_start_playback.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_start_playback.hdr.dest_port = cvs_handle;
+ cvs_start_playback.hdr.token = 0;
+ cvs_start_playback.hdr.opcode = VSS_IPLAYBACK_CMD_START;
+ cvs_start_playback.playback_mode.port_id =
+ v->music_info.port_id;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_playback);
+
+ if (ret < 0) {
+ pr_err("%s: Error %d sending START_PLAYBACK\n",
+ __func__, ret);
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ v->music_info.playing = 1;
+ } else {
+ pr_debug("%s: Start playback already sent\n", __func__);
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_cvs_stop_playback(struct voice_data *v)
+{
+ int ret = 0;
+ struct apr_hdr cvs_stop_playback;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (v->music_info.playing && ((!v->music_info.count) ||
+ (v->music_info.force))) {
+ cvs_stop_playback.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvs_stop_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_stop_playback) - APR_HDR_SIZE);
+ cvs_stop_playback.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_stop_playback.dest_port = cvs_handle;
+ cvs_stop_playback.token = 0;
+
+ cvs_stop_playback.opcode = VSS_IPLAYBACK_CMD_STOP;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_playback);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending STOP_PLAYBACK\n",
+ __func__, ret);
+
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+
+ v->music_info.playing = 0;
+ v->music_info.force = 0;
+ } else {
+ pr_debug("%s: Stop playback already sent\n", __func__);
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voc_lch_ops(struct voice_data *v, enum voice_lch_mode lch_mode)
+{
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ switch (lch_mode) {
+ case VOICE_LCH_START:
+
+ ret = voc_end_voice_call(v->session_id);
+ if (ret < 0)
+ pr_err("%s: voice call end failed %d\n",
+ __func__, ret);
+ break;
+ case VOICE_LCH_STOP:
+
+ ret = voc_start_voice_call(v->session_id);
+ if (ret < 0) {
+ pr_err("%s: voice call start failed %d\n",
+ __func__, ret);
+ goto done;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid LCH mode: %d\n",
+ __func__, v->lch_mode);
+ break;
+ }
+done:
+ return ret;
+}
+
+int voc_start_playback(uint32_t set, uint16_t port_id)
+{
+ struct voice_data *v = NULL;
+ int ret = 0;
+ struct voice_session_itr itr;
+ u16 cvs_handle;
+
+ pr_debug("%s port_id = %#x set = %d", __func__, port_id, set);
+
+ voice_itr_init(&itr, ALL_SESSION_VSID);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if ((v != NULL) &&
+ (((port_id == VOICE_PLAYBACK_TX) &&
+ is_sub1_vsid(v->session_id)) ||
+ ((port_id == VOICE2_PLAYBACK_TX) &&
+ is_sub2_vsid(v->session_id)))) {
+
+ mutex_lock(&v->lock);
+ v->music_info.port_id = port_id;
+ v->music_info.play_enable = set;
+ if (set)
+ v->music_info.count++;
+ else
+ v->music_info.count--;
+ pr_debug("%s: music_info count=%d\n", __func__,
+ v->music_info.count);
+
+ cvs_handle = voice_get_cvs_handle(v);
+ if (cvs_handle != 0) {
+ if (set)
+ ret = voice_cvs_start_playback(v);
+ else
+ ret = voice_cvs_stop_playback(v);
+ }
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: Invalid session\n", __func__);
+ }
+ }
+
+ return ret;
+}
+
+int voc_disable_topology(uint32_t session_id, uint32_t disable)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+
+ v->disable_topology = disable;
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+static int voice_set_packet_exchange_mode_and_config(uint32_t session_id,
+ uint32_t mode)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ return -EINVAL;
+ }
+
+ if (v->voc_state != VOC_RUN)
+ ret = voice_send_cvs_data_exchange_mode_cmd(v);
+
+ if (ret) {
+ pr_err("%s: Error voice_send_data_exchange_mode_cmd %d\n",
+ __func__, ret);
+ goto fail;
+ }
+
+ ret = voice_send_cvs_packet_exchange_config_cmd(v);
+ if (ret) {
+ pr_err("%s: Error: voice_send_packet_exchange_config_cmd %d\n",
+ __func__, ret);
+ goto fail;
+ }
+
+ return ret;
+fail:
+ return -EINVAL;
+}
+
+int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+ uint32_t ramp_duration)
+{
+ struct voice_data *v = NULL;
+ int ret = 0;
+ struct voice_session_itr itr;
+
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ v->stream_tx.stream_mute = mute;
+ v->stream_tx.stream_mute_ramp_duration_ms =
+ ramp_duration;
+ if (is_voc_state_active(v->voc_state) &&
+ (v->lch_mode == 0))
+ ret = voice_send_stream_mute_cmd(v,
+ VSS_IVOLUME_DIRECTION_TX,
+ v->stream_tx.stream_mute,
+ v->stream_tx.stream_mute_ramp_duration_ms);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
+
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int voc_set_device_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+ uint32_t ramp_duration)
+{
+ struct voice_data *v = NULL;
+ int ret = 0;
+ struct voice_session_itr itr;
+
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ if (dir == VSS_IVOLUME_DIRECTION_TX) {
+ v->dev_tx.dev_mute = mute;
+ v->dev_tx.dev_mute_ramp_duration_ms =
+ ramp_duration;
+ } else {
+ v->dev_rx.dev_mute = mute;
+ v->dev_rx.dev_mute_ramp_duration_ms =
+ ramp_duration;
+ }
+
+ if (((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_STANDBY)) &&
+ (v->lch_mode == 0))
+ ret = voice_send_device_mute_cmd(v,
+ dir,
+ mute,
+ ramp_duration);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
+
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int voc_get_rx_device_mute(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+
+ ret = v->dev_rx.dev_mute;
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_set_tty_mode(uint32_t session_id, uint8_t tty_mode)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+
+ v->tty_mode = tty_mode;
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+uint8_t voc_get_tty_mode(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+
+ ret = v->tty_mode;
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_set_pp_enable(uint32_t session_id, uint32_t module_id, uint32_t enable)
+{
+ struct voice_data *v = NULL;
+ int ret = 0;
+ struct voice_session_itr itr;
+
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ if (!(is_voice_app_id(v->session_id)))
+ continue;
+
+ mutex_lock(&v->lock);
+ if (module_id == MODULE_ID_VOICE_MODULE_ST)
+ v->st_enable = enable;
+
+ if (v->voc_state == VOC_RUN) {
+ if ((module_id == MODULE_ID_VOICE_MODULE_ST) &&
+ (!v->tty_mode))
+ ret = voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_ST,
+ enable);
+ }
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int voc_set_hd_enable(uint32_t session_id, uint32_t enable)
+{
+ struct voice_data *v = NULL;
+ int ret = 0;
+ struct voice_session_itr itr;
+
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ v->hd_enable = enable;
+
+ if (v->voc_state == VOC_RUN)
+ ret = voice_send_hd_cmd(v, enable);
+
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int voc_get_pp_enable(uint32_t session_id, uint32_t module_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+ if (module_id == MODULE_ID_VOICE_MODULE_ST)
+ ret = v->st_enable;
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_set_rx_vol_step(uint32_t session_id, uint32_t dir, uint32_t vol_step,
+ uint32_t ramp_duration)
+{
+ struct voice_data *v = NULL;
+ int ret = 0;
+ struct voice_session_itr itr;
+
+ pr_debug("%s session id = %#x vol = %u", __func__, session_id,
+ vol_step);
+
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ v->dev_rx.volume_step_value = vol_step;
+ v->dev_rx.volume_ramp_duration_ms = ramp_duration;
+ if (is_voc_state_active(v->voc_state))
+ ret = voice_send_vol_step_cmd(v);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
+
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int voc_set_device_config(uint32_t session_id, uint8_t path_dir,
+ uint8_t no_of_channels, uint32_t port_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+
+ if (v == NULL) {
+ pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ pr_debug("%s: path_dir=%d port_id=%x, channels=%d\n",
+ __func__, path_dir, port_id, no_of_channels);
+
+ mutex_lock(&v->lock);
+ if (path_dir == RX_PATH) {
+ v->dev_rx.port_id = q6audio_get_port_id(port_id);
+ v->dev_rx.no_of_channels = no_of_channels;
+ } else {
+ v->dev_tx.port_id = q6audio_get_port_id(port_id);
+ v->dev_tx.no_of_channels = no_of_channels;
+ }
+ mutex_unlock(&v->lock);
+
+ return 0;
+}
+
+int voc_set_route_flag(uint32_t session_id, uint8_t path_dir, uint8_t set)
+{
+ struct voice_data *v = voice_get_session(session_id);
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ pr_debug("%s: path_dir=%d, set=%d\n", __func__, path_dir, set);
+
+ mutex_lock(&v->lock);
+
+ if (path_dir == RX_PATH)
+ v->voc_route_state.rx_route_flag = set;
+ else
+ v->voc_route_state.tx_route_flag = set;
+
+ mutex_unlock(&v->lock);
+
+ return 0;
+}
+
+uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return 0;
+ }
+
+ mutex_lock(&v->lock);
+
+ if (path_dir == RX_PATH)
+ ret = v->voc_route_state.rx_route_flag;
+ else
+ ret = v->voc_route_state.tx_route_flag;
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_end_voice_call(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+
+ if (v->voc_state == VOC_RUN || v->voc_state == VOC_ERROR ||
+ v->voc_state == VOC_CHANGE || v->voc_state == VOC_STANDBY) {
+
+ pr_debug("%s: VOC_STATE: %d\n", __func__, v->voc_state);
+
+ ret = voice_destroy_vocproc(v);
+ if (ret < 0)
+ pr_err("%s: destroy voice failed\n", __func__);
+
+ voc_update_session_params(v);
+
+ voice_destroy_mvm_cvs_session(v);
+ v->voc_state = VOC_RELEASE;
+ if (common.is_vote_bms) {
+ /* vote low power to BMS during call stop */
+ voice_vote_powerstate_to_bms(v, false);
+ }
+ } else {
+ pr_err("%s: Error: End voice called in state %d\n",
+ __func__, v->voc_state);
+
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&v->lock);
+ return ret;
+}
+
+int voc_standby_voice_call(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ struct apr_hdr mvm_standby_voice_cmd;
+ void *apr_mvm;
+ u16 mvm_handle;
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: voc state=%d", __func__, v->voc_state);
+
+ if (v->voc_state == VOC_RUN) {
+ apr_mvm = common.apr_q6_mvm;
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ mvm_standby_voice_cmd.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mvm_standby_voice_cmd.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_standby_voice_cmd) - APR_HDR_SIZE);
+ pr_debug("send mvm_standby_voice_cmd pkt size = %d\n",
+ mvm_standby_voice_cmd.pkt_size);
+ mvm_standby_voice_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_standby_voice_cmd.dest_port = mvm_handle;
+ mvm_standby_voice_cmd.token = 0;
+ mvm_standby_voice_cmd.opcode = VSS_IMVM_CMD_STANDBY_VOICE;
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *)&mvm_standby_voice_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_STANDBY_VOICE\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+ v->voc_state = VOC_STANDBY;
+ }
+fail:
+ return ret;
+}
+
+int voc_disable_device(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: voc state=%d\n", __func__, v->voc_state);
+
+ mutex_lock(&v->lock);
+ if (v->voc_state == VOC_RUN) {
+ ret = voice_pause_voice_call(v);
+ if (ret < 0) {
+ pr_err("%s: Pause Voice Call failed for session 0x%x, err %d!\n",
+ __func__, v->session_id, ret);
+ goto done;
+ }
+ rtac_remove_voice(voice_get_cvs_handle(v));
+ voice_send_cvp_deregister_vol_cal_cmd(v);
+ voice_send_cvp_deregister_cal_cmd(v);
+ voice_send_cvp_deregister_dev_cfg_cmd(v);
+
+ v->voc_state = VOC_CHANGE;
+ } else {
+ pr_debug("%s: called in voc state=%d, No_OP\n",
+ __func__, v->voc_state);
+ }
+
+done:
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_enable_device(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: voc state=%d\n", __func__, v->voc_state);
+ mutex_lock(&v->lock);
+ if (v->voc_state == VOC_CHANGE) {
+ ret = voice_send_tty_mode_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Sending TTY mode failed, ret=%d\n",
+ __func__, ret);
+ /* Not a critical error, allow voice call to continue */
+ }
+
+ if (v->tty_mode) {
+ /* disable slowtalk */
+ voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_ST,
+ 0);
+ } else {
+ /* restore slowtalk */
+ voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_ST,
+ v->st_enable);
+ }
+
+ ret = voice_send_set_device_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Set device failed, ret=%d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ret = voice_send_cvp_device_channels_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Set device channels failed\n", __func__);
+ goto done;
+ }
+
+ ret = voice_send_cvp_topology_commit_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Set topology commit failed\n", __func__);
+ goto done;
+ }
+
+ voice_send_cvp_register_dev_cfg_cmd(v);
+ voice_send_cvp_register_cal_cmd(v);
+ voice_send_cvp_register_vol_cal_cmd(v);
+
+ rtac_add_voice(voice_get_cvs_handle(v),
+ voice_get_cvp_handle(v),
+ v->dev_rx.port_id, v->dev_tx.port_id,
+ v->dev_rx.dev_id, v->dev_tx.dev_id,
+ v->session_id);
+
+ ret = voice_send_start_voice_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Fail in sending START_VOICE, ret=%d\n",
+ __func__, ret);
+ goto done;
+ }
+ v->voc_state = VOC_RUN;
+ } else {
+ pr_debug("%s: called in voc state=%d, No_OP\n",
+ __func__, v->voc_state);
+ }
+
+done:
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_set_lch(uint32_t session_id, enum voice_lch_mode lch_mode)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&v->lock);
+ if (v->lch_mode == lch_mode) {
+ pr_debug("%s: Session %d already in LCH mode %d\n",
+ __func__, session_id, lch_mode);
+
+ mutex_unlock(&v->lock);
+ goto done;
+ }
+
+ v->lch_mode = lch_mode;
+ mutex_unlock(&v->lock);
+
+ ret = voc_lch_ops(v, v->lch_mode);
+ if (ret < 0) {
+ pr_err("%s: lch ops failed %d\n", __func__, ret);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+int voc_resume_voice_call(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ ret = voice_send_start_voice_cmd(v);
+ if (ret < 0) {
+ pr_err("Fail in sending START_VOICE\n");
+ goto fail;
+ }
+ v->voc_state = VOC_RUN;
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+int voc_start_voice_call(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+
+ if (v->voc_state == VOC_ERROR) {
+ pr_debug("%s: VOC in ERR state\n", __func__);
+
+ voice_destroy_mvm_cvs_session(v);
+ v->voc_state = VOC_INIT;
+ }
+
+ if ((v->voc_state == VOC_INIT) ||
+ (v->voc_state == VOC_RELEASE)) {
+ ret = voice_apr_register(session_id);
+ if (ret < 0) {
+ pr_err("%s: apr register failed\n", __func__);
+ goto fail;
+ }
+
+ if (is_cvd_version_queried()) {
+ pr_debug("%s: Returning the cached value %s\n",
+ __func__, common.cvd_version);
+ } else {
+ ret = voice_send_mvm_cvd_version_cmd(v);
+ if (ret < 0)
+ pr_debug("%s: Error retrieving CVD version %d\n",
+ __func__, ret);
+ }
+
+ ret = voice_create_mvm_cvs_session(v);
+ if (ret < 0) {
+ pr_err("create mvm and cvs failed\n");
+ goto fail;
+ }
+
+ if (is_voip_session(session_id)) {
+ /* Allocate oob mem if not already allocated and
+ * memory map the oob memory block.
+ */
+ ret = voice_alloc_and_map_oob_mem(v);
+ if (ret < 0) {
+ pr_err("%s: voice_alloc_and_map_oob_mem() failed, ret:%d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+
+ ret = voice_set_packet_exchange_mode_and_config(
+ session_id,
+ VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND);
+ if (ret) {
+ pr_err("%s: Err: exchange_mode_and_config %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ }
+ ret = voice_send_dual_control_cmd(v);
+ if (ret < 0) {
+ pr_err("Err Dual command failed\n");
+ goto fail;
+ }
+ ret = voice_setup_vocproc(v);
+ if (ret < 0) {
+ pr_err("setup voice failed\n");
+ goto fail;
+ }
+
+ ret = voice_send_vol_step_cmd(v);
+ if (ret < 0)
+ pr_err("voice volume failed\n");
+
+ ret = voice_send_stream_mute_cmd(v,
+ VSS_IVOLUME_DIRECTION_TX,
+ v->stream_tx.stream_mute,
+ v->stream_tx.stream_mute_ramp_duration_ms);
+ if (ret < 0)
+ pr_err("voice mute failed\n");
+
+ ret = voice_send_start_voice_cmd(v);
+ if (ret < 0) {
+ pr_err("start voice failed\n");
+ goto fail;
+ }
+
+ v->voc_state = VOC_RUN;
+ } else {
+ pr_err("%s: Error: Start voice called in state %d\n",
+ __func__, v->voc_state);
+
+ ret = -EINVAL;
+ goto fail;
+ }
+fail:
+ mutex_unlock(&v->lock);
+ return ret;
+}
+
+int voc_set_ext_ec_ref(uint16_t port_id, bool state)
+{
+ int ret = 0;
+
+ mutex_lock(&common.common_lock);
+ if (state == true) {
+ if (port_id == AFE_PORT_INVALID) {
+ pr_err("%s: Invalid port id", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ common.ec_port_id = port_id;
+ common.ec_ref_ext = true;
+ } else {
+ common.ec_ref_ext = false;
+ common.ec_port_id = port_id;
+ }
+exit:
+ mutex_unlock(&common.common_lock);
+ return ret;
+}
+
+void voc_register_mvs_cb(ul_cb_fn ul_cb,
+ dl_cb_fn dl_cb,
+ voip_ssr_cb ssr_cb,
+ void *private_data)
+{
+ common.mvs_info.ul_cb = ul_cb;
+ common.mvs_info.dl_cb = dl_cb;
+ common.mvs_info.ssr_cb = ssr_cb;
+ common.mvs_info.private_data = private_data;
+}
+
+void voc_register_dtmf_rx_detection_cb(dtmf_rx_det_cb_fn dtmf_rx_ul_cb,
+ void *private_data)
+{
+ common.dtmf_info.dtmf_rx_ul_cb = dtmf_rx_ul_cb;
+ common.dtmf_info.private_data = private_data;
+}
+
+void voc_config_vocoder(uint32_t media_type,
+ uint32_t rate,
+ uint32_t network_type,
+ uint32_t dtx_mode,
+ uint32_t evrc_min_rate,
+ uint32_t evrc_max_rate)
+{
+ common.mvs_info.media_type = media_type;
+ common.mvs_info.rate = rate;
+ common.mvs_info.network_type = network_type;
+ common.mvs_info.dtx_mode = dtx_mode;
+ common.mvs_info.evrc_min_rate = evrc_min_rate;
+ common.mvs_info.evrc_max_rate = evrc_max_rate;
+}
+
+static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t *ptr = NULL;
+ struct common_data *c = NULL;
+ struct voice_data *v = NULL;
+ int i = 0;
+ struct vss_iversion_rsp_get_t *version_rsp = NULL;
+
+ if ((data == NULL) || (priv == NULL)) {
+ pr_err("%s: data or priv is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ c = priv;
+
+ pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+ data->payload_size, data->opcode);
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: Reset event received in Voice service\n",
+ __func__);
+
+ if (common.mvs_info.ssr_cb) {
+ pr_debug("%s: Informing reset event to VoIP\n",
+ __func__);
+ common.mvs_info.ssr_cb(data->opcode,
+ common.mvs_info.private_data);
+ }
+
+ apr_reset(c->apr_q6_mvm);
+ c->apr_q6_mvm = NULL;
+
+ /* clean up memory handle */
+ c->cal_mem_handle = 0;
+ c->rtac_mem_handle = 0;
+ cal_utils_clear_cal_block_q6maps(MAX_VOICE_CAL_TYPES,
+ common.cal_data);
+ rtac_clear_mapping(VOICE_RTAC_CAL);
+
+ /* Sub-system restart is applicable to all sessions. */
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ c->voice[i].mvm_handle = 0;
+ c->voice[i].shmem_info.mem_handle = 0;
+ }
+
+ /* Free the ION memory and clear handles for Source Tracking */
+ if (is_source_tracking_shared_memomry_allocated()) {
+ msm_audio_ion_free(
+ common.source_tracking_sh_mem.sh_mem_block.client,
+ common.source_tracking_sh_mem.sh_mem_block.handle);
+ common.source_tracking_sh_mem.mem_handle = 0;
+ common.source_tracking_sh_mem.sh_mem_block.client =
+ NULL;
+ common.source_tracking_sh_mem.sh_mem_block.handle =
+ NULL;
+ }
+ /* clean up srvcc rec flag */
+ c->srvcc_rec_flag = false;
+ voc_set_error_state(data->reset_proc);
+ return 0;
+ }
+
+ pr_debug("%s: session_idx 0x%x\n", __func__, data->dest_port);
+
+ v = voice_get_session_by_idx(data->dest_port);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ return -EINVAL;
+ }
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ if (data->payload_size) {
+ ptr = data->payload;
+
+ pr_debug("%x %x\n", ptr[0], ptr[1]);
+ /* ping mvm service ACK */
+ switch (ptr[0]) {
+ case VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
+ case VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION:
+ /* Passive session is used for CS call
+ * Full session is used for VoIP call.
+ */
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ if (!ptr[1]) {
+ pr_debug("%s: MVM handle is %d\n",
+ __func__, data->src_port);
+ voice_set_mvm_handle(v, data->src_port);
+ } else
+ pr_err("got NACK for sending MVM create session\n");
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->mvm_wait);
+ break;
+ case VSS_IMVM_CMD_START_VOICE:
+ case VSS_IMVM_CMD_ATTACH_VOCPROC:
+ case VSS_IMVM_CMD_STOP_VOICE:
+ case VSS_IMVM_CMD_DETACH_VOCPROC:
+ case VSS_ISTREAM_CMD_SET_TTY_MODE:
+ case APRV2_IBASIC_CMD_DESTROY_SESSION:
+ case VSS_IMVM_CMD_ATTACH_STREAM:
+ case VSS_IMVM_CMD_DETACH_STREAM:
+ case VSS_ICOMMON_CMD_SET_NETWORK:
+ case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
+ case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
+ case VSS_IMVM_CMD_SET_CAL_NETWORK:
+ case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
+ case VSS_IMEMORY_CMD_MAP_PHYSICAL:
+ case VSS_IMEMORY_CMD_UNMAP:
+ case VSS_IMVM_CMD_PAUSE_VOICE:
+ case VSS_IMVM_CMD_STANDBY_VOICE:
+ case VSS_IHDVOICE_CMD_ENABLE:
+ case VSS_IHDVOICE_CMD_DISABLE:
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->mvm_wait);
+ break;
+ case VSS_IVERSION_CMD_GET:
+ pr_debug("%s: Error retrieving CVD Version, error:%d\n",
+ __func__, ptr[1]);
+
+ strlcpy(common.cvd_version, CVD_VERSION_0_0,
+ sizeof(common.cvd_version));
+ pr_debug("%s: Fall back to default value, CVD Version = %s\n",
+ __func__, common.cvd_version);
+
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->mvm_wait);
+ break;
+ default:
+ pr_debug("%s: not match cmd = 0x%x\n",
+ __func__, ptr[0]);
+ break;
+ }
+ }
+ } else if (data->opcode == VSS_IMEMORY_RSP_MAP) {
+ pr_debug("%s, Revd VSS_IMEMORY_RSP_MAP response\n", __func__);
+
+ if (data->payload_size && data->token == VOIP_MEM_MAP_TOKEN) {
+ ptr = data->payload;
+ if (ptr[0]) {
+ v->shmem_info.mem_handle = ptr[0];
+ pr_debug("%s: shared mem_handle: 0x[%x]\n",
+ __func__, v->shmem_info.mem_handle);
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ }
+ } else if (data->payload_size &&
+ data->token == VOC_CAL_MEM_MAP_TOKEN) {
+ ptr = data->payload;
+ if (ptr[0]) {
+ c->cal_mem_handle = ptr[0];
+
+ pr_debug("%s: cal mem handle 0x%x\n",
+ __func__, c->cal_mem_handle);
+
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ }
+ } else if (data->payload_size &&
+ data->token == VOC_VOICE_HOST_PCM_MAP_TOKEN) {
+ ptr = data->payload;
+ if (ptr[0]) {
+ common.voice_host_pcm_mem_handle = ptr[0];
+
+ pr_debug("%s: vhpcm mem handle 0x%x\n",
+ __func__,
+ common.voice_host_pcm_mem_handle);
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ }
+ } else if (data->payload_size &&
+ data->token == VOC_RTAC_MEM_MAP_TOKEN) {
+ ptr = data->payload;
+ if (ptr[0]) {
+ c->rtac_mem_handle = ptr[0];
+
+ pr_debug("%s: cal mem handle 0x%x\n",
+ __func__, c->rtac_mem_handle);
+
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ }
+ } else if (data->payload_size &&
+ data->token == VOC_SOURCE_TRACKING_MEM_MAP_TOKEN) {
+ ptr = data->payload;
+ if (ptr[0]) {
+ common.source_tracking_sh_mem.mem_handle =
+ ptr[0];
+
+ pr_debug("%s: Source Tracking shared mem handle 0x%x\n",
+ __func__,
+ common.source_tracking_sh_mem.mem_handle);
+
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ }
+ } else {
+ pr_err("%s: Unknown mem map token %d\n",
+ __func__, data->token);
+ }
+ } else if (data->opcode == VSS_IVERSION_RSP_GET) {
+ pr_debug("%s: Received VSS_IVERSION_RSP_GET\n", __func__);
+
+ if (data->payload_size) {
+ version_rsp =
+ (struct vss_iversion_rsp_get_t *)data->payload;
+ memcpy(common.cvd_version, version_rsp->version,
+ CVD_VERSION_STRING_MAX_SIZE);
+ pr_debug("%s: CVD Version = %s\n",
+ __func__, common.cvd_version);
+
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ }
+ }
+ return 0;
+}
+
+static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t *ptr = NULL;
+ struct common_data *c = NULL;
+ struct voice_data *v = NULL;
+ int i = 0;
+
+ if ((data == NULL) || (priv == NULL)) {
+ pr_err("%s: data or priv is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ c = priv;
+
+ pr_debug("%s: session_id 0x%x\n", __func__, data->dest_port);
+ pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+ data->payload_size, data->opcode);
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: Reset event received in Voice service\n",
+ __func__);
+
+ apr_reset(c->apr_q6_cvs);
+ c->apr_q6_cvs = NULL;
+
+ /* Sub-system restart is applicable to all sessions. */
+ for (i = 0; i < MAX_VOC_SESSIONS; i++)
+ c->voice[i].cvs_handle = 0;
+
+ cal_utils_clear_cal_block_q6maps(MAX_VOICE_CAL_TYPES,
+ common.cal_data);
+
+ /* Free the ION memory and clear handles for Source Tracking */
+ if (is_source_tracking_shared_memomry_allocated()) {
+ msm_audio_ion_free(
+ common.source_tracking_sh_mem.sh_mem_block.client,
+ common.source_tracking_sh_mem.sh_mem_block.handle);
+ common.source_tracking_sh_mem.mem_handle = 0;
+ common.source_tracking_sh_mem.sh_mem_block.client =
+ NULL;
+ common.source_tracking_sh_mem.sh_mem_block.handle =
+ NULL;
+ }
+ voc_set_error_state(data->reset_proc);
+ return 0;
+ }
+
+ v = voice_get_session_by_idx(data->dest_port);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ return -EINVAL;
+ }
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ if (data->payload_size) {
+ ptr = data->payload;
+
+ pr_debug("%x %x\n", ptr[0], ptr[1]);
+ if (ptr[1] != 0) {
+ pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+ __func__, ptr[0], ptr[1]);
+ }
+ /*response from CVS */
+ switch (ptr[0]) {
+ case VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
+ case VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION:
+ if (!ptr[1]) {
+ pr_debug("%s: CVS handle is %d\n",
+ __func__, data->src_port);
+ voice_set_cvs_handle(v, data->src_port);
+ } else
+ pr_err("got NACK for sending CVS create session\n");
+ v->cvs_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->cvs_wait);
+ break;
+ case VSS_IVOLUME_CMD_MUTE_V2:
+ case VSS_ISTREAM_CMD_SET_MEDIA_TYPE:
+ case VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE:
+ case VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE:
+ case VSS_ISTREAM_CMD_SET_ENC_DTX_MODE:
+ case VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE:
+ case APRV2_IBASIC_CMD_DESTROY_SESSION:
+ case VSS_ISTREAM_CMD_REGISTER_CALIBRATION_DATA_V2:
+ case VSS_ISTREAM_CMD_DEREGISTER_CALIBRATION_DATA:
+ case VSS_ISTREAM_CMD_REGISTER_STATIC_CALIBRATION_DATA:
+ case VSS_ISTREAM_CMD_DEREGISTER_STATIC_CALIBRATION_DATA:
+ case VSS_ICOMMON_CMD_MAP_MEMORY:
+ case VSS_ICOMMON_CMD_UNMAP_MEMORY:
+ case VSS_ICOMMON_CMD_SET_UI_PROPERTY:
+ case VSS_IPLAYBACK_CMD_START:
+ case VSS_IPLAYBACK_CMD_STOP:
+ case VSS_IRECORD_CMD_START:
+ case VSS_IRECORD_CMD_STOP:
+ case VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE:
+ case VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG:
+ case VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION:
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ v->cvs_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->cvs_wait);
+ break;
+ case VOICE_CMD_SET_PARAM:
+ pr_debug("%s: VOICE_CMD_SET_PARAM\n", __func__);
+ rtac_make_voice_callback(RTAC_CVS, ptr,
+ data->payload_size);
+ break;
+ case VOICE_CMD_GET_PARAM:
+ pr_debug("%s: VOICE_CMD_GET_PARAM\n",
+ __func__);
+ /* Should only come here if there is an APR */
+ /* error or malformed APR packet. Otherwise */
+ /* response will be returned as */
+ /* VOICE_EVT_GET_PARAM_ACK */
+ if (ptr[1] != 0) {
+ pr_err("%s: CVP get param error = %d, resuming\n",
+ __func__, ptr[1]);
+ rtac_make_voice_callback(RTAC_CVP,
+ data->payload,
+ data->payload_size);
+ }
+ break;
+ default:
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ break;
+ }
+ }
+ } else if (data->opcode ==
+ VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY) {
+ int ret = 0;
+ u16 cvs_handle;
+ uint32_t *cvs_voc_pkt;
+ struct cvs_enc_buffer_consumed_cmd send_enc_buf_consumed_cmd;
+ void *apr_cvs;
+
+ pr_debug("Encoder buffer is ready\n");
+
+ apr_cvs = common.apr_q6_cvs;
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ send_enc_buf_consumed_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ send_enc_buf_consumed_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(send_enc_buf_consumed_cmd) - APR_HDR_SIZE);
+
+ send_enc_buf_consumed_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ send_enc_buf_consumed_cmd.hdr.dest_port = cvs_handle;
+ send_enc_buf_consumed_cmd.hdr.token = 0;
+ send_enc_buf_consumed_cmd.hdr.opcode =
+ VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED;
+
+ cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data;
+ if (cvs_voc_pkt != NULL && common.mvs_info.ul_cb != NULL) {
+ /* cvs_voc_pkt[0] contains tx timestamp */
+ common.mvs_info.ul_cb((uint8_t *)&cvs_voc_pkt[3],
+ cvs_voc_pkt[2],
+ cvs_voc_pkt[0],
+ common.mvs_info.private_data);
+ } else
+ pr_err("%s: cvs_voc_pkt or ul_cb is NULL\n", __func__);
+
+ ret = apr_send_pkt(apr_cvs,
+ (uint32_t *) &send_enc_buf_consumed_cmd);
+ if (ret < 0) {
+ pr_err("%s: Err send ENC_BUF_CONSUMED_NOTIFY %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ } else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
+ pr_debug("Recd VSS_ISTREAM_EVT_SEND_ENC_BUFFER\n");
+ } else if (data->opcode ==
+ VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_REQUEST) {
+ int ret = 0;
+ u16 cvs_handle;
+ uint32_t *cvs_voc_pkt;
+ struct cvs_dec_buffer_ready_cmd send_dec_buf;
+ void *apr_cvs;
+
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ send_dec_buf.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+
+ send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(send_dec_buf) - APR_HDR_SIZE);
+
+ send_dec_buf.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ send_dec_buf.hdr.dest_port = cvs_handle;
+ send_dec_buf.hdr.token = 0;
+ send_dec_buf.hdr.opcode =
+ VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_READY;
+
+ cvs_voc_pkt = (uint32_t *)(v->shmem_info.sh_buf.buf[0].data);
+ if (cvs_voc_pkt != NULL && common.mvs_info.dl_cb != NULL) {
+ /* Set timestamp to 0 and advance the pointer */
+ cvs_voc_pkt[0] = 0;
+ /* Set media_type and advance the pointer */
+ cvs_voc_pkt[1] = common.mvs_info.media_type;
+ common.mvs_info.dl_cb(
+ (uint8_t *)&cvs_voc_pkt[2],
+ common.mvs_info.private_data);
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &send_dec_buf);
+ if (ret < 0) {
+ pr_err("%s: Err send DEC_BUF_READY_NOTIFI %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ } else {
+ pr_debug("%s: voc_pkt or dl_cb is NULL\n", __func__);
+ goto fail;
+ }
+ } else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
+ pr_debug("Recd VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER\n");
+ } else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER) {
+ pr_debug("Send dec buf resp\n");
+ } else if (data->opcode == APR_RSP_ACCEPTED) {
+ ptr = data->payload;
+ if (ptr[0])
+ pr_debug("%s: APR_RSP_ACCEPTED for 0x%x:\n",
+ __func__, ptr[0]);
+ } else if (data->opcode == VSS_ISTREAM_EVT_NOT_READY) {
+ pr_debug("Recd VSS_ISTREAM_EVT_NOT_READY\n");
+ } else if (data->opcode == VSS_ISTREAM_EVT_READY) {
+ pr_debug("Recd VSS_ISTREAM_EVT_READY\n");
+ } else if (data->opcode == VOICE_EVT_GET_PARAM_ACK) {
+ pr_debug("%s: VOICE_EVT_GET_PARAM_ACK\n", __func__);
+ ptr = data->payload;
+ if (ptr[0] != 0) {
+ pr_err("%s: VOICE_EVT_GET_PARAM_ACK returned error = 0x%x\n",
+ __func__, ptr[0]);
+ }
+ rtac_make_voice_callback(RTAC_CVS, data->payload,
+ data->payload_size);
+ } else if (data->opcode == VSS_ISTREAM_EVT_RX_DTMF_DETECTED) {
+ struct vss_istream_evt_rx_dtmf_detected *dtmf_rx_detected;
+ uint32_t *voc_pkt = data->payload;
+ uint32_t pkt_len = data->payload_size;
+
+ if ((voc_pkt != NULL) &&
+ (pkt_len ==
+ sizeof(struct vss_istream_evt_rx_dtmf_detected))) {
+
+ dtmf_rx_detected =
+ (struct vss_istream_evt_rx_dtmf_detected *) voc_pkt;
+ pr_debug("RX_DTMF_DETECTED low_freq=%d high_freq=%d\n",
+ dtmf_rx_detected->low_freq,
+ dtmf_rx_detected->high_freq);
+ if (c->dtmf_info.dtmf_rx_ul_cb)
+ c->dtmf_info.dtmf_rx_ul_cb((uint8_t *)voc_pkt,
+ voc_get_session_name(v->session_id),
+ c->dtmf_info.private_data);
+ } else {
+ pr_err("Invalid packet\n");
+ }
+ } else
+ pr_debug("Unknown opcode 0x%x\n", data->opcode);
+
+fail:
+ return 0;
+}
+
+static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t *ptr = NULL;
+ struct common_data *c = NULL;
+ struct voice_data *v = NULL;
+ int i = 0;
+
+ if ((data == NULL) || (priv == NULL)) {
+ pr_err("%s: data or priv is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ c = priv;
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: Reset event received in Voice service\n",
+ __func__);
+
+ apr_reset(c->apr_q6_cvp);
+ c->apr_q6_cvp = NULL;
+ cal_utils_clear_cal_block_q6maps(MAX_VOICE_CAL_TYPES,
+ common.cal_data);
+
+ /* Sub-system restart is applicable to all sessions. */
+ for (i = 0; i < MAX_VOC_SESSIONS; i++)
+ c->voice[i].cvp_handle = 0;
+
+ /*
+ * Free the ION memory and clear handles for
+ * Source Tracking
+ */
+ if (is_source_tracking_shared_memomry_allocated()) {
+ msm_audio_ion_free(
+ common.source_tracking_sh_mem.sh_mem_block.client,
+ common.source_tracking_sh_mem.sh_mem_block.handle);
+ common.source_tracking_sh_mem.mem_handle = 0;
+ common.source_tracking_sh_mem.sh_mem_block.client =
+ NULL;
+ common.source_tracking_sh_mem.sh_mem_block.handle =
+ NULL;
+ }
+ voc_set_error_state(data->reset_proc);
+ return 0;
+ }
+
+ v = voice_get_session_by_idx(data->dest_port);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ return -EINVAL;
+ }
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ if (data->payload_size) {
+ ptr = data->payload;
+
+ pr_debug("%x %x\n", ptr[0], ptr[1]);
+ if (ptr[1] != 0) {
+ pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+ __func__, ptr[0], ptr[1]);
+ }
+ switch (ptr[0]) {
+ case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2:
+ case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V3:
+ /*response from CVP */
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ if (!ptr[1]) {
+ voice_set_cvp_handle(v, data->src_port);
+ pr_debug("status: %d, cvphdl=%d\n",
+ ptr[1], data->src_port);
+ } else
+ pr_err("got NACK from CVP create session response\n");
+ v->cvp_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->cvp_wait);
+ break;
+ case VSS_IVOCPROC_CMD_SET_DEVICE_V2:
+ case VSS_IVOCPROC_CMD_SET_DEVICE_V3:
+ case VSS_IVOLUME_CMD_SET_STEP:
+ case VSS_IVOCPROC_CMD_ENABLE:
+ case VSS_IVOCPROC_CMD_DISABLE:
+ case APRV2_IBASIC_CMD_DESTROY_SESSION:
+ case VSS_IVOCPROC_CMD_REGISTER_VOL_CALIBRATION_DATA:
+ case VSS_IVOCPROC_CMD_DEREGISTER_VOL_CALIBRATION_DATA:
+ case VSS_IVOCPROC_CMD_REGISTER_CALIBRATION_DATA_V2:
+ case VSS_IVOCPROC_CMD_DEREGISTER_CALIBRATION_DATA:
+ case VSS_IVOCPROC_CMD_REGISTER_DYNAMIC_CALIBRATION_DATA:
+ case VSS_IVOCPROC_CMD_DEREGISTER_DYNAMIC_CALIBRATION_DATA:
+ case VSS_IVOCPROC_CMD_REGISTER_STATIC_CALIBRATION_DATA:
+ case VSS_IVOCPROC_CMD_DEREGISTER_STATIC_CALIBRATION_DATA:
+ case VSS_IVOCPROC_CMD_REGISTER_DEVICE_CONFIG:
+ case VSS_IVOCPROC_CMD_DEREGISTER_DEVICE_CONFIG:
+ case VSS_ICOMMON_CMD_MAP_MEMORY:
+ case VSS_ICOMMON_CMD_UNMAP_MEMORY:
+ case VSS_IVOLUME_CMD_MUTE_V2:
+ case VSS_IVPCM_CMD_START_V2:
+ case VSS_IVPCM_CMD_STOP:
+ case VSS_IVOCPROC_CMD_TOPOLOGY_SET_DEV_CHANNELS:
+ case VSS_IVOCPROC_CMD_TOPOLOGY_COMMIT:
+ v->cvp_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->cvp_wait);
+ break;
+ case VSS_IVPCM_EVT_PUSH_BUFFER_V2:
+ break;
+ case VOICE_CMD_SET_PARAM:
+ pr_debug("%s: VOICE_CMD_SET_PARAM\n", __func__);
+ rtac_make_voice_callback(RTAC_CVP, ptr,
+ data->payload_size);
+ break;
+ case VOICE_CMD_GET_PARAM:
+ pr_debug("%s: VOICE_CMD_GET_PARAM\n",
+ __func__);
+ /* Should only come here if there is an APR */
+ /* error or malformed APR packet. Otherwise */
+ /* response will be returned as */
+ /* VOICE_EVT_GET_PARAM_ACK */
+ if (ptr[1] != 0) {
+ pr_err("%s: CVP get param error = %d, resuming\n",
+ __func__, ptr[1]);
+ rtac_make_voice_callback(RTAC_CVP,
+ data->payload,
+ data->payload_size);
+ }
+ break;
+ case VSS_ISOUNDFOCUS_CMD_SET_SECTORS:
+ if (!ptr[1])
+ common.is_sound_focus_resp_success =
+ true;
+ else
+ common.is_sound_focus_resp_success =
+ false;
+ v->cvp_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->cvp_wait);
+ break;
+ case VSS_ISOUNDFOCUS_CMD_GET_SECTORS:
+ /*
+ * Should only come here if there is an error
+ * response received from ADSP. Otherwise
+ * response will be returned as
+ * VSS_ISOUNDFOCUS_RSP_GET_SECTORS
+ */
+ pr_err("%s: VSS_ISOUNDFOCUS_CMD_GET_SECTORS failed\n",
+ __func__);
+
+ common.is_sound_focus_resp_success = false;
+ v->cvp_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->cvp_wait);
+ break;
+ case VSS_ISOURCETRACK_CMD_GET_ACTIVITY:
+ if (!ptr[1]) {
+ /* Read data from shared memory */
+ memcpy(&common.sourceTrackingResponse,
+ common.source_tracking_sh_mem.
+ sh_mem_block.data,
+ sizeof(struct
+ vss_isourcetrack_activity_data_t));
+ common.is_source_tracking_resp_success =
+ true;
+ } else {
+ common.is_source_tracking_resp_success =
+ false;
+ pr_err("%s: Error received for source tracking params\n",
+ __func__);
+ }
+ v->cvp_state = CMD_STATUS_SUCCESS;
+ v->async_err = ptr[1];
+ wake_up(&v->cvp_wait);
+ break;
+ default:
+ pr_debug("%s: not match cmd = 0x%x\n",
+ __func__, ptr[0]);
+ break;
+ }
+ }
+ } else if (data->opcode == VOICE_EVT_GET_PARAM_ACK) {
+ pr_debug("%s: VOICE_EVT_GET_PARAM_ACK\n", __func__);
+ ptr = data->payload;
+ if (ptr[0] != 0) {
+ pr_err("%s: VOICE_EVT_GET_PARAM_ACK returned error = 0x%x\n",
+ __func__, ptr[0]);
+ }
+ rtac_make_voice_callback(RTAC_CVP, data->payload,
+ data->payload_size);
+ } else if (data->opcode == VSS_IVPCM_EVT_NOTIFY_V2) {
+ if ((data->payload != NULL) && data->payload_size ==
+ sizeof(struct vss_ivpcm_evt_notify_v2_t) &&
+ common.hostpcm_info.hostpcm_evt_cb != NULL) {
+ common.hostpcm_info.hostpcm_evt_cb(data->payload,
+ voc_get_session_name(v->session_id),
+ common.hostpcm_info.private_data);
+ }
+ } else if (data->opcode == VSS_ISOUNDFOCUS_RSP_GET_SECTORS) {
+ if (data->payload && (data->payload_size ==
+ sizeof(struct vss_isoundfocus_rsp_get_sectors_t))) {
+ common.is_sound_focus_resp_success = true;
+ memcpy(&common.soundFocusResponse,
+ (struct vss_isoundfocus_rsp_get_sectors_t *)
+ data->payload,
+ sizeof(struct
+ vss_isoundfocus_rsp_get_sectors_t));
+ } else {
+ common.is_sound_focus_resp_success = false;
+ pr_debug("%s: Invalid payload received from CVD\n",
+ __func__);
+ }
+ v->cvp_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->cvp_wait);
+ }
+ return 0;
+}
+
+static int voice_free_oob_shared_mem(void)
+{
+ int rc = 0;
+ int cnt = 0;
+ int bufcnt = NUM_OF_BUFFERS;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ mutex_lock(&common.common_lock);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ rc = -EINVAL;
+ goto done;
+ }
+
+ rc = msm_audio_ion_free(v->shmem_info.sh_buf.client,
+ v->shmem_info.sh_buf.handle);
+ v->shmem_info.sh_buf.client = NULL;
+ v->shmem_info.sh_buf.handle = NULL;
+ if (rc < 0) {
+ pr_err("%s: Error:%d freeing memory\n", __func__, rc);
+
+ goto done;
+ }
+
+
+ while (cnt < bufcnt) {
+ v->shmem_info.sh_buf.buf[cnt].data = NULL;
+ v->shmem_info.sh_buf.buf[cnt].phys = 0;
+ cnt++;
+ }
+
+ v->shmem_info.sh_buf.client = NULL;
+ v->shmem_info.sh_buf.handle = NULL;
+
+done:
+ mutex_unlock(&common.common_lock);
+ return rc;
+}
+
+static int voice_alloc_oob_shared_mem(void)
+{
+ int cnt = 0;
+ int rc = 0;
+ size_t len;
+ void *mem_addr;
+ dma_addr_t phys;
+ int bufsz = BUFFER_BLOCK_SIZE;
+ int bufcnt = NUM_OF_BUFFERS;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ mutex_lock(&common.common_lock);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ rc = -EINVAL;
+ goto done;
+ }
+
+ rc = msm_audio_ion_alloc("voip_client", &(v->shmem_info.sh_buf.client),
+ &(v->shmem_info.sh_buf.handle),
+ bufsz*bufcnt,
+ &phys, &len,
+ &mem_addr);
+ if (rc < 0) {
+ pr_err("%s: audio ION alloc failed, rc = %d\n",
+ __func__, rc);
+
+ goto done;
+ }
+
+ while (cnt < bufcnt) {
+ v->shmem_info.sh_buf.buf[cnt].data = mem_addr + (cnt * bufsz);
+ v->shmem_info.sh_buf.buf[cnt].phys = phys + (cnt * bufsz);
+ v->shmem_info.sh_buf.buf[cnt].size = bufsz;
+ cnt++;
+ }
+
+ pr_debug("%s buf[0].data:[%pK], buf[0].phys:[%pK], &buf[0].phys:[%pK],\n",
+ __func__,
+ (void *)v->shmem_info.sh_buf.buf[0].data,
+ &v->shmem_info.sh_buf.buf[0].phys,
+ (void *)&v->shmem_info.sh_buf.buf[0].phys);
+ pr_debug("%s: buf[1].data:[%pK], buf[1].phys[%pK], &buf[1].phys[%pK]\n",
+ __func__,
+ (void *)v->shmem_info.sh_buf.buf[1].data,
+ &v->shmem_info.sh_buf.buf[1].phys,
+ (void *)&v->shmem_info.sh_buf.buf[1].phys);
+
+ memset((void *)v->shmem_info.sh_buf.buf[0].data, 0, (bufsz * bufcnt));
+
+done:
+ mutex_unlock(&common.common_lock);
+ return rc;
+}
+
+static int voice_alloc_oob_mem_table(void)
+{
+ int rc = 0;
+ size_t len;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ mutex_lock(&common.common_lock);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ rc = -EINVAL;
+ goto done;
+ }
+
+ rc = msm_audio_ion_alloc("voip_client", &(v->shmem_info.memtbl.client),
+ &(v->shmem_info.memtbl.handle),
+ sizeof(struct vss_imemory_table_t),
+ &v->shmem_info.memtbl.phys,
+ &len,
+ &(v->shmem_info.memtbl.data));
+ if (rc < 0) {
+ pr_err("%s: audio ION alloc failed, rc = %d\n",
+ __func__, rc);
+
+ goto done;
+ }
+
+ v->shmem_info.memtbl.size = sizeof(struct vss_imemory_table_t);
+ pr_debug("%s data[%pK]phys[%pK][%pK]\n", __func__,
+ (void *)v->shmem_info.memtbl.data,
+ &v->shmem_info.memtbl.phys,
+ (void *)&v->shmem_info.memtbl.phys);
+
+done:
+ mutex_unlock(&common.common_lock);
+ return rc;
+}
+
+int voc_send_cvp_start_vocpcm(uint32_t session_id,
+ struct vss_ivpcm_tap_point *vpcm_tp,
+ uint32_t no_of_tp)
+{
+ struct cvp_start_cmd cvp_start_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+ struct voice_data *v = voice_get_session(session_id);
+ int i = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* Fill the header */
+ cvp_start_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvp_start_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(struct vss_ivpcm_tap_point) * no_of_tp) +
+ sizeof(cvp_start_cmd.vpcm_start_cmd.num_tap_points) +
+ sizeof(cvp_start_cmd.vpcm_start_cmd.mem_handle);
+ cvp_start_cmd.hdr.src_port = voice_get_idx_for_session(v->session_id);
+ cvp_start_cmd.hdr.dest_port = cvp_handle;
+ cvp_start_cmd.hdr.token = 0;
+ cvp_start_cmd.hdr.opcode = VSS_IVPCM_CMD_START_V2;
+
+ for (i = 0; i < no_of_tp; i++) {
+ cvp_start_cmd.vpcm_start_cmd.tap_points[i].tap_point =
+ vpcm_tp[i].tap_point;
+ cvp_start_cmd.vpcm_start_cmd.tap_points[i].direction =
+ vpcm_tp[i].direction;
+ cvp_start_cmd.vpcm_start_cmd.tap_points[i].sampling_rate =
+ vpcm_tp[i].sampling_rate;
+ cvp_start_cmd.vpcm_start_cmd.tap_points[i].duration = 0;
+ }
+
+ cvp_start_cmd.vpcm_start_cmd.mem_handle =
+ common.voice_host_pcm_mem_handle;
+ cvp_start_cmd.vpcm_start_cmd.num_tap_points = no_of_tp;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_start_cmd);
+ if (ret < 0) {
+ pr_err("%s: Fail: sending vocpcm map memory,\n", __func__);
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto done;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+int voc_send_cvp_stop_vocpcm(uint32_t session_id)
+{
+ struct cvp_command vpcm_stop_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+ struct voice_data *v = voice_get_session(session_id);
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* fill in the header */
+ vpcm_stop_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ vpcm_stop_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(vpcm_stop_cmd) - APR_HDR_SIZE);
+ vpcm_stop_cmd.hdr.src_port = voice_get_idx_for_session(v->session_id);
+ vpcm_stop_cmd.hdr.dest_port = cvp_handle;
+ vpcm_stop_cmd.hdr.token = 0;
+ vpcm_stop_cmd.hdr.opcode = VSS_IVPCM_CMD_STOP;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &vpcm_stop_cmd);
+ if (ret < 0) {
+ pr_err("Fail: sending vocpcm stop,\n");
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto done;
+ }
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+int voc_send_cvp_map_vocpcm_memory(uint32_t session_id,
+ struct mem_map_table *tp_mem_table,
+ phys_addr_t paddr, uint32_t bufsize)
+{
+ return voice_map_memory_physical_cmd(voice_get_session(session_id),
+ tp_mem_table,
+ (dma_addr_t) paddr, bufsize,
+ VOC_VOICE_HOST_PCM_MAP_TOKEN);
+}
+
+int voc_send_cvp_unmap_vocpcm_memory(uint32_t session_id)
+{
+ int ret = 0;
+
+ ret = voice_send_mvm_unmap_memory_physical_cmd(
+ voice_get_session(session_id),
+ common.voice_host_pcm_mem_handle);
+
+ if (ret == 0)
+ common.voice_host_pcm_mem_handle = 0;
+
+ return ret;
+}
+
+int voc_send_cvp_vocpcm_push_buf_evt(uint32_t session_id,
+ struct vss_ivpcm_evt_push_buffer_v2_t *push_buff_evt)
+{
+ struct cvp_push_buf_cmd vpcm_push_buf_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+ struct voice_data *v = voice_get_session(session_id);
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(&vpcm_push_buf_cmd, 0, sizeof(vpcm_push_buf_cmd));
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* fill in the header */
+ vpcm_push_buf_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ vpcm_push_buf_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(vpcm_push_buf_cmd) - APR_HDR_SIZE);
+ vpcm_push_buf_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ vpcm_push_buf_cmd.hdr.dest_port = cvp_handle;
+ vpcm_push_buf_cmd.hdr.token = 0;
+ vpcm_push_buf_cmd.hdr.opcode = VSS_IVPCM_EVT_PUSH_BUFFER_V2;
+
+ vpcm_push_buf_cmd.vpcm_evt_push_buffer.tap_point =
+ push_buff_evt->tap_point;
+ vpcm_push_buf_cmd.vpcm_evt_push_buffer.push_buf_mask =
+ push_buff_evt->push_buf_mask;
+ vpcm_push_buf_cmd.vpcm_evt_push_buffer.out_buf_mem_address =
+ push_buff_evt->out_buf_mem_address;
+ vpcm_push_buf_cmd.vpcm_evt_push_buffer.in_buf_mem_address =
+ push_buff_evt->in_buf_mem_address;
+ vpcm_push_buf_cmd.vpcm_evt_push_buffer.out_buf_mem_size =
+ push_buff_evt->out_buf_mem_size;
+ vpcm_push_buf_cmd.vpcm_evt_push_buffer.in_buf_mem_size =
+ push_buff_evt->in_buf_mem_size;
+ vpcm_push_buf_cmd.vpcm_evt_push_buffer.sampling_rate =
+ push_buff_evt->sampling_rate;
+ vpcm_push_buf_cmd.vpcm_evt_push_buffer.num_in_channels =
+ push_buff_evt->num_in_channels;
+
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &vpcm_push_buf_cmd);
+ if (ret < 0) {
+ pr_err("Fail: sending vocpcm map memory,\n");
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+void voc_register_hpcm_evt_cb(hostpcm_cb_fn hostpcm_cb,
+ void *private_data)
+{
+ common.hostpcm_info.hostpcm_evt_cb = hostpcm_cb;
+ common.hostpcm_info.private_data = private_data;
+}
+
+void voc_deregister_hpcm_evt_cb(void)
+{
+ common.hostpcm_info.hostpcm_evt_cb = NULL;
+ common.hostpcm_info.private_data = NULL;
+}
+
+int voc_get_cvd_version(char *cvd_version)
+{
+ int ret = 0;
+ struct voice_data *v = voice_get_session(VOICE_SESSION_VSID);
+
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n",
+ __func__, VOICE_SESSION_VSID);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (is_cvd_version_queried()) {
+ pr_debug("%s: Returning the cached value %s\n",
+ __func__, common.cvd_version);
+
+ goto done;
+ }
+
+ /* Register callback to APR */
+ ret = voice_apr_register(VOICE_SESSION_VSID);
+ if (ret < 0) {
+ pr_err("%s: apr register failed\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&common.common_lock);
+ mutex_lock(&v->lock);
+ ret = voice_send_mvm_cvd_version_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: voice_send_mvm_cvd_version_cmd failed\n", __func__);
+ goto unlock;
+ }
+ ret = 0;
+
+unlock:
+ mutex_unlock(&v->lock);
+ mutex_unlock(&common.common_lock);
+
+done:
+ if (cvd_version)
+ memcpy(cvd_version, common.cvd_version,
+ CVD_VERSION_STRING_MAX_SIZE);
+
+ return ret;
+}
+
+static int voice_alloc_cal_mem_map_table(void)
+{
+ int ret = 0;
+ size_t len;
+
+ ret = msm_audio_ion_alloc("voc_cal",
+ &(common.cal_mem_map_table.client),
+ &(common.cal_mem_map_table.handle),
+ sizeof(struct vss_imemory_table_t),
+ &common.cal_mem_map_table.phys,
+ &len,
+ &(common.cal_mem_map_table.data));
+ if ((ret < 0) && (ret != -EPROBE_DEFER)) {
+ pr_err("%s: audio ION alloc failed, rc = %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ common.cal_mem_map_table.size = sizeof(struct vss_imemory_table_t);
+ pr_debug("%s: data %pK phys %pK\n", __func__,
+ common.cal_mem_map_table.data,
+ &common.cal_mem_map_table.phys);
+
+done:
+ return ret;
+}
+
+static int voice_alloc_rtac_mem_map_table(void)
+{
+ int ret = 0;
+ size_t len;
+
+ ret = msm_audio_ion_alloc("voc_rtac_cal",
+ &(common.rtac_mem_map_table.client),
+ &(common.rtac_mem_map_table.handle),
+ sizeof(struct vss_imemory_table_t),
+ &common.rtac_mem_map_table.phys,
+ &len,
+ &(common.rtac_mem_map_table.data));
+ if (ret < 0) {
+ pr_err("%s: audio ION alloc failed, rc = %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ common.rtac_mem_map_table.size = sizeof(struct vss_imemory_table_t);
+ pr_debug("%s: data %pK phys %pK\n", __func__,
+ common.rtac_mem_map_table.data,
+ &common.rtac_mem_map_table.phys);
+
+done:
+ return ret;
+}
+
+static int voice_alloc_and_map_oob_mem(struct voice_data *v)
+{
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ return -EINVAL;
+ }
+
+ if (!is_voip_memory_allocated()) {
+ ret = voc_alloc_voip_shared_memory();
+ if (ret < 0) {
+ pr_err("%s: Failed to create voip oob memory %d\n",
+ __func__, ret);
+
+ goto done;
+ }
+ }
+
+ ret = voice_map_memory_physical_cmd(v,
+ &v->shmem_info.memtbl,
+ v->shmem_info.sh_buf.buf[0].phys,
+ v->shmem_info.sh_buf.buf[0].size * NUM_OF_BUFFERS,
+ VOIP_MEM_MAP_TOKEN);
+ if (ret) {
+ pr_err("%s: mvm_map_memory_phy failed %d\n",
+ __func__, ret);
+
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+uint32_t voice_get_topology(uint32_t topology_idx)
+{
+ uint32_t topology = VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+ struct cal_block_data *cal_block = NULL;
+
+ /* initialize as default topology */
+ if (topology_idx == CVP_VOC_RX_TOPOLOGY_CAL) {
+ topology = VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+ } else if (topology_idx == CVP_VOC_TX_TOPOLOGY_CAL) {
+ topology = VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+ } else {
+ pr_err("%s: cal index %x is invalid!\n",
+ __func__, topology_idx);
+
+ goto done;
+ }
+
+ if (common.cal_data[topology_idx] == NULL) {
+ pr_err("%s: cal type is NULL for cal index %x\n",
+ __func__, topology_idx);
+
+ goto done;
+ }
+
+ mutex_lock(&common.cal_data[topology_idx]->lock);
+ cal_block = cal_utils_get_only_cal_block(
+ common.cal_data[topology_idx]);
+ if (cal_block == NULL) {
+ pr_debug("%s: cal_block not found for cal index %x\n",
+ __func__, topology_idx);
+
+ goto unlock;
+ }
+
+ topology = ((struct audio_cal_info_voc_top *)
+ cal_block->cal_info)->topology;
+unlock:
+ mutex_unlock(&common.cal_data[topology_idx]->lock);
+done:
+ pr_debug("%s: Using topology %d\n", __func__, topology);
+
+ return topology;
+}
+
+static int get_cal_type_index(int32_t cal_type)
+{
+ int ret = -EINVAL;
+
+ switch (cal_type) {
+ case CVP_VOC_RX_TOPOLOGY_CAL_TYPE:
+ ret = CVP_VOC_RX_TOPOLOGY_CAL;
+ break;
+ case CVP_VOC_TX_TOPOLOGY_CAL_TYPE:
+ ret = CVP_VOC_TX_TOPOLOGY_CAL;
+ break;
+ case CVP_VOCPROC_STATIC_CAL_TYPE:
+ ret = CVP_VOCPROC_CAL;
+ break;
+ case CVP_VOCPROC_DYNAMIC_CAL_TYPE:
+ ret = CVP_VOCVOL_CAL;
+ break;
+ case CVS_VOCSTRM_STATIC_CAL_TYPE:
+ ret = CVS_VOCSTRM_CAL;
+ break;
+ case CVP_VOCDEV_CFG_CAL_TYPE:
+ ret = CVP_VOCDEV_CFG_CAL;
+ break;
+ case CVP_VOCPROC_STATIC_COL_CAL_TYPE:
+ ret = CVP_VOCPROC_COL_CAL;
+ break;
+ case CVP_VOCPROC_DYNAMIC_COL_CAL_TYPE:
+ ret = CVP_VOCVOL_COL_CAL;
+ break;
+ case CVS_VOCSTRM_STATIC_COL_CAL_TYPE:
+ ret = CVS_VOCSTRM_COL_CAL;
+ break;
+ case VOICE_RTAC_INFO_CAL_TYPE:
+ ret = VOICE_RTAC_INFO_CAL;
+ break;
+ case VOICE_RTAC_APR_CAL_TYPE:
+ ret = VOICE_RTAC_APR_CAL;
+ break;
+ default:
+ pr_err("%s: Invalid cal type %d!\n", __func__, cal_type);
+ }
+ return ret;
+}
+
+static int voice_prepare_volume_boost(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ return voc_deregister_vocproc_vol_table();
+}
+
+static int voice_enable_volume_boost(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ return voc_register_vocproc_vol_table();
+}
+
+static int voice_alloc_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+ int cal_version;
+
+ pr_debug("%s\n", __func__);
+
+ cal_version = cal_utils_get_cal_type_version(data);
+ common.is_per_vocoder_cal_enabled =
+ !!(cal_version & PER_VOCODER_CAL_BIT_MASK);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: Could not get cal index %d!\n",
+ __func__, cal_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_alloc_cal(data_size, data,
+ common.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: Cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int voice_dealloc_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: Could not get cal index %d!\n",
+ __func__, cal_index);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_dealloc_cal(data_size, data,
+ common.cal_data[cal_index]);
+ if (ret < 0) {
+ pr_err("%s: Cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static int voice_set_cal(int32_t cal_type,
+ size_t data_size, void *data)
+{
+ int ret = 0;
+ int cal_index;
+
+ pr_debug("%s\n", __func__);
+
+ cal_index = get_cal_type_index(cal_type);
+ if (cal_index < 0) {
+ pr_err("%s: Could not get cal index %d!\n",
+ __func__, cal_index);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = cal_utils_set_cal(data_size, data,
+ common.cal_data[cal_index], 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: Cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
+ __func__, ret, cal_type);
+
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static void voice_delete_cal_data(void)
+{
+ pr_debug("%s\n", __func__);
+
+ cal_utils_destroy_cal_types(MAX_VOICE_CAL_TYPES, common.cal_data);
+}
+
+static int voice_init_cal_data(void)
+{
+ int ret = 0;
+ struct cal_type_info cal_type_info[] = {
+ {{CVP_VOC_RX_TOPOLOGY_CAL_TYPE,
+ {NULL, NULL, NULL, voice_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{CVP_VOC_TX_TOPOLOGY_CAL_TYPE,
+ {NULL, NULL, NULL, voice_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{CVP_VOCPROC_STATIC_CAL_TYPE,
+ {voice_alloc_cal, voice_dealloc_cal, NULL,
+ voice_set_cal, NULL, NULL} },
+ {NULL, voice_unmap_cal_memory,
+ cal_utils_match_buf_num} },
+
+ {{CVP_VOCPROC_DYNAMIC_CAL_TYPE,
+ {voice_alloc_cal, voice_dealloc_cal,
+ voice_prepare_volume_boost,
+ voice_set_cal, NULL,
+ voice_enable_volume_boost} },
+ {NULL, voice_unmap_cal_memory,
+ cal_utils_match_buf_num} },
+
+ {{CVP_VOCDEV_CFG_CAL_TYPE,
+ {voice_alloc_cal, voice_dealloc_cal, NULL,
+ voice_set_cal, NULL, NULL} },
+ {NULL, voice_unmap_cal_memory,
+ cal_utils_match_buf_num} },
+
+ {{CVP_VOCPROC_STATIC_COL_CAL_TYPE,
+ {NULL, NULL, NULL, voice_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{CVP_VOCPROC_DYNAMIC_COL_CAL_TYPE,
+ {NULL, NULL, NULL, voice_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{CVS_VOCSTRM_STATIC_CAL_TYPE,
+ {voice_alloc_cal, voice_dealloc_cal, NULL,
+ voice_set_cal, NULL, NULL} },
+ {NULL, voice_unmap_cal_memory,
+ cal_utils_match_buf_num} },
+
+ {{CVS_VOCSTRM_STATIC_COL_CAL_TYPE,
+ {NULL, NULL, NULL, voice_set_cal, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{VOICE_RTAC_INFO_CAL_TYPE,
+ {NULL, NULL, NULL, NULL, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+
+ {{VOICE_RTAC_APR_CAL_TYPE,
+ {NULL, NULL, NULL, NULL, NULL, NULL} },
+ {NULL, NULL, cal_utils_match_buf_num} },
+ };
+
+ ret = cal_utils_create_cal_types(MAX_VOICE_CAL_TYPES, common.cal_data,
+ cal_type_info);
+ if (ret < 0) {
+ pr_err("%s: Could not create cal type!\n",
+ __func__);
+
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return ret;
+err:
+ voice_delete_cal_data();
+ memset(&common, 0, sizeof(struct common_data));
+ return ret;
+}
+
+static int voice_send_set_sound_focus_cmd(struct voice_data *v,
+ struct sound_focus_param soundFocusData)
+{
+ struct cvp_set_sound_focus_param_cmd_t cvp_set_sound_focus_param_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+ int i;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* send Sound Focus Params to cvp */
+ cvp_set_sound_focus_param_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_set_sound_focus_param_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_set_sound_focus_param_cmd) - APR_HDR_SIZE);
+ cvp_set_sound_focus_param_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_set_sound_focus_param_cmd.hdr.dest_port = cvp_handle;
+ cvp_set_sound_focus_param_cmd.hdr.token = 0;
+ cvp_set_sound_focus_param_cmd.hdr.opcode =
+ VSS_ISOUNDFOCUS_CMD_SET_SECTORS;
+
+ memset(&(cvp_set_sound_focus_param_cmd.cvp_set_sound_focus_param), 0xFF,
+ sizeof(struct vss_isoundfocus_cmd_set_sectors_t));
+ for (i = 0; i < MAX_SECTORS; i++) {
+ cvp_set_sound_focus_param_cmd.cvp_set_sound_focus_param.
+ start_angles[i] = soundFocusData.start_angle[i];
+ cvp_set_sound_focus_param_cmd.cvp_set_sound_focus_param.
+ enables[i] = soundFocusData.enable[i];
+ pr_debug("%s: start_angle[%d] = %d\n",
+ __func__, i, soundFocusData.start_angle[i]);
+ pr_debug("%s: enable[%d] = %d\n",
+ __func__, i, soundFocusData.enable[i]);
+ }
+ cvp_set_sound_focus_param_cmd.cvp_set_sound_focus_param.gain_step =
+ soundFocusData.gain_step;
+ pr_debug("%s: gain_step = %d\n", __func__, soundFocusData.gain_step);
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+
+ ret = apr_send_pkt(apr_cvp, (uint32_t *)&cvp_set_sound_focus_param_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error in sending APR command\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+ if (common.is_sound_focus_resp_success) {
+ ret = 0;
+ } else {
+ pr_err("%s: Error in setting sound focus params\n", __func__);
+
+ ret = -EINVAL;
+ }
+
+done:
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int voc_set_sound_focus(struct sound_focus_param soundFocusData)
+{
+ struct voice_data *v = NULL;
+ int ret = -EINVAL;
+ struct voice_session_itr itr;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ mutex_lock(&common.common_lock);
+ voice_itr_init(&itr, ALL_SESSION_VSID);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state) &&
+ (v->lch_mode != VOICE_LCH_START) &&
+ !v->disable_topology)
+ ret = voice_send_set_sound_focus_cmd(v,
+ soundFocusData);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session\n", __func__);
+
+ ret = -EINVAL;
+ break;
+ }
+ }
+ mutex_unlock(&common.common_lock);
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int voice_send_get_sound_focus_cmd(struct voice_data *v,
+ struct sound_focus_param *soundFocusData)
+{
+ struct apr_hdr cvp_get_sound_focus_param_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+ int i;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ if (!v) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* send APR command to retrieve Sound Focus Params */
+ cvp_get_sound_focus_param_cmd.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_get_sound_focus_param_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_get_sound_focus_param_cmd) - APR_HDR_SIZE);
+ cvp_get_sound_focus_param_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_get_sound_focus_param_cmd.dest_port = cvp_handle;
+ cvp_get_sound_focus_param_cmd.token = 0;
+ cvp_get_sound_focus_param_cmd.opcode = VSS_ISOUNDFOCUS_CMD_GET_SECTORS;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *)&cvp_get_sound_focus_param_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error in sending APR command\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+ if (common.is_sound_focus_resp_success) {
+ for (i = 0; i < MAX_SECTORS; i++) {
+ soundFocusData->start_angle[i] =
+ common.soundFocusResponse.start_angles[i];
+ soundFocusData->enable[i] =
+ common.soundFocusResponse.enables[i];
+ pr_debug("%s: start_angle[%d] = %d\n",
+ __func__, i, soundFocusData->start_angle[i]);
+ pr_debug("%s: enable[%d] = %d\n",
+ __func__, i, soundFocusData->enable[i]);
+ }
+ soundFocusData->gain_step = common.soundFocusResponse.gain_step;
+ pr_debug("%s: gain_step = %d\n", __func__,
+ soundFocusData->gain_step);
+
+ common.is_sound_focus_resp_success = false;
+ ret = 0;
+ } else {
+ pr_err("%s: Invalid payload received from CVD\n", __func__);
+
+ ret = -EINVAL;
+ }
+done:
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int voc_get_sound_focus(struct sound_focus_param *soundFocusData)
+{
+ struct voice_data *v = NULL;
+ int ret = -EINVAL;
+ struct voice_session_itr itr;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ mutex_lock(&common.common_lock);
+ voice_itr_init(&itr, ALL_SESSION_VSID);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v) {
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state) &&
+ (v->lch_mode != VOICE_LCH_START) &&
+ !v->disable_topology)
+ ret = voice_send_get_sound_focus_cmd(v,
+ soundFocusData);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session\n", __func__);
+
+ ret = -EINVAL;
+ break;
+ }
+ }
+ mutex_unlock(&common.common_lock);
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int is_source_tracking_shared_memomry_allocated(void)
+{
+ bool ret;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ if (common.source_tracking_sh_mem.sh_mem_block.client != NULL &&
+ common.source_tracking_sh_mem.sh_mem_block.handle != NULL)
+ ret = true;
+ else
+ ret = false;
+
+ pr_debug("%s: Exit\n", __func__);
+
+ return ret;
+}
+
+static int voice_alloc_source_tracking_shared_memory(void)
+{
+ int ret = 0;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ ret = msm_audio_ion_alloc("source_tracking_sh_mem_block",
+ &(common.source_tracking_sh_mem.sh_mem_block.client),
+ &(common.source_tracking_sh_mem.sh_mem_block.handle),
+ BUFFER_BLOCK_SIZE,
+ &(common.source_tracking_sh_mem.sh_mem_block.phys),
+ (size_t *)&(common.source_tracking_sh_mem.sh_mem_block.size),
+ &(common.source_tracking_sh_mem.sh_mem_block.data));
+ if (ret < 0) {
+ pr_err("%s: audio ION alloc failed for sh_mem block, ret = %d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ memset((void *)(common.source_tracking_sh_mem.sh_mem_block.data), 0,
+ common.source_tracking_sh_mem.sh_mem_block.size);
+
+ pr_debug("%s: sh_mem_block: phys:[%pK], data:[0x%pK], size:[%zd]\n",
+ __func__,
+ &(common.source_tracking_sh_mem.sh_mem_block.phys),
+ (void *)(common.source_tracking_sh_mem.sh_mem_block.data),
+ (size_t)(common.source_tracking_sh_mem.sh_mem_block.size));
+
+ ret = msm_audio_ion_alloc("source_tracking_sh_mem_table",
+ &(common.source_tracking_sh_mem.sh_mem_table.client),
+ &(common.source_tracking_sh_mem.sh_mem_table.handle),
+ sizeof(struct vss_imemory_table_t),
+ &(common.source_tracking_sh_mem.sh_mem_table.phys),
+ (size_t *)&(common.source_tracking_sh_mem.sh_mem_table.size),
+ &(common.source_tracking_sh_mem.sh_mem_table.data));
+ if (ret < 0) {
+ pr_err("%s: audio ION alloc failed for sh_mem table, ret = %d\n",
+ __func__, ret);
+
+ ret = msm_audio_ion_free(
+ common.source_tracking_sh_mem.sh_mem_block.client,
+ common.source_tracking_sh_mem.sh_mem_block.handle);
+ common.source_tracking_sh_mem.sh_mem_block.client = NULL;
+ common.source_tracking_sh_mem.sh_mem_block.handle = NULL;
+ if (ret < 0)
+ pr_err("%s: Error:%d freeing memory\n", __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ memset((void *)(common.source_tracking_sh_mem.sh_mem_table.data), 0,
+ common.source_tracking_sh_mem.sh_mem_table.size);
+
+ pr_debug("%s sh_mem_table: phys:[%pK], data:[0x%pK], size:[%zd],\n",
+ __func__,
+ &(common.source_tracking_sh_mem.sh_mem_table.phys),
+ (void *)(common.source_tracking_sh_mem.sh_mem_table.data),
+ (size_t)(common.source_tracking_sh_mem.sh_mem_table.size));
+
+done:
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int voice_alloc_and_map_source_tracking_shared_memory(
+ struct voice_data *v)
+{
+ int ret = 0;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ ret = voice_alloc_source_tracking_shared_memory();
+ if (ret) {
+ pr_err("%s: Failed to allocate shared memory %d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = voice_map_memory_physical_cmd(v,
+ &(common.source_tracking_sh_mem.sh_mem_table),
+ common.source_tracking_sh_mem.sh_mem_block.phys,
+ common.source_tracking_sh_mem.sh_mem_block.size,
+ VOC_SOURCE_TRACKING_MEM_MAP_TOKEN);
+ if (ret) {
+ pr_err("%s: memory mapping failed %d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+done:
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int voice_unmap_and_free_source_tracking_shared_memory(
+ struct voice_data *v)
+{
+ int ret = 0;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ if (common.source_tracking_sh_mem.mem_handle != 0) {
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ common.source_tracking_sh_mem.mem_handle);
+ if (ret < 0) {
+ pr_err("%s: Memory_unmap failed err %d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if ((common.source_tracking_sh_mem.sh_mem_block.client == NULL) ||
+ (common.source_tracking_sh_mem.sh_mem_block.handle == NULL))
+ goto done;
+
+ ret = msm_audio_ion_free(
+ common.source_tracking_sh_mem.sh_mem_block.client,
+ common.source_tracking_sh_mem.sh_mem_block.handle);
+ if (ret < 0) {
+ pr_err("%s: Error:%d freeing memory\n", __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+done:
+ common.source_tracking_sh_mem.mem_handle = 0;
+ common.source_tracking_sh_mem.sh_mem_block.client = NULL;
+ common.source_tracking_sh_mem.sh_mem_block.handle = NULL;
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int voice_send_get_source_tracking_cmd(struct voice_data *v,
+ struct source_tracking_param *sourceTrackingData)
+{
+ struct cvp_get_source_tracking_param_cmd_t st_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+ int i;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ if (!v) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+
+ if (!is_source_tracking_shared_memomry_allocated()) {
+ ret = voice_alloc_and_map_source_tracking_shared_memory(v);
+ if (ret) {
+ pr_err("%s: Fail in allocating/mapping shared memory\n",
+ __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ st_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ st_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(st_cmd) - APR_HDR_SIZE);
+ st_cmd.hdr.src_port = voice_get_idx_for_session(v->session_id);
+ st_cmd.hdr.dest_port = cvp_handle;
+ st_cmd.hdr.token = 0;
+ st_cmd.hdr.opcode = VSS_ISOURCETRACK_CMD_GET_ACTIVITY;
+
+ st_cmd.cvp_get_source_tracking_param.mem_handle =
+ common.source_tracking_sh_mem.mem_handle;
+ st_cmd.cvp_get_source_tracking_param.mem_address_lsw =
+ lower_32_bits(common.source_tracking_sh_mem.sh_mem_block.phys);
+ st_cmd.cvp_get_source_tracking_param.mem_address_msw =
+ msm_audio_populate_upper_32_bits(common.source_tracking_sh_mem.
+ sh_mem_block.phys);
+ st_cmd.cvp_get_source_tracking_param.mem_size =
+ (uint32_t)common.source_tracking_sh_mem.sh_mem_block.size;
+ pr_debug("%s: mem_handle=0x%x, mem_address_lsw=0x%x, msw=0x%x, mem_size=%d\n",
+ __func__,
+ st_cmd.cvp_get_source_tracking_param.mem_handle,
+ st_cmd.cvp_get_source_tracking_param.mem_address_lsw,
+ st_cmd.cvp_get_source_tracking_param.mem_address_msw,
+ (uint32_t)st_cmd.cvp_get_source_tracking_param.mem_size);
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp,
+ (uint32_t *) &st_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error in sending APR command\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto done;
+ }
+
+ if (common.is_source_tracking_resp_success) {
+ for (i = 0; i < MAX_SECTORS; i++) {
+ sourceTrackingData->vad[i] =
+ common.sourceTrackingResponse.voice_active[i];
+ pr_debug("%s: vad[%d] = %d\n",
+ __func__, i, sourceTrackingData->vad[i]);
+ }
+ sourceTrackingData->doa_speech =
+ common.sourceTrackingResponse.talker_doa;
+ pr_debug("%s: doa_speech = %d\n",
+ __func__, sourceTrackingData->doa_speech);
+
+ for (i = 0; i < MAX_NOISE_SOURCE_INDICATORS; i++) {
+ sourceTrackingData->doa_noise[i] =
+ common.sourceTrackingResponse.interferer_doa[i];
+ pr_debug("%s: doa_noise[%d] = %d\n",
+ __func__, i, sourceTrackingData->doa_noise[i]);
+ }
+ for (i = 0; i < MAX_POLAR_ACTIVITY_INDICATORS; i++) {
+ sourceTrackingData->polar_activity[i] =
+ common.sourceTrackingResponse.sound_strength[i];
+ pr_debug("%s: polar_activity[%d] = %d\n",
+ __func__, i, sourceTrackingData->polar_activity[i]);
+ }
+ common.is_source_tracking_resp_success = false;
+ ret = 0;
+ } else {
+ pr_err("%s: Error response received from CVD\n", __func__);
+
+ ret = -EINVAL;
+ }
+done:
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int voc_get_source_tracking(struct source_tracking_param *sourceTrackingData)
+{
+ struct voice_data *v = NULL;
+ int ret = -EINVAL;
+ struct voice_session_itr itr;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ mutex_lock(&common.common_lock);
+
+ voice_itr_init(&itr, ALL_SESSION_VSID);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state) &&
+ (v->lch_mode != VOICE_LCH_START) &&
+ !v->disable_topology)
+ ret = voice_send_get_source_tracking_cmd(v,
+ sourceTrackingData);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session\n", __func__);
+
+ break;
+ }
+ }
+
+ mutex_unlock(&common.common_lock);
+ pr_debug("%s: Exit, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int is_voc_initialized(void)
+{
+ return module_initialized;
+}
+
+static int __init voice_init(void)
+{
+ int rc = 0, i = 0;
+
+ memset(&common, 0, sizeof(struct common_data));
+
+ /* set default value */
+ common.default_mute_val = 0; /* default is un-mute */
+ common.default_sample_val = 8000;
+ common.default_vol_step_val = 0;
+ common.default_vol_ramp_duration_ms = DEFAULT_VOLUME_RAMP_DURATION;
+ common.default_mute_ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
+ common.ec_ref_ext = false;
+ /* Initialize MVS info. */
+ common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
+
+ /* Initialize is low memory flag */
+ common.is_destroy_cvd = false;
+
+ /* Initialize CVD version */
+ strlcpy(common.cvd_version, CVD_VERSION_DEFAULT,
+ sizeof(common.cvd_version));
+ /* Initialize Per-Vocoder Calibration flag */
+ common.is_per_vocoder_cal_enabled = false;
+
+ mutex_init(&common.common_lock);
+
+ /* Initialize session id with vsid */
+ init_session_id();
+
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+
+ /* initialize dev_rx and dev_tx */
+ common.voice[i].dev_rx.dev_mute = common.default_mute_val;
+ common.voice[i].dev_tx.dev_mute = common.default_mute_val;
+ common.voice[i].dev_rx.volume_step_value =
+ common.default_vol_step_val;
+ common.voice[i].dev_rx.volume_ramp_duration_ms =
+ common.default_vol_ramp_duration_ms;
+ common.voice[i].dev_rx.dev_mute_ramp_duration_ms =
+ common.default_mute_ramp_duration_ms;
+ common.voice[i].dev_tx.dev_mute_ramp_duration_ms =
+ common.default_mute_ramp_duration_ms;
+ common.voice[i].stream_rx.stream_mute = common.default_mute_val;
+ common.voice[i].stream_tx.stream_mute = common.default_mute_val;
+
+ common.voice[i].dev_tx.port_id = 0x100B;
+ common.voice[i].dev_rx.port_id = 0x100A;
+ common.voice[i].dev_tx.dev_id = 0;
+ common.voice[i].dev_rx.dev_id = 0;
+ common.voice[i].dev_rx.no_of_channels = 0;
+ common.voice[i].dev_tx.no_of_channels = 0;
+ common.voice[i].sidetone_gain = 0x512;
+ common.voice[i].dtmf_rx_detect_en = 0;
+ common.voice[i].lch_mode = 0;
+ common.voice[i].disable_topology = false;
+
+ common.voice[i].voc_state = VOC_INIT;
+
+ init_waitqueue_head(&common.voice[i].mvm_wait);
+ init_waitqueue_head(&common.voice[i].cvs_wait);
+ init_waitqueue_head(&common.voice[i].cvp_wait);
+
+ mutex_init(&common.voice[i].lock);
+ }
+
+ if (voice_init_cal_data())
+ pr_err("%s: Could not init cal data!\n", __func__);
+
+ if (rc == 0)
+ module_initialized = true;
+
+ pr_debug("%s: rc=%d\n", __func__, rc);
+ return rc;
+}
+
+device_initcall(voice_init);
+
+static void __exit voice_exit(void)
+{
+ voice_delete_cal_data();
+ free_cal_map_table();
+}
+
+__exitcall(voice_exit);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
new file mode 100644
index 0000000..f336a44
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -0,0 +1,1789 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QDSP6VOICE_H__
+#define __QDSP6VOICE_H__
+
+#include <linux/qdsp6v2/apr.h>
+#include <linux/qdsp6v2/rtac.h>
+#include <linux/msm_ion.h>
+#include <sound/voice_params.h>
+#include <linux/power_supply.h>
+
+#define MAX_VOC_PKT_SIZE 642
+#define SESSION_NAME_LEN 20
+#define NUM_OF_MEMORY_BLOCKS 1
+#define NUM_OF_BUFFERS 2
+/*
+ * BUFFER BLOCK SIZE based on
+ * the supported page size
+ */
+#define BUFFER_BLOCK_SIZE 4096
+
+#define MAX_COL_INFO_SIZE 324
+
+#define VOC_REC_UPLINK 0x00
+#define VOC_REC_DOWNLINK 0x01
+#define VOC_REC_BOTH 0x02
+
+#define VSS_IVERSION_CMD_GET 0x00011378
+#define VSS_IVERSION_RSP_GET 0x00011379
+#define CVD_VERSION_STRING_MAX_SIZE 31
+#define CVD_VERSION_DEFAULT ""
+#define CVD_VERSION_0_0 "0.0"
+#define CVD_VERSION_2_1 "2.1"
+#define CVD_VERSION_2_2 "2.2"
+#define CVD_VERSION_2_3 "2.3"
+
+#define CVD_INT_VERSION_DEFAULT 0
+#define CVD_INT_VERSION_0_0 1
+#define CVD_INT_VERSION_2_1 2
+#define CVD_INT_VERSION_2_2 3
+#define CVD_INT_VERSION_2_3 4
+#define CVD_INT_VERSION_LAST CVD_INT_VERSION_2_3
+#define CVD_INT_VERSION_MAX (CVD_INT_VERSION_LAST + 1)
+
+struct cvd_version_table {
+ char cvd_ver[CVD_VERSION_STRING_MAX_SIZE];
+ int cvd_ver_int;
+};
+
+int voc_get_cvd_version(char *cvd_version);
+
+/* Payload structure for the VSS_IVERSION_RSP_GET command response */
+struct vss_iversion_rsp_get_t {
+ char version[CVD_VERSION_STRING_MAX_SIZE];
+ /* NULL-terminated version string */
+};
+
+enum {
+ CVP_VOC_RX_TOPOLOGY_CAL = 0,
+ CVP_VOC_TX_TOPOLOGY_CAL,
+ CVP_VOCPROC_CAL,
+ CVP_VOCVOL_CAL,
+ CVP_VOCDEV_CFG_CAL,
+ CVP_VOCPROC_COL_CAL,
+ CVP_VOCVOL_COL_CAL,
+ CVS_VOCSTRM_CAL,
+ CVS_VOCSTRM_COL_CAL,
+ VOICE_RTAC_INFO_CAL,
+ VOICE_RTAC_APR_CAL,
+ MAX_VOICE_CAL_TYPES
+};
+
+struct voice_header {
+ uint32_t id;
+ uint32_t data_len;
+};
+
+struct voice_init {
+ struct voice_header hdr;
+ void *cb_handle;
+};
+
+/* Stream information payload structure */
+struct stream_data {
+ uint32_t stream_mute;
+ uint32_t stream_mute_ramp_duration_ms;
+};
+
+/* Device information payload structure */
+struct device_data {
+ uint32_t dev_mute;
+ uint32_t sample;
+ uint32_t enabled;
+ uint32_t dev_id;
+ uint32_t port_id;
+ uint32_t volume_step_value;
+ uint32_t volume_ramp_duration_ms;
+ uint32_t dev_mute_ramp_duration_ms;
+ uint32_t no_of_channels;
+};
+
+struct voice_dev_route_state {
+ u16 rx_route_flag;
+ u16 tx_route_flag;
+};
+
+struct voice_rec_route_state {
+ u16 ul_flag;
+ u16 dl_flag;
+};
+
+enum {
+ VOC_INIT = 0,
+ VOC_RUN,
+ VOC_CHANGE,
+ VOC_RELEASE,
+ VOC_ERROR,
+ VOC_STANDBY,
+};
+
+struct mem_buffer {
+ dma_addr_t phys;
+ void *data;
+ uint32_t size; /* size of buffer */
+};
+
+struct share_mem_buf {
+ struct ion_handle *handle;
+ struct ion_client *client;
+ struct mem_buffer buf[NUM_OF_BUFFERS];
+};
+
+struct mem_map_table {
+ dma_addr_t phys;
+ void *data;
+ size_t size; /* size of buffer */
+ struct ion_handle *handle;
+ struct ion_client *client;
+};
+
+/* Common */
+#define VSS_ICOMMON_CMD_SET_UI_PROPERTY 0x00011103
+/* Set a UI property */
+#define VSS_ICOMMON_CMD_MAP_MEMORY 0x00011025
+#define VSS_ICOMMON_CMD_UNMAP_MEMORY 0x00011026
+/* General shared memory; byte-accessible, 4 kB-aligned. */
+#define VSS_ICOMMON_MAP_MEMORY_SHMEM8_4K_POOL 3
+
+struct vss_icommon_cmd_map_memory_t {
+ uint32_t phys_addr;
+ /* Physical address of a memory region; must be at least
+ * 4 kB aligned.
+ */
+
+ uint32_t mem_size;
+ /* Number of bytes in the region; should be a multiple of 32. */
+
+ uint16_t mem_pool_id;
+ /* Type of memory being provided. The memory ID implicitly defines
+ * the characteristics of the memory. The characteristics might include
+ * alignment type, permissions, etc.
+ * Memory pool ID. Possible values:
+ * 3 -- VSS_ICOMMON_MEM_TYPE_SHMEM8_4K_POOL.
+ */
+} __packed;
+
+struct vss_icommon_cmd_unmap_memory_t {
+ uint32_t phys_addr;
+ /* Physical address of a memory region; must be at least
+ * 4 kB aligned.
+ */
+} __packed;
+
+struct vss_map_memory_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_map_memory_t vss_map_mem;
+} __packed;
+
+struct vss_unmap_memory_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_unmap_memory_t vss_unmap_mem;
+} __packed;
+
+/* TO MVM commands */
+#define VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x000110FF
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL 0x00011327
+/*
+ * VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL
+ * Description: This command is required to let MVM know
+ * who is in control of session.
+ * Payload: Defined by vss_imvm_cmd_set_policy_dual_control_t.
+ * Result: Wait for APRV2_IBASIC_RSP_RESULT response.
+ */
+
+#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110FE
+/* Create a new full control MVM session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_ATTACH_STREAM 0x0001123C
+/* Attach a stream to the MVM. */
+
+#define VSS_IMVM_CMD_DETACH_STREAM 0x0001123D
+/* Detach a stream from the MVM. */
+
+#define VSS_IMVM_CMD_ATTACH_VOCPROC 0x0001123E
+/* Attach a vocproc to the MVM. The MVM will symmetrically connect this vocproc
+ * to all the streams currently attached to it.
+ */
+
+#define VSS_IMVM_CMD_DETACH_VOCPROC 0x0001123F
+/* Detach a vocproc from the MVM. The MVM will symmetrically disconnect this
+ * vocproc from all the streams to which it is currently attached.
+ */
+
+#define VSS_IMVM_CMD_START_VOICE 0x00011190
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_STANDBY_VOICE 0x00011191
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_STOP_VOICE 0x00011192
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_PAUSE_VOICE 0x0001137D
+/* No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_ATTACH_VOCPROC 0x000110F8
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_DETACH_VOCPROC 0x000110F9
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+
+#define VSS_ISTREAM_CMD_SET_TTY_MODE 0x00011196
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ICOMMON_CMD_SET_NETWORK 0x0001119C
+/* Set the network type. */
+
+#define VSS_ICOMMON_CMD_SET_VOICE_TIMING 0x000111E0
+/* Set the voice timing parameters. */
+
+#define VSS_IMEMORY_CMD_MAP_PHYSICAL 0x00011334
+#define VSS_IMEMORY_RSP_MAP 0x00011336
+#define VSS_IMEMORY_CMD_UNMAP 0x00011337
+#define VSS_IMVM_CMD_SET_CAL_NETWORK 0x0001137A
+#define VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE 0x0001137B
+#define VSS_IHDVOICE_CMD_ENABLE 0x000130A2
+#define VSS_IHDVOICE_CMD_DISABLE 0x000130A3
+
+enum msm_audio_voc_rate {
+ VOC_0_RATE, /* Blank frame */
+ VOC_8_RATE, /* 1/8 rate */
+ VOC_4_RATE, /* 1/4 rate */
+ VOC_2_RATE, /* 1/2 rate */
+ VOC_1_RATE, /* Full rate */
+ VOC_8_RATE_NC /* Noncritical 1/8 rate */
+};
+
+struct vss_istream_cmd_set_tty_mode_t {
+ uint32_t mode;
+ /**<
+ * TTY mode.
+ *
+ * 0 : TTY disabled
+ * 1 : HCO
+ * 2 : VCO
+ * 3 : FULL
+ */
+} __packed;
+
+struct vss_istream_cmd_attach_vocproc_t {
+ uint16_t handle;
+ /**< Handle of vocproc being attached. */
+} __packed;
+
+struct vss_istream_cmd_detach_vocproc_t {
+ uint16_t handle;
+ /**< Handle of vocproc being detached. */
+} __packed;
+
+struct vss_imvm_cmd_attach_stream_t {
+ uint16_t handle;
+ /* The stream handle to attach. */
+} __packed;
+
+struct vss_imvm_cmd_detach_stream_t {
+ uint16_t handle;
+ /* The stream handle to detach. */
+} __packed;
+
+struct vss_icommon_cmd_set_network_t {
+ uint32_t network_id;
+ /* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+} __packed;
+
+struct vss_icommon_cmd_set_voice_timing_t {
+ uint16_t mode;
+ /*
+ * The vocoder frame synchronization mode.
+ *
+ * 0 : No frame sync.
+ * 1 : Hard VFR (20ms Vocoder Frame Reference interrupt).
+ */
+ uint16_t enc_offset;
+ /*
+ * The offset in microseconds from the VFR to deliver a Tx vocoder
+ * packet. The offset should be less than 20000us.
+ */
+ uint16_t dec_req_offset;
+ /*
+ * The offset in microseconds from the VFR to request for an Rx vocoder
+ * packet. The offset should be less than 20000us.
+ */
+ uint16_t dec_offset;
+ /*
+ * The offset in microseconds from the VFR to indicate the deadline to
+ * receive an Rx vocoder packet. The offset should be less than 20000us.
+ * Rx vocoder packets received after this deadline are not guaranteed to
+ * be processed.
+ */
+} __packed;
+
+struct vss_imvm_cmd_create_control_session_t {
+ char name[SESSION_NAME_LEN];
+ /*
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __packed;
+
+
+struct vss_imvm_cmd_set_policy_dual_control_t {
+ bool enable_flag;
+ /* Set to TRUE to enable modem state machine control */
+} __packed;
+
+struct mvm_attach_vocproc_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_attach_vocproc_t mvm_attach_cvp_handle;
+} __packed;
+
+struct mvm_detach_vocproc_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_detach_vocproc_t mvm_detach_cvp_handle;
+} __packed;
+
+struct mvm_create_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_create_control_session_t mvm_session;
+} __packed;
+
+struct mvm_modem_dual_control_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_set_policy_dual_control_t voice_ctl;
+} __packed;
+
+struct mvm_set_tty_mode_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_tty_mode_t tty_mode;
+} __packed;
+
+struct mvm_attach_stream_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_attach_stream_t attach_stream;
+} __packed;
+
+struct mvm_detach_stream_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_detach_stream_t detach_stream;
+} __packed;
+
+struct mvm_set_network_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_network_t network;
+} __packed;
+
+struct mvm_set_voice_timing_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_voice_timing_t timing;
+} __packed;
+
+struct mvm_set_hd_enable_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct vss_imemory_table_descriptor_t {
+ uint32_t mem_address_lsw;
+ uint32_t mem_address_msw;
+ /*
+ * Base physical address of the table. The address must be aligned
+ * to LCM( cache_line_size, page_align, max_data_width ), where the
+ * attributes are specified in #VSS_IMEMORY_CMD_MAP_PHYSICAL, and
+ * LCM = Least Common Multiple. The table at the address must have
+ * the format specified by #vss_imemory_table_t.
+ */
+ uint32_t mem_size;
+ /* Size in bytes of the table. */
+} __packed;
+
+struct vss_imemory_block_t {
+ uint64_t mem_address;
+ /*
+ * Base address of the memory block. The address is virtual for virtual
+ * memory and physical for physical memory. The address must be aligned
+ * to LCM( cache_line_size, page_align, max_data_width ), where the
+ * attributes are specified in VSS_IMEMORY_CMD_MAP_VIRTUAL or
+ * VSS_IMEMORY_CMD_MAP_PHYSICAL, and LCM = Least Common Multiple.
+ */
+ uint32_t mem_size;
+ /*
+ * Size in bytes of the memory block. The size must be multiple of
+ * page_align, where page_align is specified in
+ * VSS_IMEMORY_CMD_MAP_VIRTUAL or #VSS_IMEMORY_CMD_MAP_PHYSICAL.
+ */
+} __packed;
+
+struct vss_imemory_table_t {
+ struct vss_imemory_table_descriptor_t next_table_descriptor;
+ /*
+ * Specifies the next table. If there is no next table,
+ * set the size of the table to 0 and the table address is ignored.
+ */
+ struct vss_imemory_block_t blocks[NUM_OF_MEMORY_BLOCKS];
+ /* Specifies one ore more memory blocks. */
+} __packed;
+
+struct vss_imemory_cmd_map_physical_t {
+ struct apr_hdr hdr;
+ struct vss_imemory_table_descriptor_t table_descriptor;
+ bool is_cached;
+ /*
+ * Indicates cached or uncached memory. Supported values:
+ * TRUE - Cached.
+ */
+ uint16_t cache_line_size;
+ /* Cache line size in bytes. Supported values: 128 */
+ uint32_t access_mask;
+ /*
+ * CVD's access permission to the memory while it is mapped.
+ * Supported values:
+ * bit 0 - If set, the memory is readable.
+ * bit 1 - If set, the memory is writable.
+ */
+ uint32_t page_align;
+ /* Page frame alignment in bytes. Supported values: 4096 */
+ uint8_t min_data_width;
+ /*
+ * Minimum native data type width in bits that can be accessed.
+ * Supported values: 8
+ */
+ uint8_t max_data_width;
+ /*
+ * Maximum native data type width in bits that can be accessed.
+ * Supported values: 64
+ */
+} __packed;
+
+struct vss_imvm_cmd_set_cal_network_t {
+ struct apr_hdr hdr;
+ uint32_t network_id;
+} __packed;
+
+struct vss_imvm_cmd_set_cal_media_type_t {
+ struct apr_hdr hdr;
+ uint32_t media_id;
+} __packed;
+
+struct vss_imemory_cmd_unmap_t {
+ struct apr_hdr hdr;
+ uint32_t mem_handle;
+} __packed;
+
+/* TO CVS commands */
+#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x00011140
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110F7
+/* Create a new full control stream session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+
+/*
+ * This command changes the mute setting. The new mute setting will
+ * be applied over the specified ramp duration.
+ */
+#define VSS_IVOLUME_CMD_MUTE_V2 0x0001138B
+
+#define VSS_ISTREAM_CMD_REGISTER_CALIBRATION_DATA_V2 0x00011369
+
+#define VSS_ISTREAM_CMD_DEREGISTER_CALIBRATION_DATA 0x0001127A
+
+#define VSS_ISTREAM_CMD_REGISTER_STATIC_CALIBRATION_DATA 0x0001307D
+#define VSS_ISTREAM_CMD_DEREGISTER_STATIC_CALIBRATION_DATA 0x0001307E
+
+#define VSS_ISTREAM_CMD_SET_MEDIA_TYPE 0x00011186
+/* Set media type on the stream. */
+
+#define VSS_ISTREAM_EVT_SEND_ENC_BUFFER 0x00011015
+/* Event sent by the stream to its client to provide an encoded packet. */
+
+#define VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER 0x00011017
+/* Event sent by the stream to its client requesting for a decoder packet.
+ * The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
+ */
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_REQUEST 0x0001136E
+
+#define VSS_ISTREAM_EVT_SEND_DEC_BUFFER 0x00011016
+/* Event sent by the client to the stream in response to a
+ * VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
+ */
+
+#define VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE 0x0001113E
+/* Set AMR encoder rate. */
+
+#define VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE 0x0001113F
+/* Set AMR-WB encoder rate. */
+
+#define VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE 0x00011019
+/* Set encoder minimum and maximum rate. */
+
+#define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE 0x0001101D
+/* Set encoder DTX mode. */
+
+#define MODULE_ID_VOICE_MODULE_ST 0x00010EE3
+#define VOICE_PARAM_MOD_ENABLE 0x00010E00
+#define MOD_ENABLE_PARAM_LEN 4
+
+#define VSS_IPLAYBACK_CMD_START 0x000112BD
+/* Start in-call music delivery on the Tx voice path. */
+
+#define VSS_IPLAYBACK_CMD_STOP 0x00011239
+/* Stop the in-call music delivery on the Tx voice path. */
+
+#define VSS_IPLAYBACK_PORT_ID_DEFAULT 0x0000FFFF
+/* Default AFE port ID. */
+
+#define VSS_IPLAYBACK_PORT_ID_VOICE 0x00008005
+/* AFE port ID for VOICE 1. */
+
+#define VSS_IPLAYBACK_PORT_ID_VOICE2 0x00008002
+/* AFE port ID for VOICE 2. */
+
+#define VSS_IRECORD_CMD_START 0x000112BE
+/* Start in-call conversation recording. */
+#define VSS_IRECORD_CMD_STOP 0x00011237
+/* Stop in-call conversation recording. */
+
+#define VSS_IRECORD_PORT_ID_DEFAULT 0x0000FFFF
+/* Default AFE port ID. */
+
+#define VSS_IRECORD_TAP_POINT_NONE 0x00010F78
+/* Indicates no tapping for specified path. */
+
+#define VSS_IRECORD_TAP_POINT_STREAM_END 0x00010F79
+/* Indicates that specified path should be tapped at the end of the stream. */
+
+#define VSS_IRECORD_MODE_TX_RX_STEREO 0x00010F7A
+/* Select Tx on left channel and Rx on right channel. */
+
+#define VSS_IRECORD_MODE_TX_RX_MIXING 0x00010F7B
+/* Select mixed Tx and Rx paths. */
+
+#define VSS_ISTREAM_EVT_NOT_READY 0x000110FD
+
+#define VSS_ISTREAM_EVT_READY 0x000110FC
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_READY 0x0001136F
+/*notify dsp that decoder buffer is ready*/
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY 0x0001136C
+/*dsp notifying client that encoder buffer is ready*/
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED 0x0001136D
+/*notify dsp that encoder buffer is consumed*/
+
+#define VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG 0x0001136B
+
+#define VSS_ISTREAM_PACKET_EXCHANGE_MODE_INBAND 0
+/* In-band packet exchange mode. */
+
+#define VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND 1
+/* Out-of-band packet exchange mode. */
+
+#define VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE 0x0001136A
+
+struct vss_iplayback_cmd_start_t {
+ uint16_t port_id;
+ /*
+ * AFE Port ID from which the audio samples are available.
+ * To use the default AFE pseudo port (0x8005), set this value to
+ * #VSS_IPLAYBACK_PORT_ID_DEFAULT.
+ */
+} __packed;
+
+struct vss_irecord_cmd_start_t {
+ uint32_t rx_tap_point;
+ /* Tap point to use on the Rx path. Supported values are:
+ * VSS_IRECORD_TAP_POINT_NONE : Do not record Rx path.
+ * VSS_IRECORD_TAP_POINT_STREAM_END : Rx tap point is at the end of
+ * the stream.
+ */
+ uint32_t tx_tap_point;
+ /* Tap point to use on the Tx path. Supported values are:
+ * VSS_IRECORD_TAP_POINT_NONE : Do not record tx path.
+ * VSS_IRECORD_TAP_POINT_STREAM_END : Tx tap point is at the end of
+ * the stream.
+ */
+ uint16_t port_id;
+ /* AFE Port ID to which the conversation recording stream needs to be
+ * sent. Set this to #VSS_IRECORD_PORT_ID_DEFAULT to use default AFE
+ * pseudo ports (0x8003 for Rx and 0x8004 for Tx).
+ */
+ uint32_t mode;
+ /* Recording Mode. The mode parameter value is ignored if the port_id
+ * is set to #VSS_IRECORD_PORT_ID_DEFAULT.
+ * The supported values:
+ * #VSS_IRECORD_MODE_TX_RX_STEREO
+ * #VSS_IRECORD_MODE_TX_RX_MIXING
+ */
+} __packed;
+
+struct vss_istream_cmd_create_passive_control_session_t {
+ char name[SESSION_NAME_LEN];
+ /**<
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __packed;
+
+#define VSS_IVOLUME_DIRECTION_TX 0
+#define VSS_IVOLUME_DIRECTION_RX 1
+
+#define VSS_IVOLUME_MUTE_OFF 0
+#define VSS_IVOLUME_MUTE_ON 1
+
+#define DEFAULT_MUTE_RAMP_DURATION 500
+#define DEFAULT_VOLUME_RAMP_DURATION 20
+#define MAX_RAMP_DURATION 5000
+
+struct vss_ivolume_cmd_mute_v2_t {
+ uint16_t direction;
+ /*
+ * The direction field sets the direction to apply the mute command.
+ * The Supported values:
+ * VSS_IVOLUME_DIRECTION_TX
+ * VSS_IVOLUME_DIRECTION_RX
+ */
+ uint16_t mute_flag;
+ /*
+ * Turn mute on or off. The Supported values:
+ * VSS_IVOLUME_MUTE_OFF
+ * VSS_IVOLUME_MUTE_ON
+ */
+ uint16_t ramp_duration_ms;
+ /*
+ * Mute change ramp duration in milliseconds.
+ * The Supported values: 0 to 5000.
+ */
+} __packed;
+
+struct vss_istream_cmd_create_full_control_session_t {
+ uint16_t direction;
+ /*
+ * Stream direction.
+ *
+ * 0 : TX only
+ * 1 : RX only
+ * 2 : TX and RX
+ * 3 : TX and RX loopback
+ */
+ uint32_t enc_media_type;
+ /* Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t dec_media_type;
+ /* Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t network_id;
+ /* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+ char name[SESSION_NAME_LEN];
+ /*
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __packed;
+
+struct vss_istream_cmd_set_media_type_t {
+ uint32_t rx_media_id;
+ /* Set the Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t tx_media_id;
+ /* Set the Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+} __packed;
+
+struct vss_istream_evt_send_enc_buffer_t {
+ uint32_t media_id;
+ /* Media ID of the packet. */
+ uint8_t packet_data[MAX_VOC_PKT_SIZE];
+ /* Packet data buffer. */
+} __packed;
+
+struct vss_istream_evt_send_dec_buffer_t {
+ uint32_t media_id;
+ /* Media ID of the packet. */
+ uint8_t packet_data[MAX_VOC_PKT_SIZE];
+ /* Packet data. */
+} __packed;
+
+struct vss_istream_cmd_voc_amr_set_enc_rate_t {
+ uint32_t mode;
+ /* Set the AMR encoder rate.
+ *
+ * 0x00000000 : 4.75 kbps
+ * 0x00000001 : 5.15 kbps
+ * 0x00000002 : 5.90 kbps
+ * 0x00000003 : 6.70 kbps
+ * 0x00000004 : 7.40 kbps
+ * 0x00000005 : 7.95 kbps
+ * 0x00000006 : 10.2 kbps
+ * 0x00000007 : 12.2 kbps
+ */
+} __packed;
+
+struct vss_istream_cmd_voc_amrwb_set_enc_rate_t {
+ uint32_t mode;
+ /* Set the AMR-WB encoder rate.
+ *
+ * 0x00000000 : 6.60 kbps
+ * 0x00000001 : 8.85 kbps
+ * 0x00000002 : 12.65 kbps
+ * 0x00000003 : 14.25 kbps
+ * 0x00000004 : 15.85 kbps
+ * 0x00000005 : 18.25 kbps
+ * 0x00000006 : 19.85 kbps
+ * 0x00000007 : 23.05 kbps
+ * 0x00000008 : 23.85 kbps
+ */
+} __packed;
+
+struct vss_istream_cmd_cdma_set_enc_minmax_rate_t {
+ uint16_t min_rate;
+ /* Set the lower bound encoder rate.
+ *
+ * 0x0000 : Blank frame
+ * 0x0001 : Eighth rate
+ * 0x0002 : Quarter rate
+ * 0x0003 : Half rate
+ * 0x0004 : Full rate
+ */
+ uint16_t max_rate;
+ /* Set the upper bound encoder rate.
+ *
+ * 0x0000 : Blank frame
+ * 0x0001 : Eighth rate
+ * 0x0002 : Quarter rate
+ * 0x0003 : Half rate
+ * 0x0004 : Full rate
+ */
+} __packed;
+
+struct vss_istream_cmd_set_enc_dtx_mode_t {
+ uint32_t enable;
+ /* Toggle DTX on or off.
+ *
+ * 0 : Disables DTX
+ * 1 : Enables DTX
+ */
+} __packed;
+
+struct vss_istream_cmd_register_calibration_data_v2_t {
+ uint32_t cal_mem_handle;
+ /* Handle to the shared memory that holds the calibration data. */
+ uint32_t cal_mem_address_lsw;
+ uint32_t cal_mem_address_msw;
+ /* Location of calibration data. */
+ uint32_t cal_mem_size;
+ /* Size of the calibration data in bytes. */
+ uint8_t column_info[MAX_COL_INFO_SIZE];
+ /*
+ * Column info contains the number of columns and the array of columns
+ * in the calibration table. The order in which the columns are provided
+ * here must match the order in which they exist in the calibration
+ * table provided.
+ */
+} __packed;
+
+struct vss_icommon_cmd_set_ui_property_enable_t {
+ uint32_t module_id;
+ /* Unique ID of the module. */
+ uint32_t param_id;
+ /* Unique ID of the parameter. */
+ uint16_t param_size;
+ /* Size of the parameter in bytes: MOD_ENABLE_PARAM_LEN */
+ uint16_t reserved;
+ /* Reserved; set to 0. */
+ uint16_t enable;
+ uint16_t reserved_field;
+ /* Reserved, set to 0. */
+};
+
+/*
+ * Event sent by the stream to the client that enables Rx DTMF
+ * detection whenever DTMF is detected in the Rx path.
+ *
+ * The DTMF detection feature can only be used to detect DTMF
+ * frequencies as listed in the vss_istream_evt_rx_dtmf_detected_t
+ * structure.
+ */
+
+#define VSS_ISTREAM_EVT_RX_DTMF_DETECTED 0x0001101A
+
+struct vss_istream_cmd_set_rx_dtmf_detection {
+ /*
+ * Enables/disables Rx DTMF detection
+ *
+ * Possible values are
+ * 0 - disable
+ * 1 - enable
+ *
+ */
+ uint32_t enable;
+};
+
+#define VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION 0x00011027
+
+struct vss_istream_evt_rx_dtmf_detected {
+ uint16_t low_freq;
+ /*
+ * Detected low frequency. Possible values:
+ * 697 Hz
+ * 770 Hz
+ * 852 Hz
+ * 941 Hz
+ */
+ uint16_t high_freq;
+ /*
+ * Detected high frequency. Possible values:
+ * 1209 Hz
+ * 1336 Hz
+ * 1477 Hz
+ * 1633 Hz
+ */
+};
+
+struct cvs_set_rx_dtmf_detection_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_rx_dtmf_detection cvs_dtmf_det;
+} __packed;
+
+
+struct cvs_create_passive_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_create_passive_control_session_t cvs_session;
+} __packed;
+
+struct cvs_create_full_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_create_full_control_session_t cvs_session;
+} __packed;
+
+struct cvs_destroy_session_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvs_set_mute_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivolume_cmd_mute_v2_t cvs_set_mute;
+} __packed;
+
+struct cvs_set_media_type_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_media_type_t media_type;
+} __packed;
+
+struct cvs_send_dec_buf_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_evt_send_dec_buffer_t dec_buf;
+} __packed;
+
+struct cvs_set_amr_enc_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_voc_amr_set_enc_rate_t amr_rate;
+} __packed;
+
+struct cvs_set_amrwb_enc_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_voc_amrwb_set_enc_rate_t amrwb_rate;
+} __packed;
+
+struct cvs_set_cdma_enc_minmax_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_cdma_set_enc_minmax_rate_t cdma_rate;
+} __packed;
+
+struct cvs_set_enc_dtx_mode_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_enc_dtx_mode_t dtx_mode;
+} __packed;
+
+struct cvs_register_cal_data_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_register_calibration_data_v2_t cvs_cal_data;
+} __packed;
+
+struct cvs_deregister_cal_data_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvs_set_pp_enable_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_ui_property_enable_t vss_set_pp;
+} __packed;
+struct cvs_start_record_cmd {
+ struct apr_hdr hdr;
+ struct vss_irecord_cmd_start_t rec_mode;
+} __packed;
+
+struct cvs_start_playback_cmd {
+ struct apr_hdr hdr;
+ struct vss_iplayback_cmd_start_t playback_mode;
+} __packed;
+
+struct cvs_dec_buffer_ready_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvs_enc_buffer_consumed_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct vss_istream_cmd_set_oob_packet_exchange_config_t {
+ struct apr_hdr hdr;
+ uint32_t mem_handle;
+ uint32_t enc_buf_addr_lsw;
+ uint32_t enc_buf_addr_msw;
+ uint32_t enc_buf_size;
+ uint32_t dec_buf_addr_lsw;
+ uint32_t dec_buf_addr_msw;
+ uint32_t dec_buf_size;
+} __packed;
+
+struct vss_istream_cmd_set_packet_exchange_mode_t {
+ struct apr_hdr hdr;
+ uint32_t mode;
+} __packed;
+
+/* TO CVP commands */
+
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION 0x000100C3
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+
+#define VSS_IVOCPROC_CMD_SET_DEVICE_V2 0x000112C6
+
+#define VSS_IVOCPROC_CMD_SET_DEVICE_V3 0x0001316A
+
+#define VSS_IVOCPROC_CMD_TOPOLOGY_SET_DEV_CHANNELS 0x00013199
+
+#define VSS_IVOCPROC_CMD_TOPOLOGY_COMMIT 0x00013198
+
+#define VSS_IVOCPROC_CMD_SET_VP3_DATA 0x000110EB
+
+#define VSS_IVOLUME_CMD_SET_STEP 0x000112C2
+
+#define VSS_IVOCPROC_CMD_ENABLE 0x000100C6
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_CMD_DISABLE 0x000110E1
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+/*
+ * Registers the memory that contains device specific configuration data with
+ * the vocproc. The client must register device configuration data with the
+ * vocproc that corresponds with the device being set on the vocproc.
+ */
+#define VSS_IVOCPROC_CMD_REGISTER_DEVICE_CONFIG 0x00011371
+
+/*
+ * Deregisters the memory that holds device configuration data from the
+ vocproc.
+*/
+#define VSS_IVOCPROC_CMD_DEREGISTER_DEVICE_CONFIG 0x00011372
+
+#define VSS_IVOCPROC_CMD_REGISTER_CALIBRATION_DATA_V2 0x00011373
+#define VSS_IVOCPROC_CMD_DEREGISTER_CALIBRATION_DATA 0x00011276
+
+#define VSS_IVOCPROC_CMD_REGISTER_VOL_CALIBRATION_DATA 0x00011374
+#define VSS_IVOCPROC_CMD_DEREGISTER_VOL_CALIBRATION_DATA 0x00011375
+
+#define VSS_IVOCPROC_CMD_REGISTER_STATIC_CALIBRATION_DATA 0x00013079
+#define VSS_IVOCPROC_CMD_DEREGISTER_STATIC_CALIBRATION_DATA 0x0001307A
+
+#define VSS_IVOCPROC_CMD_REGISTER_DYNAMIC_CALIBRATION_DATA 0x0001307B
+#define VSS_IVOCPROC_CMD_DEREGISTER_DYNAMIC_CALIBRATION_DATA 0x0001307C
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_NONE 0x00010F70
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS 0x00010F71
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE 0x00010F72
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT 0x00010F77
+
+/* Newtwork IDs */
+#define VSS_ICOMMON_CAL_NETWORK_ID_NONE 0x0001135E
+
+/* Select internal mixing mode. */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING 0x00010F7C
+
+/* Select external mixing mode. */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING 0x00010F7D
+
+/* Default AFE port ID. Applicable to Tx and Rx. */
+#define VSS_IVOCPROC_PORT_ID_NONE 0xFFFF
+
+#define VSS_NETWORK_ID_DEFAULT 0x00010037
+
+/* Voice over Internet Protocol (VoIP) network ID. Common for all bands.*/
+#define VSS_NETWORK_ID_VOIP 0x00011362
+
+/* Media types */
+#define VSS_MEDIA_ID_EVRC_MODEM 0x00010FC2
+/* 80-VF690-47 CDMA enhanced variable rate vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_NB_MODEM 0x00010FC6
+/* 80-VF690-47 UMTS AMR-NB vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_WB_MODEM 0x00010FC7
+/* 80-VF690-47 UMTS AMR-WB vocoder modem format. */
+
+#define VSS_MEDIA_ID_PCM_8_KHZ 0x00010FCB
+#define VSS_MEDIA_ID_PCM_16_KHZ 0x00010FCC
+#define VSS_MEDIA_ID_PCM_32_KHZ 0x00010FD9
+#define VSS_MEDIA_ID_PCM_48_KHZ 0x00010FD6
+
+/* Linear PCM (16-bit, little-endian). */
+#define VSS_MEDIA_ID_G711_ALAW 0x00010FCD
+/* G.711 a-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G711_MULAW 0x00010FCE
+/* G.711 mu-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G729 0x00010FD0
+/* G.729AB (contains two 10ms vocoder frames. */
+#define VSS_MEDIA_ID_4GV_NB_MODEM 0x00010FC3
+/*CDMA EVRC-B vocoder modem format */
+#define VSS_MEDIA_ID_4GV_WB_MODEM 0x00010FC4
+/*CDMA EVRC-WB vocoder modem format */
+#define VSS_MEDIA_ID_4GV_NW_MODEM 0x00010FC5
+/*CDMA EVRC-NW vocoder modem format */
+
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2 0x000112BF
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V3 0x00013169
+
+#define VSS_NUM_DEV_CHANNELS_1 1
+#define VSS_NUM_DEV_CHANNELS_2 2
+#define VSS_NUM_DEV_CHANNELS_3 3
+#define VSS_NUM_DEV_CHANNELS_4 4
+
+struct vss_ivocproc_cmd_create_full_control_session_v2_t {
+ uint16_t direction;
+ /*
+ * Vocproc direction. The supported values:
+ * VSS_IVOCPROC_DIRECTION_RX
+ * VSS_IVOCPROC_DIRECTION_TX
+ * VSS_IVOCPROC_DIRECTION_RX_TX
+ */
+ uint16_t tx_port_id;
+ /*
+ * Tx device port ID to which the vocproc connects. If a port ID is
+ * not being supplied, set this to #VSS_IVOCPROC_PORT_ID_NONE.
+ */
+ uint32_t tx_topology_id;
+ /*
+ * Tx path topology ID. If a topology ID is not being supplied, set
+ * this to #VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ */
+ uint16_t rx_port_id;
+ /*
+ * Rx device port ID to which the vocproc connects. If a port ID is
+ * not being supplied, set this to #VSS_IVOCPROC_PORT_ID_NONE.
+ */
+ uint32_t rx_topology_id;
+ /*
+ * Rx path topology ID. If a topology ID is not being supplied, set
+ * this to #VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ */
+ uint32_t profile_id;
+ /* Voice calibration profile ID. */
+ uint32_t vocproc_mode;
+ /*
+ * Vocproc mode. The supported values:
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING
+ */
+ uint16_t ec_ref_port_id;
+ /*
+ * Port ID to which the vocproc connects for receiving echo
+ * cancellation reference signal. If a port ID is not being supplied,
+ * set this to #VSS_IVOCPROC_PORT_ID_NONE. This parameter value is
+ * ignored when the vocproc_mode parameter is set to
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING.
+ */
+ char name[SESSION_NAME_LEN];
+ /*
+ * Session name string used to identify a session that can be shared
+ * with passive controllers (optional). The string size, including the
+ * NULL termination character, is limited to 31 characters.
+ */
+} __packed;
+
+struct vss_ivocproc_cmd_set_volume_index_t {
+ uint16_t vol_index;
+ /*
+ * Volume index utilized by the vocproc to index into the volume table
+ * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+ * volume on the VDSP.
+ */
+} __packed;
+
+struct vss_ivolume_cmd_set_step_t {
+ uint16_t direction;
+ /*
+ * The direction field sets the direction to apply the volume command.
+ * The supported values:
+ * #VSS_IVOLUME_DIRECTION_RX
+ */
+ uint32_t value;
+ /*
+ * Volume step used to find the corresponding linear volume and
+ * the best match index in the registered volume calibration table.
+ */
+ uint16_t ramp_duration_ms;
+ /*
+ * Volume change ramp duration in milliseconds.
+ * The supported values: 0 to 5000.
+ */
+} __packed;
+
+struct vss_ivocproc_cmd_set_device_v2_t {
+ uint16_t tx_port_id;
+ /*
+ * TX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
+ uint32_t tx_topology_id;
+ /*
+ * TX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
+ uint16_t rx_port_id;
+ /*
+ * RX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
+ uint32_t rx_topology_id;
+ /*
+ * RX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
+ uint32_t vocproc_mode;
+ /* Vocproc mode. The supported values:
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING - 0x00010F7C
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING - 0x00010F7D
+ */
+ uint16_t ec_ref_port_id;
+ /* Port ID to which the vocproc connects for receiving
+ * echo
+ */
+} __packed;
+
+struct vss_ivocproc_cmd_register_device_config_t {
+ uint32_t mem_handle;
+ /*
+ * Handle to the shared memory that holds the per-network calibration
+ * data.
+ */
+ uint32_t mem_address_lsw;
+ uint32_t mem_address_msw;
+ /* Location of calibration data. */
+ uint32_t mem_size;
+ /* Size of the calibration data in bytes. */
+} __packed;
+
+struct vss_ivocproc_cmd_register_calibration_data_v2_t {
+ uint32_t cal_mem_handle;
+ /*
+ * Handle to the shared memory that holds the per-network calibration
+ * data.
+ */
+ uint32_t cal_mem_address_lsw;
+ uint32_t cal_mem_address_msw;
+ /* Location of calibration data. */
+ uint32_t cal_mem_size;
+ /* Size of the calibration data in bytes. */
+ uint8_t column_info[MAX_COL_INFO_SIZE];
+ /*
+ * Column info contains the number of columns and the array of columns
+ * in the calibration table. The order in which the columns are provided
+ * here must match the order in which they exist in the calibration
+ * table provided.
+ */
+} __packed;
+
+struct vss_ivocproc_cmd_register_volume_cal_data_t {
+ uint32_t cal_mem_handle;
+ /*
+ * Handle to the shared memory that holds the volume calibration
+ * data.
+ */
+ uint32_t cal_mem_address_lsw;
+ uint32_t cal_mem_address_msw;
+ /* Location of volume calibration data. */
+ uint32_t cal_mem_size;
+ /* Size of the volume calibration data in bytes. */
+ uint8_t column_info[MAX_COL_INFO_SIZE];
+ /*
+ * Column info contains the number of columns and the array of columns
+ * in the calibration table. The order in which the columns are provided
+ * here must match the order in which they exist in the calibration
+ * table provided.
+ */
+} __packed;
+
+struct vss_ivocproc_cmd_topology_set_dev_channels_t {
+ uint16_t tx_num_channels;
+ /*
+ * Number of Mics.
+ * Supported values
+ * 1 VSS_NUM_DEV_CHANNELS_1
+ * 2 VSS_NUM_DEV_CHANNELS_2
+ * 3 VSS_NUM_DEV_CHANNELS_3
+ * 4 VSS_NUM_DEV_CHANNELS_4
+ */
+ uint16_t rx_num_channels;
+ /*
+ * Number of speaker channels.
+ * Supported values
+ * 1 VSS_NUM_DEV_CHANNELS_1
+ */
+} __packed;
+
+/* Starts a vocoder PCM session */
+#define VSS_IVPCM_CMD_START_V2 0x00011339
+
+/* Default tap point location on the TX path. */
+#define VSS_IVPCM_TAP_POINT_TX_DEFAULT 0x00011289
+
+/* Default tap point location on the RX path. */
+#define VSS_IVPCM_TAP_POINT_RX_DEFAULT 0x0001128A
+
+/* Indicates tap point direction is output. */
+#define VSS_IVPCM_TAP_POINT_DIR_OUT 0
+
+/* Indicates tap point direction is input. */
+#define VSS_IVPCM_TAP_POINT_DIR_IN 1
+
+/* Indicates tap point direction is output and input. */
+#define VSS_IVPCM_TAP_POINT_DIR_OUT_IN 2
+
+
+#define VSS_IVPCM_SAMPLING_RATE_AUTO 0
+
+/* Indicates 8 KHz vocoder PCM sampling rate. */
+#define VSS_IVPCM_SAMPLING_RATE_8K 8000
+
+/* Indicates 16 KHz vocoder PCM sampling rate. */
+#define VSS_IVPCM_SAMPLING_RATE_16K 16000
+
+/* RX and TX */
+#define MAX_TAP_POINTS_SUPPORTED 2
+
+struct vss_ivpcm_tap_point {
+ uint32_t tap_point;
+ uint16_t direction;
+ uint16_t sampling_rate;
+ uint16_t duration;
+} __packed;
+
+
+struct vss_ivpcm_cmd_start_v2_t {
+ uint32_t mem_handle;
+ uint32_t num_tap_points;
+ struct vss_ivpcm_tap_point tap_points[MAX_TAP_POINTS_SUPPORTED];
+} __packed;
+
+#define VSS_IVPCM_EVT_PUSH_BUFFER_V2 0x0001133A
+
+/* Push buffer event mask indicating output buffer is filled. */
+#define VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER 1
+
+/* Push buffer event mask indicating input buffer is consumed. */
+#define VSS_IVPCM_PUSH_BUFFER_MASK_INPUT_BUFFER 2
+
+
+struct vss_ivpcm_evt_push_buffer_v2_t {
+ uint32_t tap_point;
+ uint32_t push_buf_mask;
+ uint64_t out_buf_mem_address;
+ uint16_t out_buf_mem_size;
+ uint64_t in_buf_mem_address;
+ uint16_t in_buf_mem_size;
+ uint16_t sampling_rate;
+ uint16_t num_in_channels;
+} __packed;
+
+#define VSS_IVPCM_EVT_NOTIFY_V2 0x0001133B
+
+/* Notify event mask indicates output buffer is filled. */
+#define VSS_IVPCM_NOTIFY_MASK_OUTPUT_BUFFER 1
+
+/* Notify event mask indicates input buffer is consumed. */
+#define VSS_IVPCM_NOTIFY_MASK_INPUT_BUFFER 2
+
+/* Notify event mask indicates a timetick */
+#define VSS_IVPCM_NOTIFY_MASK_TIMETICK 4
+
+/* Notify event mask indicates an error occurred in output buffer operation */
+#define VSS_IVPCM_NOTIFY_MASK_OUTPUT_ERROR 8
+
+/* Notify event mask indicates an error occurred in input buffer operation */
+#define VSS_IVPCM_NOTIFY_MASK_INPUT_ERROR 16
+
+
+struct vss_ivpcm_evt_notify_v2_t {
+ uint32_t tap_point;
+ uint32_t notify_mask;
+ uint64_t out_buff_addr;
+ uint64_t in_buff_addr;
+ uint16_t filled_out_size;
+ uint16_t request_buf_size;
+ uint16_t sampling_rate;
+ uint16_t num_out_channels;
+} __packed;
+
+struct cvp_start_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivpcm_cmd_start_v2_t vpcm_start_cmd;
+} __packed;
+
+struct cvp_push_buf_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivpcm_evt_push_buffer_v2_t vpcm_evt_push_buffer;
+} __packed;
+
+#define VSS_IVPCM_CMD_STOP 0x0001100B
+
+struct cvp_create_full_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_create_full_control_session_v2_t cvp_session;
+} __packed;
+
+struct cvp_command {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvp_set_device_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_set_device_v2_t cvp_set_device_v2;
+} __packed;
+
+struct cvp_set_dev_channels_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_topology_set_dev_channels_t cvp_set_channels;
+} __packed;
+
+struct cvp_set_vp3_data_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvp_set_rx_volume_index_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_set_volume_index_t cvp_set_vol_idx;
+} __packed;
+
+struct cvp_set_rx_volume_step_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivolume_cmd_set_step_t cvp_set_vol_step;
+} __packed;
+
+struct cvp_register_dev_cfg_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_register_device_config_t cvp_dev_cfg_data;
+} __packed;
+
+struct cvp_deregister_dev_cfg_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvp_register_cal_data_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_register_calibration_data_v2_t cvp_cal_data;
+} __packed;
+
+struct cvp_deregister_cal_data_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvp_register_vol_cal_data_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_register_volume_cal_data_t cvp_vol_cal_data;
+} __packed;
+
+struct cvp_deregister_vol_cal_data_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvp_set_mute_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivolume_cmd_mute_v2_t cvp_set_mute;
+} __packed;
+
+/* CB for up-link packets. */
+typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
+ uint32_t pkt_len,
+ uint32_t timestamp,
+ void *private_data);
+
+/* CB for down-link packets. */
+typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
+ void *private_data);
+
+/* CB for DTMF RX Detection */
+typedef void (*dtmf_rx_det_cb_fn)(uint8_t *pkt,
+ char *session,
+ void *private_data);
+
+typedef void (*voip_ssr_cb) (uint32_t opcode,
+ void *private_data);
+
+typedef void (*hostpcm_cb_fn)(uint8_t *data,
+ char *session,
+ void *private_data);
+
+struct mvs_driver_info {
+ uint32_t media_type;
+ uint32_t rate;
+ uint32_t network_type;
+ uint32_t dtx_mode;
+ ul_cb_fn ul_cb;
+ dl_cb_fn dl_cb;
+ voip_ssr_cb ssr_cb;
+ void *private_data;
+ uint32_t evrc_min_rate;
+ uint32_t evrc_max_rate;
+};
+
+struct dtmf_driver_info {
+ dtmf_rx_det_cb_fn dtmf_rx_ul_cb;
+ void *private_data;
+};
+
+struct hostpcm_driver_info {
+ hostpcm_cb_fn hostpcm_evt_cb;
+ void *private_data;
+};
+
+struct incall_rec_info {
+ uint32_t rec_enable;
+ uint32_t rec_mode;
+ uint32_t recording;
+};
+
+struct incall_music_info {
+ uint32_t play_enable;
+ uint32_t playing;
+ int count;
+ int force;
+ uint16_t port_id;
+};
+
+struct share_memory_info {
+ u32 mem_handle;
+ struct share_mem_buf sh_buf;
+ struct mem_map_table memtbl;
+};
+
+#define VSS_ISOUNDFOCUS_CMD_SET_SECTORS 0x00013133
+#define VSS_ISOUNDFOCUS_CMD_GET_SECTORS 0x00013134
+#define VSS_ISOUNDFOCUS_RSP_GET_SECTORS 0x00013135
+#define VSS_ISOURCETRACK_CMD_GET_ACTIVITY 0x00013136
+
+struct vss_isoundfocus_cmd_set_sectors_t {
+ uint16_t start_angles[8];
+ uint8_t enables[8];
+ uint16_t gain_step;
+} __packed;
+
+/* Payload of the VSS_ISOUNDFOCUS_RSP_GET_SECTORS response */
+struct vss_isoundfocus_rsp_get_sectors_t {
+ uint16_t start_angles[8];
+ uint8_t enables[8];
+ uint16_t gain_step;
+} __packed;
+
+struct cvp_set_sound_focus_param_cmd_t {
+ struct apr_hdr hdr;
+ struct vss_isoundfocus_cmd_set_sectors_t cvp_set_sound_focus_param;
+} __packed;
+
+/* Payload structure for the VSS_ISOURCETRACK_CMD_GET_ACTIVITY command */
+struct vss_isourcetrack_cmd_get_activity_t {
+ uint32_t mem_handle;
+ uint32_t mem_address_lsw;
+ uint32_t mem_address_msw;
+ uint32_t mem_size;
+} __packed;
+
+struct cvp_get_source_tracking_param_cmd_t {
+ struct apr_hdr hdr;
+ struct vss_isourcetrack_cmd_get_activity_t
+ cvp_get_source_tracking_param;
+} __packed;
+
+/* Structure for the sound activity data */
+struct vss_isourcetrack_activity_data_t {
+ uint8_t voice_active[8];
+ uint16_t talker_doa;
+ uint16_t interferer_doa[3];
+ uint8_t sound_strength[360];
+} __packed;
+
+struct shared_mem_info {
+ uint32_t mem_handle;
+ struct mem_map_table sh_mem_block;
+ struct mem_map_table sh_mem_table;
+};
+
+struct voice_data {
+ int voc_state;/*INIT, CHANGE, RELEASE, RUN */
+
+ /* Shared mem to store decoder and encoder packets */
+ struct share_memory_info shmem_info;
+
+ wait_queue_head_t mvm_wait;
+ wait_queue_head_t cvs_wait;
+ wait_queue_head_t cvp_wait;
+
+ /* Cache the values related to Rx and Tx devices */
+ struct device_data dev_rx;
+ struct device_data dev_tx;
+
+ /* Cache the values related to Rx and Tx streams */
+ struct stream_data stream_rx;
+ struct stream_data stream_tx;
+
+ u32 mvm_state;
+ u32 cvs_state;
+ u32 cvp_state;
+
+ u32 async_err;
+
+ /* Handle to MVM in the Q6 */
+ u16 mvm_handle;
+ /* Handle to CVS in the Q6 */
+ u16 cvs_handle;
+ /* Handle to CVP in the Q6 */
+ u16 cvp_handle;
+
+ struct mutex lock;
+
+ bool disable_topology;
+
+ uint16_t sidetone_gain;
+ uint8_t tty_mode;
+ /* slowtalk enable value */
+ uint32_t st_enable;
+ uint32_t hd_enable;
+ uint32_t dtmf_rx_detect_en;
+ /* Local Call Hold mode */
+ uint8_t lch_mode;
+
+ struct voice_dev_route_state voc_route_state;
+
+ u32 session_id;
+
+ struct incall_rec_info rec_info;
+
+ struct incall_music_info music_info;
+
+ struct voice_rec_route_state rec_route_state;
+
+ struct power_supply *psy;
+};
+
+struct cal_mem {
+ struct ion_handle *handle;
+ uint32_t phy;
+ void *buf;
+};
+
+#define MAX_VOC_SESSIONS 8
+
+struct common_data {
+ /* these default values are for all devices */
+ uint32_t default_mute_val;
+ uint32_t default_sample_val;
+ uint32_t default_vol_step_val;
+ uint32_t default_vol_ramp_duration_ms;
+ uint32_t default_mute_ramp_duration_ms;
+ bool ec_ref_ext;
+ uint16_t ec_port_id;
+
+ /* APR to MVM in the Q6 */
+ void *apr_q6_mvm;
+ /* APR to CVS in the Q6 */
+ void *apr_q6_cvs;
+ /* APR to CVP in the Q6 */
+ void *apr_q6_cvp;
+
+ struct cal_type_data *cal_data[MAX_VOICE_CAL_TYPES];
+
+ struct mem_map_table cal_mem_map_table;
+ uint32_t cal_mem_handle;
+
+ struct mem_map_table rtac_mem_map_table;
+ uint32_t rtac_mem_handle;
+
+ uint32_t voice_host_pcm_mem_handle;
+
+ struct cal_mem cvp_cal;
+ struct cal_mem cvs_cal;
+
+ struct mutex common_lock;
+
+ struct mvs_driver_info mvs_info;
+
+ struct dtmf_driver_info dtmf_info;
+
+ struct hostpcm_driver_info hostpcm_info;
+
+ struct voice_data voice[MAX_VOC_SESSIONS];
+
+ bool srvcc_rec_flag;
+ bool is_destroy_cvd;
+ bool is_vote_bms;
+ char cvd_version[CVD_VERSION_STRING_MAX_SIZE];
+ bool is_per_vocoder_cal_enabled;
+ bool is_sound_focus_resp_success;
+ bool is_source_tracking_resp_success;
+ struct vss_isoundfocus_rsp_get_sectors_t soundFocusResponse;
+ struct shared_mem_info source_tracking_sh_mem;
+ struct vss_isourcetrack_activity_data_t sourceTrackingResponse;
+};
+
+struct voice_session_itr {
+ int cur_idx;
+ int session_idx;
+};
+
+void voc_register_mvs_cb(ul_cb_fn ul_cb,
+ dl_cb_fn dl_cb,
+ voip_ssr_cb ssr_cb,
+ void *private_data);
+
+void voc_register_dtmf_rx_detection_cb(dtmf_rx_det_cb_fn dtmf_rx_ul_cb,
+ void *private_data);
+
+void voc_config_vocoder(uint32_t media_type,
+ uint32_t rate,
+ uint32_t network_type,
+ uint32_t dtx_mode,
+ uint32_t evrc_min_rate,
+ uint32_t evrc_max_rate);
+
+enum {
+ DEV_RX = 0,
+ DEV_TX,
+};
+
+enum {
+ RX_PATH = 0,
+ TX_PATH,
+};
+
+
+#define VOC_PATH_PASSIVE 0
+#define VOC_PATH_FULL 1
+#define VOC_PATH_VOLTE_PASSIVE 2
+#define VOC_PATH_VOICE2_PASSIVE 3
+#define VOC_PATH_QCHAT_PASSIVE 4
+#define VOC_PATH_VOWLAN_PASSIVE 5
+#define VOC_PATH_VOICEMMODE1_PASSIVE 6
+#define VOC_PATH_VOICEMMODE2_PASSIVE 7
+
+#define MAX_SESSION_NAME_LEN 32
+#define VOICE_SESSION_NAME "Voice session"
+#define VOIP_SESSION_NAME "VoIP session"
+#define VOLTE_SESSION_NAME "VoLTE session"
+#define VOICE2_SESSION_NAME "Voice2 session"
+#define QCHAT_SESSION_NAME "QCHAT session"
+#define VOWLAN_SESSION_NAME "VoWLAN session"
+#define VOICEMMODE1_NAME "VoiceMMode1"
+#define VOICEMMODE2_NAME "VoiceMMode2"
+
+#define VOICE2_SESSION_VSID_STR "10DC1000"
+#define QCHAT_SESSION_VSID_STR "10803000"
+#define VOWLAN_SESSION_VSID_STR "10002000"
+#define VOICEMMODE1_VSID_STR "11C05000"
+#define VOICEMMODE2_VSID_STR "11DC5000"
+#define VOICE_SESSION_VSID 0x10C01000
+#define VOICE2_SESSION_VSID 0x10DC1000
+#define VOLTE_SESSION_VSID 0x10C02000
+#define VOIP_SESSION_VSID 0x10004000
+#define QCHAT_SESSION_VSID 0x10803000
+#define VOWLAN_SESSION_VSID 0x10002000
+#define VOICEMMODE1_VSID 0x11C05000
+#define VOICEMMODE2_VSID 0x11DC5000
+#define ALL_SESSION_VSID 0xFFFFFFFF
+#define VSID_MAX ALL_SESSION_VSID
+
+/* called by alsa driver */
+int voc_set_pp_enable(uint32_t session_id, uint32_t module_id,
+ uint32_t enable);
+int voc_get_pp_enable(uint32_t session_id, uint32_t module_id);
+int voc_set_hd_enable(uint32_t session_id, uint32_t enable);
+uint8_t voc_get_tty_mode(uint32_t session_id);
+int voc_set_tty_mode(uint32_t session_id, uint8_t tty_mode);
+int voc_start_voice_call(uint32_t session_id);
+int voc_end_voice_call(uint32_t session_id);
+int voc_standby_voice_call(uint32_t session_id);
+int voc_resume_voice_call(uint32_t session_id);
+int voc_set_lch(uint32_t session_id, enum voice_lch_mode lch_mode);
+int voc_set_rx_vol_step(uint32_t session_id, uint32_t dir, uint32_t vol_step,
+ uint32_t ramp_duration);
+int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+ uint32_t ramp_duration);
+int voc_set_device_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+ uint32_t ramp_duration);
+int voc_get_rx_device_mute(uint32_t session_id);
+int voc_set_route_flag(uint32_t session_id, uint8_t path_dir, uint8_t set);
+uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir);
+int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable);
+void voc_disable_dtmf_det_on_active_sessions(void);
+int voc_alloc_cal_shared_memory(void);
+int voc_alloc_voip_shared_memory(void);
+int is_voc_initialized(void);
+int voc_register_vocproc_vol_table(void);
+int voc_deregister_vocproc_vol_table(void);
+int voc_send_cvp_map_vocpcm_memory(uint32_t session_id,
+ struct mem_map_table *tp_mem_table,
+ phys_addr_t paddr, uint32_t bufsize);
+int voc_send_cvp_unmap_vocpcm_memory(uint32_t session_id);
+int voc_send_cvp_start_vocpcm(uint32_t session_id,
+ struct vss_ivpcm_tap_point *vpcm_tp,
+ uint32_t no_of_tp);
+int voc_send_cvp_vocpcm_push_buf_evt(uint32_t session_id,
+ struct vss_ivpcm_evt_push_buffer_v2_t *push_buff_evt);
+int voc_send_cvp_stop_vocpcm(uint32_t session_id);
+void voc_register_hpcm_evt_cb(hostpcm_cb_fn hostpcm_cb,
+ void *private_data);
+void voc_deregister_hpcm_evt_cb(void);
+
+int voc_map_rtac_block(struct rtac_cal_block_data *cal_block);
+int voc_unmap_rtac_block(uint32_t *mem_map_handle);
+
+uint32_t voc_get_session_id(char *name);
+
+int voc_start_playback(uint32_t set, uint16_t port_id);
+int voc_start_record(uint32_t port_id, uint32_t set, uint32_t session_id);
+int voice_get_idx_for_session(u32 session_id);
+int voc_set_ext_ec_ref(uint16_t port_id, bool state);
+int voc_update_amr_vocoder_rate(uint32_t session_id);
+int voc_disable_device(uint32_t session_id);
+int voc_enable_device(uint32_t session_id);
+void voc_set_destroy_cvd_flag(bool is_destroy_cvd);
+void voc_set_vote_bms_flag(bool is_vote_bms);
+int voc_disable_topology(uint32_t session_id, uint32_t disable);
+int voc_set_device_config(uint32_t session_id, uint8_t path_dir,
+ uint8_t no_of_channels, uint32_t dev_port_id);
+uint32_t voice_get_topology(uint32_t topology_idx);
+int voc_set_sound_focus(struct sound_focus_param sound_focus_param);
+int voc_get_sound_focus(struct sound_focus_param *soundFocusData);
+int voc_get_source_tracking(struct source_tracking_param *sourceTrackingData);
+#endif
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
new file mode 100644
index 0000000..923908f
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -0,0 +1,1904 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/msm_audio_calibration.h>
+#include <linux/atomic.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/qdsp6v2/rtac.h>
+#include <linux/compat.h>
+#include <sound/q6asm-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6adm-v2.h>
+#include <sound/apr_audio-v2.h>
+#include "q6voice.h"
+#include "msm-pcm-routing-v2.h"
+#include <sound/adsp_err.h>
+
+
+/* Max size of payload (buf size - apr header) */
+#define MAX_PAYLOAD_SIZE 4076
+#define RTAC_MAX_ACTIVE_VOICE_COMBOS 2
+#define RTAC_MAX_ACTIVE_POPP 8
+#define RTAC_BUF_SIZE 163840
+
+#define TIMEOUT_MS 1000
+
+struct rtac_cal_block_data rtac_cal[MAX_RTAC_BLOCKS] = {
+/* ADM_RTAC_CAL */
+ {{RTAC_BUF_SIZE, 0, 0, 0}, {0, 0, 0} },
+/* ASM_RTAC_CAL */
+ {{RTAC_BUF_SIZE, 0, 0, 0}, {0, 0, 0} },
+/* VOICE_RTAC_CAL */
+ {{RTAC_BUF_SIZE, 0, 0, 0}, {0, 0, 0} },
+/* AFE_RTAC_CAL */
+ {{RTAC_BUF_SIZE, 0, 0, 0}, {0, 0, 0} }
+};
+
+struct rtac_common_data {
+ atomic_t usage_count;
+ atomic_t apr_err_code;
+};
+
+static struct rtac_common_data rtac_common;
+
+/* APR data */
+struct rtac_apr_data {
+ void *apr_handle;
+ atomic_t cmd_state;
+ wait_queue_head_t cmd_wait;
+};
+
+static struct rtac_apr_data rtac_adm_apr_data;
+static struct rtac_apr_data rtac_asm_apr_data[ASM_ACTIVE_STREAMS_ALLOWED + 1];
+static struct rtac_apr_data rtac_afe_apr_data;
+static struct rtac_apr_data rtac_voice_apr_data[RTAC_VOICE_MODES];
+
+/* ADM info & APR */
+static struct rtac_adm rtac_adm_data;
+static u32 *rtac_adm_buffer;
+
+
+/* ASM APR */
+static u32 *rtac_asm_buffer;
+
+static u32 *rtac_afe_buffer;
+
+/* Voice info & APR */
+struct rtac_voice_data_t {
+ uint32_t tx_topology_id;
+ uint32_t rx_topology_id;
+ uint32_t tx_afe_topology;
+ uint32_t rx_afe_topology;
+ uint32_t tx_afe_port;
+ uint32_t rx_afe_port;
+ uint16_t cvs_handle;
+ uint16_t cvp_handle;
+ uint32_t tx_acdb_id;
+ uint32_t rx_acdb_id;
+};
+
+struct rtac_voice {
+ uint32_t num_of_voice_combos;
+ struct rtac_voice_data_t voice[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+};
+
+struct rtac_afe_user_data {
+ uint32_t buf_size;
+ uint32_t cmd_size;
+ uint32_t port_id;
+ union {
+ struct rtac_afe_set {
+ struct afe_port_cmd_set_param_v2 cmd;
+ struct afe_port_param_data_v2 data;
+ } rtac_afe_set;
+ struct rtac_afe_get {
+ struct afe_port_cmd_get_param_v2 cmd;
+ struct afe_port_param_data_v2 data;
+ } rtac_afe_get;
+ };
+} __packed;
+
+static struct rtac_voice rtac_voice_data;
+static u32 *rtac_voice_buffer;
+static u32 voice_session_id[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+
+
+struct mutex rtac_adm_mutex;
+struct mutex rtac_adm_apr_mutex;
+struct mutex rtac_asm_apr_mutex;
+struct mutex rtac_voice_mutex;
+struct mutex rtac_voice_apr_mutex;
+struct mutex rtac_afe_apr_mutex;
+
+int rtac_clear_mapping(uint32_t cal_type)
+{
+ int result = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type >= MAX_RTAC_BLOCKS) {
+ pr_debug("%s: invalid cal type %d\n", __func__, cal_type);
+ result = -EINVAL;
+ goto done;
+ }
+
+ rtac_cal[cal_type].map_data.map_handle = 0;
+done:
+ return result;
+}
+
+int rtac_allocate_cal_buffer(uint32_t cal_type)
+{
+ int result = 0;
+ size_t len;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type >= MAX_RTAC_BLOCKS) {
+ pr_err("%s: cal_type %d is invalid!\n",
+ __func__, cal_type);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (rtac_cal[cal_type].cal_data.paddr != 0) {
+ pr_err("%s: memory already allocated! cal_type %d, paddr 0x%pK\n",
+ __func__, cal_type, &rtac_cal[cal_type].cal_data.paddr);
+ result = -EPERM;
+ goto done;
+ }
+
+ result = msm_audio_ion_alloc("rtac_client",
+ &rtac_cal[cal_type].map_data.ion_client,
+ &rtac_cal[cal_type].map_data.ion_handle,
+ rtac_cal[cal_type].map_data.map_size,
+ &rtac_cal[cal_type].cal_data.paddr,
+ &len,
+ &rtac_cal[cal_type].cal_data.kvaddr);
+ if (result < 0) {
+ pr_err("%s: ION create client for RTAC failed\n",
+ __func__);
+ goto done;
+ }
+
+ pr_debug("%s: cal_type %d, paddr 0x%pK, kvaddr 0x%pK, map_size 0x%x\n",
+ __func__, cal_type,
+ &rtac_cal[cal_type].cal_data.paddr,
+ rtac_cal[cal_type].cal_data.kvaddr,
+ rtac_cal[cal_type].map_data.map_size);
+done:
+ return result;
+}
+
+int rtac_free_cal_buffer(uint32_t cal_type)
+{
+ int result = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type >= MAX_RTAC_BLOCKS) {
+ pr_err("%s: cal_type %d is invalid!\n",
+ __func__, cal_type);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (rtac_cal[cal_type].map_data.ion_client == NULL) {
+ pr_debug("%s: cal_type %d not allocated!\n",
+ __func__, cal_type);
+ goto done;
+ }
+
+ result = msm_audio_ion_free(rtac_cal[cal_type].map_data.ion_client,
+ rtac_cal[cal_type].map_data.ion_handle);
+ if (result < 0) {
+ pr_err("%s: ION free for RTAC failed! cal_type %d, paddr 0x%pK\n",
+ __func__, cal_type, &rtac_cal[cal_type].cal_data.paddr);
+ goto done;
+ }
+
+ rtac_cal[cal_type].map_data.map_handle = 0;
+ rtac_cal[cal_type].map_data.ion_client = NULL;
+ rtac_cal[cal_type].map_data.ion_handle = NULL;
+ rtac_cal[cal_type].cal_data.size = 0;
+ rtac_cal[cal_type].cal_data.kvaddr = 0;
+ rtac_cal[cal_type].cal_data.paddr = 0;
+done:
+ return result;
+}
+
+int rtac_map_cal_buffer(uint32_t cal_type)
+{
+ int result = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type >= MAX_RTAC_BLOCKS) {
+ pr_err("%s: cal_type %d is invalid!\n",
+ __func__, cal_type);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (rtac_cal[cal_type].map_data.map_handle != 0) {
+ pr_err("%s: already mapped cal_type %d\n",
+ __func__, cal_type);
+ result = -EPERM;
+ goto done;
+ }
+
+ if (rtac_cal[cal_type].cal_data.paddr == 0) {
+ pr_err("%s: physical address is NULL cal_type %d\n",
+ __func__, cal_type);
+ result = -EPERM;
+ goto done;
+ }
+
+ switch (cal_type) {
+ case ADM_RTAC_CAL:
+ result = adm_map_rtac_block(&rtac_cal[cal_type]);
+ break;
+ case ASM_RTAC_CAL:
+ result = q6asm_map_rtac_block(&rtac_cal[cal_type]);
+ break;
+ case VOICE_RTAC_CAL:
+ result = voc_map_rtac_block(&rtac_cal[cal_type]);
+ break;
+ case AFE_RTAC_CAL:
+ result = afe_map_rtac_block(&rtac_cal[cal_type]);
+ break;
+ }
+ if (result < 0) {
+ pr_err("%s: map RTAC failed! cal_type %d\n",
+ __func__, cal_type);
+ goto done;
+ }
+done:
+ return result;
+}
+
+int rtac_unmap_cal_buffer(uint32_t cal_type)
+{
+ int result = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (cal_type >= MAX_RTAC_BLOCKS) {
+ pr_err("%s: cal_type %d is invalid!\n",
+ __func__, cal_type);
+ result = -EINVAL;
+ goto done;
+ }
+
+ if (rtac_cal[cal_type].map_data.map_handle == 0) {
+ pr_debug("%s: nothing to unmap cal_type %d\n",
+ __func__, cal_type);
+ goto done;
+ }
+
+ switch (cal_type) {
+ case ADM_RTAC_CAL:
+ result = adm_unmap_rtac_block(
+ &rtac_cal[cal_type].map_data.map_handle);
+ break;
+ case ASM_RTAC_CAL:
+ result = q6asm_unmap_rtac_block(
+ &rtac_cal[cal_type].map_data.map_handle);
+ break;
+ case VOICE_RTAC_CAL:
+ result = voc_unmap_rtac_block(
+ &rtac_cal[cal_type].map_data.map_handle);
+ break;
+ case AFE_RTAC_CAL:
+ result = afe_unmap_rtac_block(
+ &rtac_cal[cal_type].map_data.map_handle);
+ break;
+ }
+ if (result < 0) {
+ pr_err("%s: unmap RTAC failed! cal_type %d\n",
+ __func__, cal_type);
+ goto done;
+ }
+done:
+ return result;
+}
+
+static int rtac_open(struct inode *inode, struct file *f)
+{
+ int result = 0;
+
+ pr_debug("%s\n", __func__);
+
+ atomic_inc(&rtac_common.usage_count);
+ return result;
+}
+
+static int rtac_release(struct inode *inode, struct file *f)
+{
+ int result = 0;
+ int result2 = 0;
+ int i;
+
+ pr_debug("%s\n", __func__);
+
+ atomic_dec(&rtac_common.usage_count);
+ pr_debug("%s: ref count %d!\n", __func__,
+ atomic_read(&rtac_common.usage_count));
+
+ if (atomic_read(&rtac_common.usage_count) > 0)
+ goto done;
+
+ for (i = 0; i < MAX_RTAC_BLOCKS; i++) {
+ result2 = rtac_unmap_cal_buffer(i);
+ if (result2 < 0) {
+ pr_err("%s: unmap buffer failed! error %d!\n",
+ __func__, result2);
+ result = result2;
+ }
+
+ result2 = rtac_free_cal_buffer(i);
+ if (result2 < 0) {
+ pr_err("%s: free buffer failed! error %d!\n",
+ __func__, result2);
+ result = result2;
+ }
+ }
+done:
+ return result;
+}
+
+
+/* ADM Info */
+void add_popp(u32 dev_idx, u32 port_id, u32 popp_id)
+{
+ u32 i = 0;
+
+ for (; i < rtac_adm_data.device[dev_idx].num_of_popp; i++)
+ if (rtac_adm_data.device[dev_idx].popp[i].popp == popp_id)
+ goto done;
+
+ if (rtac_adm_data.device[dev_idx].num_of_popp ==
+ RTAC_MAX_ACTIVE_POPP) {
+ pr_err("%s, Max POPP!\n", __func__);
+ goto done;
+ }
+ rtac_adm_data.device[dev_idx].popp[
+ rtac_adm_data.device[dev_idx].num_of_popp].popp = popp_id;
+ rtac_adm_data.device[dev_idx].popp[
+ rtac_adm_data.device[dev_idx].num_of_popp].popp_topology =
+ q6asm_get_asm_topology(popp_id);
+ rtac_adm_data.device[dev_idx].popp[
+ rtac_adm_data.device[dev_idx].num_of_popp++].app_type =
+ q6asm_get_asm_app_type(popp_id);
+
+ pr_debug("%s: popp_id = %d, popp topology = 0x%x, popp app type = 0x%x\n",
+ __func__,
+ rtac_adm_data.device[dev_idx].popp[
+ rtac_adm_data.device[dev_idx].num_of_popp - 1].popp,
+ rtac_adm_data.device[dev_idx].popp[
+ rtac_adm_data.device[dev_idx].num_of_popp - 1].popp_topology,
+ rtac_adm_data.device[dev_idx].popp[
+ rtac_adm_data.device[dev_idx].num_of_popp - 1].app_type);
+done:
+ return;
+}
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id,
+ u32 app_type, u32 acdb_id)
+{
+ u32 i = 0;
+
+ pr_debug("%s: num rtac devices %d port_id = %d, copp_id = %d\n",
+ __func__, rtac_adm_data.num_of_dev, port_id, copp_id);
+
+ mutex_lock(&rtac_adm_mutex);
+ if (rtac_adm_data.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
+ pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+ goto done;
+ }
+
+ /* Check if device already added */
+ if (rtac_adm_data.num_of_dev != 0) {
+ for (; i < rtac_adm_data.num_of_dev; i++) {
+ if (rtac_adm_data.device[i].afe_port == port_id &&
+ rtac_adm_data.device[i].copp == copp_id) {
+ add_popp(i, port_id, popp_id);
+ goto done;
+ }
+ if (rtac_adm_data.device[i].num_of_popp ==
+ RTAC_MAX_ACTIVE_POPP) {
+ pr_err("%s, Max POPP!\n", __func__);
+ goto done;
+ }
+ }
+ }
+
+ /* Add device */
+ rtac_adm_data.num_of_dev++;
+
+ rtac_adm_data.device[i].topology_id =
+ adm_get_topology_for_port_from_copp_id(port_id, copp_id);
+ rtac_adm_data.device[i].afe_topology =
+ afe_get_topology(port_id);
+ rtac_adm_data.device[i].afe_port = port_id;
+ rtac_adm_data.device[i].copp = copp_id;
+ rtac_adm_data.device[i].app_type = app_type;
+ rtac_adm_data.device[i].acdb_dev_id = acdb_id;
+ rtac_adm_data.device[i].popp[
+ rtac_adm_data.device[i].num_of_popp].popp = popp_id;
+ rtac_adm_data.device[i].popp[
+ rtac_adm_data.device[i].num_of_popp].popp_topology =
+ q6asm_get_asm_topology(popp_id);
+ rtac_adm_data.device[i].popp[
+ rtac_adm_data.device[i].num_of_popp++].app_type =
+ q6asm_get_asm_app_type(popp_id);
+
+ pr_debug("%s: topology = 0x%x, afe_topology = 0x%x, port_id = %d, copp_id = %d, app id = 0x%x, acdb id = %d, popp_id = %d, popp topology = 0x%x, popp app type = 0x%x\n",
+ __func__,
+ rtac_adm_data.device[i].topology_id,
+ rtac_adm_data.device[i].afe_topology,
+ rtac_adm_data.device[i].afe_port,
+ rtac_adm_data.device[i].copp,
+ rtac_adm_data.device[i].app_type,
+ rtac_adm_data.device[i].acdb_dev_id,
+ rtac_adm_data.device[i].popp[
+ rtac_adm_data.device[i].num_of_popp - 1].popp,
+ rtac_adm_data.device[i].popp[
+ rtac_adm_data.device[i].num_of_popp - 1].popp_topology,
+ rtac_adm_data.device[i].popp[
+ rtac_adm_data.device[i].num_of_popp - 1].app_type);
+done:
+ mutex_unlock(&rtac_adm_mutex);
+}
+
+static void shift_adm_devices(u32 dev_idx)
+{
+ for (; dev_idx < rtac_adm_data.num_of_dev; dev_idx++) {
+ memcpy(&rtac_adm_data.device[dev_idx],
+ &rtac_adm_data.device[dev_idx + 1],
+ sizeof(rtac_adm_data.device[dev_idx]));
+ memset(&rtac_adm_data.device[dev_idx + 1], 0,
+ sizeof(rtac_adm_data.device[dev_idx]));
+ }
+}
+
+static void shift_popp(u32 copp_idx, u32 popp_idx)
+{
+ for (; popp_idx < rtac_adm_data.device[copp_idx].num_of_popp;
+ popp_idx++) {
+ memcpy(&rtac_adm_data.device[copp_idx].popp[popp_idx].popp,
+ &rtac_adm_data.device[copp_idx].popp[popp_idx + 1].
+ popp, sizeof(uint32_t));
+ memcpy(&rtac_adm_data.device[copp_idx].popp[popp_idx].
+ popp_topology,
+ &rtac_adm_data.device[copp_idx].popp[popp_idx + 1].
+ popp_topology,
+ sizeof(uint32_t));
+ memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1].
+ popp, 0, sizeof(uint32_t));
+ memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1].
+ popp_topology, 0, sizeof(uint32_t));
+ }
+}
+
+void rtac_remove_adm_device(u32 port_id, u32 copp_id)
+{
+ s32 i;
+
+ pr_debug("%s: num rtac devices %d port_id = %d, copp_id = %d\n",
+ __func__, rtac_adm_data.num_of_dev, port_id, copp_id);
+
+ mutex_lock(&rtac_adm_mutex);
+ /* look for device */
+ for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+ if (rtac_adm_data.device[i].afe_port == port_id &&
+ rtac_adm_data.device[i].copp == copp_id) {
+ memset(&rtac_adm_data.device[i], 0,
+ sizeof(rtac_adm_data.device[i]));
+ rtac_adm_data.num_of_dev--;
+
+ if (rtac_adm_data.num_of_dev >= 1) {
+ shift_adm_devices(i);
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&rtac_adm_mutex);
+}
+
+void rtac_remove_popp_from_adm_devices(u32 popp_id)
+{
+ s32 i, j;
+
+ pr_debug("%s: popp_id = %d\n", __func__, popp_id);
+
+ mutex_lock(&rtac_adm_mutex);
+ for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+ for (j = 0; j < rtac_adm_data.device[i].num_of_popp; j++) {
+ if (rtac_adm_data.device[i].popp[j].popp ==
+ popp_id) {
+ rtac_adm_data.device[i].popp[j].popp = 0;
+ rtac_adm_data.device[i].popp[j].
+ popp_topology = 0;
+ rtac_adm_data.device[i].num_of_popp--;
+ shift_popp(i, j);
+ }
+ }
+ }
+ mutex_unlock(&rtac_adm_mutex);
+}
+
+
+/* Voice Info */
+static void set_rtac_voice_data(int idx, u32 cvs_handle, u32 cvp_handle,
+ u32 rx_afe_port, u32 tx_afe_port,
+ u32 rx_acdb_id, u32 tx_acdb_id,
+ u32 session_id)
+{
+ rtac_voice_data.voice[idx].tx_topology_id =
+ voice_get_topology(CVP_VOC_TX_TOPOLOGY_CAL);
+ rtac_voice_data.voice[idx].rx_topology_id =
+ voice_get_topology(CVP_VOC_RX_TOPOLOGY_CAL);
+ rtac_voice_data.voice[idx].tx_afe_topology =
+ afe_get_topology(tx_afe_port);
+ rtac_voice_data.voice[idx].rx_afe_topology =
+ afe_get_topology(rx_afe_port);
+ rtac_voice_data.voice[idx].tx_afe_port = tx_afe_port;
+ rtac_voice_data.voice[idx].rx_afe_port = rx_afe_port;
+ rtac_voice_data.voice[idx].tx_acdb_id = tx_acdb_id;
+ rtac_voice_data.voice[idx].rx_acdb_id = rx_acdb_id;
+ rtac_voice_data.voice[idx].cvs_handle = cvs_handle;
+ rtac_voice_data.voice[idx].cvp_handle = cvp_handle;
+ pr_debug("%s\n%s: %x\n%s: %d %s: %d\n%s: %d %s: %d\n %s: %d\n %s: %d\n%s: %d %s: %d\n%s",
+ "<---- Voice Data Info ---->", "Session id", session_id,
+ "cvs_handle", cvs_handle, "cvp_handle", cvp_handle,
+ "rx_afe_topology", rtac_voice_data.voice[idx].rx_afe_topology,
+ "tx_afe_topology", rtac_voice_data.voice[idx].tx_afe_topology,
+ "rx_afe_port", rx_afe_port, "tx_afe_port", tx_afe_port,
+ "rx_acdb_id", rx_acdb_id, "tx_acdb_id", tx_acdb_id,
+ "<-----------End----------->");
+
+ /* Store session ID for voice RTAC */
+ voice_session_id[idx] = session_id;
+}
+
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+ u32 tx_afe_port, u32 rx_acdb_id, u32 tx_acdb_id,
+ u32 session_id)
+{
+ u32 i = 0;
+
+ pr_debug("%s\n", __func__);
+ mutex_lock(&rtac_voice_mutex);
+
+ if (rtac_voice_data.num_of_voice_combos ==
+ RTAC_MAX_ACTIVE_VOICE_COMBOS) {
+ pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+ goto done;
+ }
+
+ /* Check if device already added */
+ if (rtac_voice_data.num_of_voice_combos != 0) {
+ for (; i < rtac_voice_data.num_of_voice_combos; i++) {
+ if (rtac_voice_data.voice[i].cvs_handle ==
+ cvs_handle) {
+ set_rtac_voice_data(i, cvs_handle, cvp_handle,
+ rx_afe_port, tx_afe_port, rx_acdb_id,
+ tx_acdb_id, session_id);
+ goto done;
+ }
+ }
+ }
+
+ /* Add device */
+ rtac_voice_data.num_of_voice_combos++;
+ set_rtac_voice_data(i, cvs_handle, cvp_handle,
+ rx_afe_port, tx_afe_port,
+ rx_acdb_id, tx_acdb_id,
+ session_id);
+done:
+ mutex_unlock(&rtac_voice_mutex);
+}
+
+static void shift_voice_devices(u32 idx)
+{
+ for (; idx < rtac_voice_data.num_of_voice_combos - 1; idx++) {
+ memcpy(&rtac_voice_data.voice[idx],
+ &rtac_voice_data.voice[idx + 1],
+ sizeof(rtac_voice_data.voice[idx]));
+ voice_session_id[idx] = voice_session_id[idx + 1];
+ }
+}
+
+void rtac_remove_voice(u32 cvs_handle)
+{
+ u32 i = 0;
+
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&rtac_voice_mutex);
+ /* look for device */
+ for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+ if (rtac_voice_data.voice[i].cvs_handle == cvs_handle) {
+ shift_voice_devices(i);
+ rtac_voice_data.num_of_voice_combos--;
+ memset(&rtac_voice_data.voice[
+ rtac_voice_data.num_of_voice_combos], 0,
+ sizeof(rtac_voice_data.voice
+ [rtac_voice_data.num_of_voice_combos]));
+ voice_session_id[rtac_voice_data.num_of_voice_combos]
+ = 0;
+ break;
+ }
+ }
+ mutex_unlock(&rtac_voice_mutex);
+}
+
+static u32 get_voice_session_id_cvs(u32 cvs_handle)
+{
+ u32 i;
+
+ for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+ if (rtac_voice_data.voice[i].cvs_handle == cvs_handle)
+ return voice_session_id[i];
+ }
+
+ pr_err("%s: No voice index for CVS handle %d found returning 0\n",
+ __func__, cvs_handle);
+ return 0;
+}
+
+static u32 get_voice_session_id_cvp(u32 cvp_handle)
+{
+ u32 i;
+
+ for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+ if (rtac_voice_data.voice[i].cvp_handle == cvp_handle)
+ return voice_session_id[i];
+ }
+
+ pr_err("%s: No voice index for CVP handle %d found returning 0\n",
+ __func__, cvp_handle);
+ return 0;
+}
+
+static int get_voice_index(u32 mode, u32 handle)
+{
+ if (mode == RTAC_CVP)
+ return voice_get_idx_for_session(
+ get_voice_session_id_cvp(handle));
+ if (mode == RTAC_CVS)
+ return voice_get_idx_for_session(
+ get_voice_session_id_cvs(handle));
+
+ pr_err("%s: Invalid mode %d, returning 0\n",
+ __func__, mode);
+ return 0;
+}
+
+
+/* ADM APR */
+void rtac_set_adm_handle(void *handle)
+{
+ pr_debug("%s: handle = %pK\n", __func__, handle);
+
+ mutex_lock(&rtac_adm_apr_mutex);
+ rtac_adm_apr_data.apr_handle = handle;
+ mutex_unlock(&rtac_adm_apr_mutex);
+}
+
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+{
+ pr_debug("%s:cmd_state = %d\n", __func__,
+ atomic_read(&rtac_adm_apr_data.cmd_state));
+ if (atomic_read(&rtac_adm_apr_data.cmd_state) != 1)
+ return false;
+
+ pr_debug("%s\n", __func__);
+ if (payload_size == sizeof(uint32_t))
+ atomic_set(&rtac_common.apr_err_code, payload[0]);
+ else if (payload_size == (2*sizeof(uint32_t)))
+ atomic_set(&rtac_common.apr_err_code, payload[1]);
+
+ atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+ wake_up(&rtac_adm_apr_data.cmd_wait);
+ return true;
+}
+
+int send_adm_apr(void *buf, u32 opcode)
+{
+ s32 result;
+ u32 user_buf_size = 0;
+ u32 bytes_returned = 0;
+ u32 copp_id;
+ u32 payload_size;
+ u32 data_size = 0;
+ int copp_idx;
+ int port_idx;
+ struct apr_hdr adm_params;
+
+ pr_debug("%s\n", __func__);
+
+ if (rtac_cal[ADM_RTAC_CAL].map_data.ion_handle == NULL) {
+ result = rtac_allocate_cal_buffer(ADM_RTAC_CAL);
+ if (result < 0) {
+ pr_err("%s: allocate buffer failed!",
+ __func__);
+ goto done;
+ }
+ }
+
+ if (rtac_cal[ADM_RTAC_CAL].map_data.map_handle == 0) {
+ result = rtac_map_cal_buffer(ADM_RTAC_CAL);
+ if (result < 0) {
+ pr_err("%s: map buffer failed!",
+ __func__);
+ goto done;
+ }
+ }
+
+ if (copy_from_user(&user_buf_size, (void *)buf,
+ sizeof(user_buf_size))) {
+ pr_err("%s: Copy from user failed! buf = 0x%pK\n",
+ __func__, buf);
+ goto done;
+ }
+ if (user_buf_size <= 0) {
+ pr_err("%s: Invalid buffer size = %d\n",
+ __func__, user_buf_size);
+ goto done;
+ }
+
+ if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy payload size from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ if (copy_from_user(&copp_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy port id from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ if (adm_get_indexes_from_copp_id(copp_id, &copp_idx, &port_idx) != 0) {
+ pr_err("%s: Copp Id-%d is not active\n", __func__, copp_id);
+ goto done;
+ }
+
+ mutex_lock(&rtac_adm_apr_mutex);
+ if (rtac_adm_apr_data.apr_handle == NULL) {
+ pr_err("%s: APR not initialized\n", __func__);
+ result = -EINVAL;
+ goto err;
+ }
+
+ if (opcode == ADM_CMD_SET_PP_PARAMS_V5) {
+ /* set payload size to in-band payload */
+ /* set data size to actual out of band payload size */
+ data_size = payload_size - 4 * sizeof(u32);
+ if (data_size > rtac_cal[ADM_RTAC_CAL].map_data.map_size) {
+ pr_err("%s: Invalid data size = %d\n",
+ __func__, data_size);
+ result = -EINVAL;
+ goto err;
+ }
+ payload_size = 4 * sizeof(u32);
+
+ /* Copy buffer to out-of-band payload */
+ if (copy_from_user((void *)
+ rtac_cal[ADM_RTAC_CAL].cal_data.kvaddr,
+ buf + 7 * sizeof(u32), data_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+ /* set payload size in packet */
+ rtac_adm_buffer[8] = data_size;
+ } else {
+ if (payload_size > MAX_PAYLOAD_SIZE) {
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, payload_size);
+ result = -EINVAL;
+ goto err;
+ }
+
+ /* Copy buffer to in-band payload */
+ if (copy_from_user(rtac_adm_buffer +
+ sizeof(adm_params)/sizeof(u32),
+ buf + 3 * sizeof(u32), payload_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+ }
+
+ /* Pack header */
+ adm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ payload_size);
+ adm_params.src_svc = APR_SVC_ADM;
+ adm_params.src_domain = APR_DOMAIN_APPS;
+ adm_params.src_port = copp_id;
+ adm_params.dest_svc = APR_SVC_ADM;
+ adm_params.dest_domain = APR_DOMAIN_ADSP;
+ adm_params.dest_port = copp_id;
+ adm_params.token = port_idx << 16 | copp_idx;
+ adm_params.opcode = opcode;
+
+ /* fill for out-of-band */
+ rtac_adm_buffer[5] =
+ lower_32_bits(rtac_cal[ADM_RTAC_CAL].cal_data.paddr);
+ rtac_adm_buffer[6] =
+ msm_audio_populate_upper_32_bits(
+ rtac_cal[ADM_RTAC_CAL].cal_data.paddr);
+ rtac_adm_buffer[7] = rtac_cal[ADM_RTAC_CAL].map_data.map_handle;
+
+ memcpy(rtac_adm_buffer, &adm_params, sizeof(adm_params));
+ atomic_set(&rtac_adm_apr_data.cmd_state, 1);
+
+ pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
+ __func__, opcode,
+ &rtac_cal[ADM_RTAC_CAL].cal_data.paddr);
+
+ result = apr_send_pkt(rtac_adm_apr_data.apr_handle,
+ (uint32_t *)rtac_adm_buffer);
+ if (result < 0) {
+ pr_err("%s: Set params failed copp = %d\n", __func__, copp_id);
+ goto err;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(rtac_adm_apr_data.cmd_wait,
+ (atomic_read(&rtac_adm_apr_data.cmd_state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: Set params timed out copp = %d\n", __func__,
+ copp_id);
+ goto err;
+ }
+ if (atomic_read(&rtac_common.apr_err_code)) {
+ pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
+ __func__, adsp_err_get_err_str(atomic_read(
+ &rtac_common.apr_err_code)),
+ opcode);
+ result = adsp_err_get_lnx_err_code(
+ atomic_read(
+ &rtac_common.apr_err_code));
+ goto err;
+ }
+
+ if (opcode == ADM_CMD_GET_PP_PARAMS_V5) {
+ bytes_returned = ((u32 *)rtac_cal[ADM_RTAC_CAL].cal_data.
+ kvaddr)[2] + 3 * sizeof(u32);
+
+ if (bytes_returned > user_buf_size) {
+ pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
+ __func__, user_buf_size, bytes_returned);
+ result = -EINVAL;
+ goto err;
+ }
+
+ if (copy_to_user(buf, (void *)
+ rtac_cal[ADM_RTAC_CAL].cal_data.kvaddr,
+ bytes_returned)) {
+ pr_err("%s: Could not copy buffer to user,size = %d\n",
+ __func__, bytes_returned);
+ result = -EINVAL;
+ goto err;
+ }
+ } else {
+ bytes_returned = data_size;
+ }
+ mutex_unlock(&rtac_adm_apr_mutex);
+done:
+ return bytes_returned;
+err:
+ mutex_unlock(&rtac_adm_apr_mutex);
+ return result;
+}
+
+
+/* ASM APR */
+void rtac_set_asm_handle(u32 session_id, void *handle)
+{
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&rtac_asm_apr_mutex);
+ rtac_asm_apr_data[session_id].apr_handle = handle;
+ mutex_unlock(&rtac_asm_apr_mutex);
+}
+
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+ u32 payload_size)
+{
+ if (atomic_read(&rtac_asm_apr_data[session_id].cmd_state) != 1)
+ return false;
+
+ pr_debug("%s\n", __func__);
+ if (payload_size == sizeof(uint32_t))
+ atomic_set(&rtac_common.apr_err_code, payload[0]);
+ else if (payload_size == (2*sizeof(uint32_t)))
+ atomic_set(&rtac_common.apr_err_code, payload[1]);
+
+ atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 0);
+ wake_up(&rtac_asm_apr_data[session_id].cmd_wait);
+ return true;
+}
+
+int send_rtac_asm_apr(void *buf, u32 opcode)
+{
+ s32 result;
+ u32 user_buf_size = 0;
+ u32 bytes_returned = 0;
+ u32 session_id = 0;
+ u32 payload_size;
+ u32 data_size = 0;
+ struct apr_hdr asm_params;
+
+ pr_debug("%s\n", __func__);
+
+ if (rtac_cal[ASM_RTAC_CAL].map_data.ion_handle == NULL) {
+ result = rtac_allocate_cal_buffer(ASM_RTAC_CAL);
+ if (result < 0) {
+ pr_err("%s: allocate buffer failed!",
+ __func__);
+ goto done;
+ }
+ }
+
+ if (rtac_cal[ASM_RTAC_CAL].map_data.map_handle == 0) {
+ result = rtac_map_cal_buffer(ASM_RTAC_CAL);
+ if (result < 0) {
+ pr_err("%s: map buffer failed!",
+ __func__);
+ goto done;
+ }
+ }
+
+ if (copy_from_user(&user_buf_size, (void *)buf,
+ sizeof(user_buf_size))) {
+ pr_err("%s: Copy from user failed! buf = 0x%pK\n",
+ __func__, buf);
+ goto done;
+ }
+ if (user_buf_size <= 0) {
+ pr_err("%s: Invalid buffer size = %d\n",
+ __func__, user_buf_size);
+ goto done;
+ }
+
+ if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy payload size from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ if (copy_from_user(&session_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy session id from user buffer\n",
+ __func__);
+ goto done;
+ }
+ if (session_id >= (ASM_ACTIVE_STREAMS_ALLOWED + 1)) {
+ pr_err("%s: Invalid Session = %d\n", __func__, session_id);
+ goto done;
+ }
+
+ mutex_lock(&rtac_asm_apr_mutex);
+ if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
+ pr_err("%s: APR not initialized\n", __func__);
+ result = -EINVAL;
+ goto err;
+ }
+
+ if (opcode == ASM_STREAM_CMD_SET_PP_PARAMS_V2) {
+ /* set payload size to in-band payload */
+ /* set data size to actual out of band payload size */
+ data_size = payload_size - 4 * sizeof(u32);
+ if (data_size > rtac_cal[ASM_RTAC_CAL].map_data.map_size) {
+ pr_err("%s: Invalid data size = %d\n",
+ __func__, data_size);
+ result = -EINVAL;
+ goto err;
+ }
+ payload_size = 4 * sizeof(u32);
+
+ /* Copy buffer to out-of-band payload */
+ if (copy_from_user((void *)
+ rtac_cal[ASM_RTAC_CAL].cal_data.kvaddr,
+ buf + 7 * sizeof(u32), data_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+ /* set payload size in packet */
+ rtac_asm_buffer[8] = data_size;
+
+ } else {
+ if (payload_size > MAX_PAYLOAD_SIZE) {
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, payload_size);
+ result = -EINVAL;
+ goto err;
+ }
+
+ /* Copy buffer to in-band payload */
+ if (copy_from_user(rtac_asm_buffer +
+ sizeof(asm_params)/sizeof(u32),
+ buf + 3 * sizeof(u32), payload_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+ }
+
+ /* Pack header */
+ asm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ asm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ payload_size);
+ asm_params.src_svc = q6asm_get_apr_service_id(session_id);
+ asm_params.src_domain = APR_DOMAIN_APPS;
+ asm_params.src_port = (session_id << 8) | 0x0001;
+ asm_params.dest_svc = APR_SVC_ASM;
+ asm_params.dest_domain = APR_DOMAIN_ADSP;
+ asm_params.dest_port = (session_id << 8) | 0x0001;
+ asm_params.token = session_id;
+ asm_params.opcode = opcode;
+
+ /* fill for out-of-band */
+ rtac_asm_buffer[5] =
+ lower_32_bits(rtac_cal[ASM_RTAC_CAL].cal_data.paddr);
+ rtac_asm_buffer[6] =
+ msm_audio_populate_upper_32_bits(
+ rtac_cal[ASM_RTAC_CAL].cal_data.paddr);
+ rtac_asm_buffer[7] = rtac_cal[ASM_RTAC_CAL].map_data.map_handle;
+
+ memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
+ atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
+
+ pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
+ __func__, opcode,
+ &rtac_cal[ASM_RTAC_CAL].cal_data.paddr);
+
+ result = apr_send_pkt(rtac_asm_apr_data[session_id].apr_handle,
+ (uint32_t *)rtac_asm_buffer);
+ if (result < 0) {
+ pr_err("%s: Set params failed session = %d\n",
+ __func__, session_id);
+ goto err;
+ }
+
+ /* Wait for the callback */
+ result = wait_event_timeout(rtac_asm_apr_data[session_id].cmd_wait,
+ (atomic_read(&rtac_asm_apr_data[session_id].cmd_state) == 0),
+ 5 * HZ);
+ if (!result) {
+ pr_err("%s: Set params timed out session = %d\n",
+ __func__, session_id);
+ goto err;
+ }
+ if (atomic_read(&rtac_common.apr_err_code)) {
+ pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
+ __func__, adsp_err_get_err_str(atomic_read(
+ &rtac_common.apr_err_code)),
+ opcode);
+ result = adsp_err_get_lnx_err_code(
+ atomic_read(
+ &rtac_common.apr_err_code));
+ goto err;
+ }
+
+ if (opcode == ASM_STREAM_CMD_GET_PP_PARAMS_V2) {
+ bytes_returned = ((u32 *)rtac_cal[ASM_RTAC_CAL].cal_data.
+ kvaddr)[2] + 3 * sizeof(u32);
+
+ if (bytes_returned > user_buf_size) {
+ pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
+ __func__, user_buf_size, bytes_returned);
+ result = -EINVAL;
+ goto err;
+ }
+
+ if (copy_to_user(buf, (void *)
+ rtac_cal[ASM_RTAC_CAL].cal_data.kvaddr,
+ bytes_returned)) {
+ pr_err("%s: Could not copy buffer to user,size = %d\n",
+ __func__, bytes_returned);
+ result = -EINVAL;
+ goto err;
+ }
+ } else {
+ bytes_returned = data_size;
+ }
+ mutex_unlock(&rtac_asm_apr_mutex);
+done:
+ return bytes_returned;
+err:
+ mutex_unlock(&rtac_asm_apr_mutex);
+ return result;
+}
+
+/* AFE APR */
+void rtac_set_afe_handle(void *handle)
+{
+ mutex_lock(&rtac_afe_apr_mutex);
+ rtac_afe_apr_data.apr_handle = handle;
+ mutex_unlock(&rtac_afe_apr_mutex);
+}
+
+bool rtac_make_afe_callback(uint32_t *payload, uint32_t payload_size)
+{
+ pr_debug("%s:cmd_state = %d\n", __func__,
+ atomic_read(&rtac_afe_apr_data.cmd_state));
+ if (atomic_read(&rtac_afe_apr_data.cmd_state) != 1)
+ return false;
+
+ if (payload_size == sizeof(uint32_t))
+ atomic_set(&rtac_common.apr_err_code, payload[0]);
+ else if (payload_size == (2*sizeof(uint32_t)))
+ atomic_set(&rtac_common.apr_err_code, payload[1]);
+
+ atomic_set(&rtac_afe_apr_data.cmd_state, 0);
+ wake_up(&rtac_afe_apr_data.cmd_wait);
+ return true;
+}
+
+static int fill_afe_apr_hdr(struct apr_hdr *apr_hdr, uint32_t port,
+ uint32_t opcode, uint32_t apr_msg_size)
+{
+ if (apr_hdr == NULL) {
+ pr_err("%s: invalid APR pointer", __func__);
+ return -EINVAL;
+ }
+
+ apr_hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ apr_hdr->pkt_size = apr_msg_size;
+ apr_hdr->src_svc = APR_SVC_AFE;
+ apr_hdr->src_domain = APR_DOMAIN_APPS;
+ apr_hdr->src_port = 0;
+ apr_hdr->dest_svc = APR_SVC_AFE;
+ apr_hdr->dest_domain = APR_DOMAIN_ADSP;
+ apr_hdr->dest_port = 0;
+ apr_hdr->token = port;
+ apr_hdr->opcode = opcode;
+
+ return 0;
+
+}
+static int send_rtac_afe_apr(void *buf, uint32_t opcode)
+{
+ int32_t result;
+ uint32_t bytes_returned = 0;
+ uint32_t port_index = 0;
+ uint32_t apr_msg_size = 0;
+ struct rtac_afe_user_data user_afe_buf;
+
+ pr_debug("%s\n", __func__);
+
+ if (rtac_cal[AFE_RTAC_CAL].map_data.ion_handle == NULL) {
+ result = rtac_allocate_cal_buffer(AFE_RTAC_CAL);
+ if (result < 0) {
+ pr_err("%s: allocate buffer failed! ret = %d\n",
+ __func__, result);
+ goto done;
+ }
+ }
+
+ if (rtac_cal[AFE_RTAC_CAL].map_data.map_handle == 0) {
+ result = rtac_map_cal_buffer(AFE_RTAC_CAL);
+ if (result < 0) {
+ pr_err("%s: map buffer failed! ret = %d\n",
+ __func__, result);
+ goto done;
+ }
+ }
+
+ if (copy_from_user(&user_afe_buf, (void *)buf,
+ sizeof(struct rtac_afe_user_data))) {
+ pr_err("%s: Copy from user failed! buf = 0x%pK\n",
+ __func__, buf);
+ goto done;
+ }
+
+ if (user_afe_buf.buf_size <= 0) {
+ pr_err("%s: Invalid buffer size = %d\n",
+ __func__, user_afe_buf.buf_size);
+ goto done;
+ }
+
+ port_index = q6audio_get_port_index(user_afe_buf.port_id);
+ if (port_index >= AFE_MAX_PORTS) {
+ pr_err("%s: Invalid AFE port = 0x%x\n",
+ __func__, user_afe_buf.port_id);
+ goto done;
+ }
+
+ mutex_lock(&rtac_afe_apr_mutex);
+ if (rtac_afe_apr_data.apr_handle == NULL) {
+ pr_err("%s: APR not initialized\n", __func__);
+ result = -EINVAL;
+ goto err;
+ }
+ if (opcode == AFE_PORT_CMD_SET_PARAM_V2) {
+ struct afe_port_cmd_set_param_v2 *afe_set_apr_msg;
+
+ /* set data size to actual out of band payload size */
+ if (user_afe_buf.rtac_afe_set.cmd.payload_size >
+ rtac_cal[AFE_RTAC_CAL].map_data.map_size) {
+ pr_err("%s: Invalid data size = %d\n",
+ __func__,
+ user_afe_buf.rtac_afe_set.cmd.payload_size);
+ result = -EINVAL;
+ goto err;
+ }
+
+ /* Copy buffer to out-of-band payload */
+ if (copy_from_user((void *)
+ rtac_cal[AFE_RTAC_CAL].cal_data.kvaddr,
+ buf+offsetof(struct rtac_afe_user_data,
+ rtac_afe_set.data),
+ user_afe_buf.rtac_afe_set.cmd.payload_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+
+ /* Copy AFE APR Message */
+ afe_set_apr_msg = (struct afe_port_cmd_set_param_v2 *)
+ ((u8 *)rtac_afe_buffer +
+ sizeof(struct apr_hdr));
+ if (copy_from_user((void *)
+ afe_set_apr_msg,
+ buf + offsetof(struct rtac_afe_user_data,
+ rtac_afe_set.cmd),
+ sizeof(struct afe_port_cmd_set_param_v2))) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+
+ afe_set_apr_msg->payload_address_lsw =
+ lower_32_bits(rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
+ afe_set_apr_msg->payload_address_msw =
+ msm_audio_populate_upper_32_bits(
+ rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
+ afe_set_apr_msg->mem_map_handle =
+ rtac_cal[AFE_RTAC_CAL].map_data.map_handle;
+
+ apr_msg_size = sizeof(struct apr_hdr) +
+ sizeof(struct afe_port_cmd_set_param_v2);
+
+ } else {
+ struct afe_port_cmd_get_param_v2 *afe_get_apr_msg;
+
+ if (user_afe_buf.cmd_size > MAX_PAYLOAD_SIZE) {
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, user_afe_buf.cmd_size);
+ result = -EINVAL;
+ goto err;
+ }
+
+ /* Copy buffer to in-band payload */
+ afe_get_apr_msg = (struct afe_port_cmd_get_param_v2 *)
+ ((u8 *) rtac_afe_buffer +
+ sizeof(struct apr_hdr));
+ if (copy_from_user((void *)afe_get_apr_msg,
+ buf+offsetof(struct rtac_afe_user_data,
+ rtac_afe_get.cmd),
+ sizeof(struct afe_port_cmd_get_param_v2))) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+
+ afe_get_apr_msg->payload_address_lsw =
+ lower_32_bits(rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
+ afe_get_apr_msg->payload_address_msw =
+ msm_audio_populate_upper_32_bits(
+ rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
+ afe_get_apr_msg->mem_map_handle =
+ rtac_cal[AFE_RTAC_CAL].map_data.map_handle;
+ afe_get_apr_msg->payload_size -= sizeof(struct apr_hdr);
+ apr_msg_size = sizeof(struct apr_hdr) +
+ sizeof(struct afe_port_cmd_get_param_v2);
+ }
+
+ fill_afe_apr_hdr((struct apr_hdr *) rtac_afe_buffer,
+ port_index, opcode, apr_msg_size);
+
+ atomic_set(&rtac_afe_apr_data.cmd_state, 1);
+
+ pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
+ __func__, opcode,
+ &rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
+
+ result = apr_send_pkt(rtac_afe_apr_data.apr_handle,
+ (uint32_t *)rtac_afe_buffer);
+ if (result < 0) {
+ pr_err("%s: Set params failed port = 0x%x, ret = %d\n",
+ __func__, user_afe_buf.port_id, result);
+ goto err;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(rtac_afe_apr_data.cmd_wait,
+ (atomic_read(&rtac_afe_apr_data.cmd_state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: Set params timed out port = 0x%x, ret = %d\n",
+ __func__, user_afe_buf.port_id, result);
+ goto err;
+ }
+ if (atomic_read(&rtac_common.apr_err_code)) {
+ pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
+ __func__, adsp_err_get_err_str(atomic_read(
+ &rtac_common.apr_err_code)),
+ opcode);
+ result = adsp_err_get_lnx_err_code(
+ atomic_read(
+ &rtac_common.apr_err_code));
+ goto err;
+ }
+
+ if (opcode == AFE_PORT_CMD_GET_PARAM_V2) {
+ struct afe_port_param_data_v2 *get_resp;
+
+ get_resp = (struct afe_port_param_data_v2 *)
+ rtac_cal[AFE_RTAC_CAL].cal_data.kvaddr;
+
+ bytes_returned = get_resp->param_size +
+ sizeof(struct afe_port_param_data_v2);
+
+ if (bytes_returned > user_afe_buf.buf_size) {
+ pr_err("%s: user size = 0x%x, returned size = 0x%x\n",
+ __func__, user_afe_buf.buf_size,
+ bytes_returned);
+ result = -EINVAL;
+ goto err;
+ }
+
+ if (copy_to_user(buf, (void *)
+ rtac_cal[AFE_RTAC_CAL].cal_data.kvaddr,
+ bytes_returned)) {
+ pr_err("%s: Could not copy buffer to user,size = %d\n",
+ __func__, bytes_returned);
+ result = -EINVAL;
+ goto err;
+ }
+ } else {
+ bytes_returned = user_afe_buf.rtac_afe_set.cmd.payload_size;
+ }
+ mutex_unlock(&rtac_afe_apr_mutex);
+done:
+ return bytes_returned;
+err:
+ mutex_unlock(&rtac_afe_apr_mutex);
+ return result;
+}
+
+/* Voice APR */
+void rtac_set_voice_handle(u32 mode, void *handle)
+{
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&rtac_voice_apr_mutex);
+ rtac_voice_apr_data[mode].apr_handle = handle;
+ mutex_unlock(&rtac_voice_apr_mutex);
+}
+
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
+{
+ if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
+ (mode >= RTAC_VOICE_MODES))
+ return false;
+
+ pr_debug("%s\n", __func__);
+ if (payload_size == sizeof(uint32_t))
+ atomic_set(&rtac_common.apr_err_code, payload[0]);
+ else if (payload_size == (2*sizeof(uint32_t)))
+ atomic_set(&rtac_common.apr_err_code, payload[1]);
+
+ atomic_set(&rtac_voice_apr_data[mode].cmd_state, 0);
+ wake_up(&rtac_voice_apr_data[mode].cmd_wait);
+ return true;
+}
+
+int send_voice_apr(u32 mode, void *buf, u32 opcode)
+{
+ s32 result;
+ u32 user_buf_size = 0;
+ u32 bytes_returned = 0;
+ u32 payload_size;
+ u32 dest_port;
+ u32 data_size = 0;
+ struct apr_hdr voice_params;
+
+ pr_debug("%s\n", __func__);
+
+ if (rtac_cal[VOICE_RTAC_CAL].map_data.ion_handle == NULL) {
+ result = rtac_allocate_cal_buffer(VOICE_RTAC_CAL);
+ if (result < 0) {
+ pr_err("%s: allocate buffer failed!",
+ __func__);
+ goto done;
+ }
+ }
+
+ if (rtac_cal[VOICE_RTAC_CAL].map_data.map_handle == 0) {
+ result = rtac_map_cal_buffer(VOICE_RTAC_CAL);
+ if (result < 0) {
+ pr_err("%s: map buffer failed!",
+ __func__);
+ goto done;
+ }
+ }
+
+ if (copy_from_user(&user_buf_size, (void *)buf,
+ sizeof(user_buf_size))) {
+ pr_err("%s: Copy from user failed! buf = 0x%pK\n",
+ __func__, buf);
+ goto done;
+ }
+ if (user_buf_size <= 0) {
+ pr_err("%s: Invalid buffer size = %d\n",
+ __func__, user_buf_size);
+ goto done;
+ }
+
+ if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy payload size from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ if (copy_from_user(&dest_port, buf + 2 * sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy port id from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ if ((mode != RTAC_CVP) && (mode != RTAC_CVS)) {
+ pr_err("%s: Invalid Mode for APR, mode = %d\n",
+ __func__, mode);
+ goto done;
+ }
+
+ mutex_lock(&rtac_voice_apr_mutex);
+ if (rtac_voice_apr_data[mode].apr_handle == NULL) {
+ pr_err("%s: APR not initialized\n", __func__);
+ result = -EINVAL;
+ goto err;
+ }
+
+ if (opcode == VOICE_CMD_SET_PARAM) {
+ /* set payload size to in-band payload */
+ /* set data size to actual out of band payload size */
+ data_size = payload_size - 4 * sizeof(u32);
+ if (data_size > rtac_cal[VOICE_RTAC_CAL].map_data.map_size) {
+ pr_err("%s: Invalid data size = %d\n",
+ __func__, data_size);
+ result = -EINVAL;
+ goto err;
+ }
+ payload_size = 4 * sizeof(u32);
+
+ /* Copy buffer to out-of-band payload */
+ if (copy_from_user((void *)
+ rtac_cal[VOICE_RTAC_CAL].cal_data.kvaddr,
+ buf + 7 * sizeof(u32), data_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+ /* set payload size in packet */
+ rtac_voice_buffer[8] = data_size;
+ } else {
+ if (payload_size > MAX_PAYLOAD_SIZE) {
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, payload_size);
+ result = -EINVAL;
+ goto err;
+ }
+
+ /* Copy buffer to in-band payload */
+ if (copy_from_user(rtac_voice_buffer +
+ sizeof(voice_params)/sizeof(u32),
+ buf + 3 * sizeof(u32), payload_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ result = -EINVAL;
+ goto err;
+ }
+ }
+
+ /* Pack header */
+ voice_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ voice_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ payload_size);
+ voice_params.src_svc = 0;
+ voice_params.src_domain = APR_DOMAIN_APPS;
+ voice_params.src_port = get_voice_index(mode, dest_port);
+ voice_params.dest_svc = 0;
+ voice_params.dest_domain = APR_DOMAIN_MODEM;
+ voice_params.dest_port = (u16)dest_port;
+ voice_params.token = 0;
+ voice_params.opcode = opcode;
+
+ /* fill for out-of-band */
+ rtac_voice_buffer[5] = rtac_cal[VOICE_RTAC_CAL].map_data.map_handle;
+ rtac_voice_buffer[6] =
+ lower_32_bits(rtac_cal[VOICE_RTAC_CAL].cal_data.paddr);
+ rtac_voice_buffer[7] =
+ msm_audio_populate_upper_32_bits(
+ rtac_cal[VOICE_RTAC_CAL].cal_data.paddr);
+
+ memcpy(rtac_voice_buffer, &voice_params, sizeof(voice_params));
+ atomic_set(&rtac_voice_apr_data[mode].cmd_state, 1);
+
+ pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
+ __func__, opcode,
+ &rtac_cal[VOICE_RTAC_CAL].cal_data.paddr);
+
+ result = apr_send_pkt(rtac_voice_apr_data[mode].apr_handle,
+ (uint32_t *)rtac_voice_buffer);
+ if (result < 0) {
+ pr_err("%s: apr_send_pkt failed opcode = %x\n",
+ __func__, opcode);
+ goto err;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(rtac_voice_apr_data[mode].cmd_wait,
+ (atomic_read(&rtac_voice_apr_data[mode].cmd_state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: apr_send_pkt timed out opcode = %x\n",
+ __func__, opcode);
+ goto err;
+ }
+ if (atomic_read(&rtac_common.apr_err_code)) {
+ pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
+ __func__, adsp_err_get_err_str(atomic_read(
+ &rtac_common.apr_err_code)),
+ opcode);
+ result = adsp_err_get_lnx_err_code(
+ atomic_read(
+ &rtac_common.apr_err_code));
+ goto err;
+ }
+
+ if (opcode == VOICE_CMD_GET_PARAM) {
+ bytes_returned = ((u32 *)rtac_cal[VOICE_RTAC_CAL].cal_data.
+ kvaddr)[2] + 3 * sizeof(u32);
+
+ if (bytes_returned > user_buf_size) {
+ pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
+ __func__, user_buf_size, bytes_returned);
+ result = -EINVAL;
+ goto err;
+ }
+
+ if (copy_to_user(buf, (void *)
+ rtac_cal[VOICE_RTAC_CAL].cal_data.kvaddr,
+ bytes_returned)) {
+ pr_err("%s: Could not copy buffer to user, size = %d\n",
+ __func__, bytes_returned);
+ result = -EINVAL;
+ goto err;
+ }
+ } else {
+ bytes_returned = data_size;
+ }
+ mutex_unlock(&rtac_voice_apr_mutex);
+done:
+ return bytes_returned;
+err:
+ mutex_unlock(&rtac_voice_apr_mutex);
+ return result;
+}
+
+void get_rtac_adm_data(struct rtac_adm *adm_data)
+{
+ mutex_lock(&rtac_adm_mutex);
+ memcpy(adm_data, &rtac_adm_data, sizeof(struct rtac_adm));
+ mutex_unlock(&rtac_adm_mutex);
+}
+
+
+static long rtac_ioctl_shared(struct file *f,
+ unsigned int cmd, void *arg)
+{
+ int result = 0;
+
+ if (!arg) {
+ pr_err("%s: No data sent to driver!\n", __func__);
+ result = -EFAULT;
+ goto done;
+ }
+
+ switch (cmd) {
+ case AUDIO_GET_RTAC_ADM_INFO: {
+ mutex_lock(&rtac_adm_mutex);
+ if (copy_to_user((void *)arg, &rtac_adm_data,
+ sizeof(rtac_adm_data))) {
+ pr_err("%s: copy_to_user failed for AUDIO_GET_RTAC_ADM_INFO\n",
+ __func__);
+ mutex_unlock(&rtac_adm_mutex);
+ return -EFAULT;
+ }
+ result = sizeof(rtac_adm_data);
+ mutex_unlock(&rtac_adm_mutex);
+ break;
+ }
+ case AUDIO_GET_RTAC_VOICE_INFO: {
+ mutex_lock(&rtac_voice_mutex);
+ if (copy_to_user((void *)arg, &rtac_voice_data,
+ sizeof(rtac_voice_data))) {
+ pr_err("%s: copy_to_user failed for AUDIO_GET_RTAC_VOICE_INFO\n",
+ __func__);
+ mutex_unlock(&rtac_voice_mutex);
+ return -EFAULT;
+ }
+ result = sizeof(rtac_voice_data);
+ mutex_unlock(&rtac_voice_mutex);
+ break;
+ }
+
+ case AUDIO_GET_RTAC_ADM_CAL:
+ result = send_adm_apr((void *)arg, ADM_CMD_GET_PP_PARAMS_V5);
+ break;
+ case AUDIO_SET_RTAC_ADM_CAL:
+ result = send_adm_apr((void *)arg, ADM_CMD_SET_PP_PARAMS_V5);
+ break;
+ case AUDIO_GET_RTAC_ASM_CAL:
+ result = send_rtac_asm_apr((void *)arg,
+ ASM_STREAM_CMD_GET_PP_PARAMS_V2);
+ break;
+ case AUDIO_SET_RTAC_ASM_CAL:
+ result = send_rtac_asm_apr((void *)arg,
+ ASM_STREAM_CMD_SET_PP_PARAMS_V2);
+ break;
+ case AUDIO_GET_RTAC_CVS_CAL:
+ result = send_voice_apr(RTAC_CVS, (void *)arg,
+ VOICE_CMD_GET_PARAM);
+ break;
+ case AUDIO_SET_RTAC_CVS_CAL:
+ result = send_voice_apr(RTAC_CVS, (void *)arg,
+ VOICE_CMD_SET_PARAM);
+ break;
+ case AUDIO_GET_RTAC_CVP_CAL:
+ result = send_voice_apr(RTAC_CVP, (void *)arg,
+ VOICE_CMD_GET_PARAM);
+ break;
+ case AUDIO_SET_RTAC_CVP_CAL:
+ result = send_voice_apr(RTAC_CVP, (void *)arg,
+ VOICE_CMD_SET_PARAM);
+ break;
+ case AUDIO_GET_RTAC_AFE_CAL:
+ result = send_rtac_afe_apr((void *)arg,
+ AFE_PORT_CMD_GET_PARAM_V2);
+ break;
+ case AUDIO_SET_RTAC_AFE_CAL:
+ result = send_rtac_afe_apr((void *)arg,
+ AFE_PORT_CMD_SET_PARAM_V2);
+ break;
+ default:
+ pr_err("%s: Invalid IOCTL, command = %d!\n",
+ __func__, cmd);
+ result = -EINVAL;
+ }
+done:
+ return result;
+}
+
+static long rtac_ioctl(struct file *f,
+ unsigned int cmd, unsigned long arg)
+{
+ int result = 0;
+
+ if (!arg) {
+ pr_err("%s: No data sent to driver!\n", __func__);
+ result = -EFAULT;
+ } else {
+ result = rtac_ioctl_shared(f, cmd, (void __user *)arg);
+ }
+
+ return result;
+}
+
+#ifdef CONFIG_COMPAT
+#define AUDIO_GET_RTAC_ADM_INFO_32 _IOR(CAL_IOCTL_MAGIC, 207, compat_uptr_t)
+#define AUDIO_GET_RTAC_VOICE_INFO_32 _IOR(CAL_IOCTL_MAGIC, 208, compat_uptr_t)
+#define AUDIO_GET_RTAC_ADM_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 209, compat_uptr_t)
+#define AUDIO_SET_RTAC_ADM_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 210, compat_uptr_t)
+#define AUDIO_GET_RTAC_ASM_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 211, compat_uptr_t)
+#define AUDIO_SET_RTAC_ASM_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 212, compat_uptr_t)
+#define AUDIO_GET_RTAC_CVS_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 213, compat_uptr_t)
+#define AUDIO_SET_RTAC_CVS_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 214, compat_uptr_t)
+#define AUDIO_GET_RTAC_CVP_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 215, compat_uptr_t)
+#define AUDIO_SET_RTAC_CVP_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 216, compat_uptr_t)
+#define AUDIO_GET_RTAC_AFE_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 217, compat_uptr_t)
+#define AUDIO_SET_RTAC_AFE_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 218, compat_uptr_t)
+
+static long rtac_compat_ioctl(struct file *f,
+ unsigned int cmd, unsigned long arg)
+{
+ int result = 0;
+
+ if (!arg) {
+ pr_err("%s: No data sent to driver!\n", __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ switch (cmd) {
+ case AUDIO_GET_RTAC_ADM_INFO_32:
+ cmd = AUDIO_GET_RTAC_ADM_INFO;
+ goto process;
+ case AUDIO_GET_RTAC_VOICE_INFO_32:
+ cmd = AUDIO_GET_RTAC_VOICE_INFO;
+ goto process;
+ case AUDIO_GET_RTAC_AFE_CAL_32:
+ cmd = AUDIO_GET_RTAC_AFE_CAL;
+ goto process;
+ case AUDIO_SET_RTAC_AFE_CAL_32:
+ cmd = AUDIO_SET_RTAC_AFE_CAL;
+ goto process;
+ case AUDIO_GET_RTAC_ADM_CAL_32:
+ cmd = AUDIO_GET_RTAC_ADM_CAL;
+ goto process;
+ case AUDIO_SET_RTAC_ADM_CAL_32:
+ cmd = AUDIO_SET_RTAC_ADM_CAL;
+ goto process;
+ case AUDIO_GET_RTAC_ASM_CAL_32:
+ cmd = AUDIO_GET_RTAC_ASM_CAL;
+ goto process;
+ case AUDIO_SET_RTAC_ASM_CAL_32:
+ cmd = AUDIO_SET_RTAC_ASM_CAL;
+ goto process;
+ case AUDIO_GET_RTAC_CVS_CAL_32:
+ cmd = AUDIO_GET_RTAC_CVS_CAL;
+ goto process;
+ case AUDIO_SET_RTAC_CVS_CAL_32:
+ cmd = AUDIO_SET_RTAC_CVS_CAL;
+ goto process;
+ case AUDIO_GET_RTAC_CVP_CAL_32:
+ cmd = AUDIO_GET_RTAC_CVP_CAL;
+ goto process;
+ case AUDIO_SET_RTAC_CVP_CAL_32:
+ cmd = AUDIO_SET_RTAC_CVP_CAL;
+process:
+ result = rtac_ioctl_shared(f, cmd, compat_ptr(arg));
+ break;
+ default:
+ result = -EINVAL;
+ pr_err("%s: Invalid IOCTL, command = %d!\n",
+ __func__, cmd);
+ break;
+ }
+done:
+ return result;
+}
+#else
+#define rtac_compat_ioctl NULL
+#endif
+
+static const struct file_operations rtac_fops = {
+ .owner = THIS_MODULE,
+ .open = rtac_open,
+ .release = rtac_release,
+ .unlocked_ioctl = rtac_ioctl,
+ .compat_ioctl = rtac_compat_ioctl,
+};
+
+struct miscdevice rtac_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_rtac",
+ .fops = &rtac_fops,
+};
+
+static int __init rtac_init(void)
+{
+ int i = 0;
+
+ /* Driver */
+ atomic_set(&rtac_common.usage_count, 0);
+ atomic_set(&rtac_common.apr_err_code, 0);
+
+ /* ADM */
+ memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
+ rtac_adm_apr_data.apr_handle = NULL;
+ atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+ init_waitqueue_head(&rtac_adm_apr_data.cmd_wait);
+ mutex_init(&rtac_adm_mutex);
+ mutex_init(&rtac_adm_apr_mutex);
+
+ rtac_adm_buffer = kzalloc(
+ rtac_cal[ADM_RTAC_CAL].map_data.map_size, GFP_KERNEL);
+ if (rtac_adm_buffer == NULL)
+ goto nomem;
+
+ /* ASM */
+ for (i = 0; i < ASM_ACTIVE_STREAMS_ALLOWED+1; i++) {
+ rtac_asm_apr_data[i].apr_handle = NULL;
+ atomic_set(&rtac_asm_apr_data[i].cmd_state, 0);
+ init_waitqueue_head(&rtac_asm_apr_data[i].cmd_wait);
+ }
+ mutex_init(&rtac_asm_apr_mutex);
+
+ rtac_asm_buffer = kzalloc(
+ rtac_cal[ASM_RTAC_CAL].map_data.map_size, GFP_KERNEL);
+ if (rtac_asm_buffer == NULL) {
+ kzfree(rtac_adm_buffer);
+ goto nomem;
+ }
+
+ /* AFE */
+ rtac_afe_apr_data.apr_handle = NULL;
+ atomic_set(&rtac_afe_apr_data.cmd_state, 0);
+ init_waitqueue_head(&rtac_afe_apr_data.cmd_wait);
+ mutex_init(&rtac_afe_apr_mutex);
+
+ rtac_afe_buffer = kzalloc(
+ rtac_cal[AFE_RTAC_CAL].map_data.map_size, GFP_KERNEL);
+ if (rtac_afe_buffer == NULL) {
+ kzfree(rtac_adm_buffer);
+ kzfree(rtac_asm_buffer);
+ goto nomem;
+ }
+
+ /* Voice */
+ memset(&rtac_voice_data, 0, sizeof(rtac_voice_data));
+ for (i = 0; i < RTAC_VOICE_MODES; i++) {
+ rtac_voice_apr_data[i].apr_handle = NULL;
+ atomic_set(&rtac_voice_apr_data[i].cmd_state, 0);
+ init_waitqueue_head(&rtac_voice_apr_data[i].cmd_wait);
+ }
+ mutex_init(&rtac_voice_mutex);
+ mutex_init(&rtac_voice_apr_mutex);
+
+ rtac_voice_buffer = kzalloc(
+ rtac_cal[VOICE_RTAC_CAL].map_data.map_size, GFP_KERNEL);
+ if (rtac_voice_buffer == NULL) {
+ kzfree(rtac_adm_buffer);
+ kzfree(rtac_asm_buffer);
+ kzfree(rtac_afe_buffer);
+ goto nomem;
+ }
+
+ return misc_register(&rtac_misc);
+nomem:
+ return -ENOMEM;
+}
+
+module_init(rtac_init);
+
+MODULE_DESCRIPTION("SoC QDSP6v2 Real-Time Audio Calibration driver");
+MODULE_LICENSE("GPL v2");