Merge "USB: gadget: midi: Replace snd_card_free with snd_card_free_closed" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt b/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt
new file mode 100644
index 0000000..0a5c0b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt
@@ -0,0 +1,55 @@
+Qualcomm Technologies, Inc. QTI Mailbox Protocol
+
+QMP Driver
+===================
+
+Required properties:
+- compatible : should be "qcom,qmp-mbox".
+- label : the name of the remote proc this link connects to.
+- reg : The location and size of shared memory.
+ The irq register base address for triggering interrupts.
+- reg-names : "msgram" - string to identify the shared memory region.
+ "irq-reg-base" - string to identify the irq register region.
+- qcom,irq-mask : the bitmask to trigger an interrupt.
+- interrupt : the receiving interrupt line.
+- mbox-desc-offset : offset of mailbox descriptor from start of the msgram.
+- #mbox-cells: Common mailbox binding property to identify the number of cells
+ required for the mailbox specifier, should be 1.
+
+Optional properties:
+- mbox-offset : offset of the mcore mailbox from the offset of msgram. If this
+ property is not used, qmp will use the configuration
+ provided by the ucore.
+- mbox-size : size of the mcore mailbox. If this property is not used, qmp will
+ use the configuration provided by the ucore.
+
+Example:
+ qmp_aop: qcom,qmp-aop {
+ compatible = "qcom,qmp-mbox";
+ label = "aop";
+ reg = <0xc300000 0x100000>,
+ <0x1799000C 0x4>;
+ reg-names = "msgram", "irq-reg-base";
+ qcom,irq-mask = <0x1>;
+ interrupt = <0 389 1>;
+ mbox-desc-offset = <0x100>;
+ mbox-offset = <0x500>;
+ mbox-size = <0x400>;
+ #mbox-cells = <1>;
+ };
+
+Mailbox Client
+==============
+"mboxes" and the optional "mbox-names" (please see
+Documentation/devicetree/bindings/mailbox/mailbox.txt for details). Each value
+of the mboxes property should contain a phandle to the mailbox controller
+device node and second argument is the channel index. It must be 0 (qmp
+supports only one channel).The equivalent "mbox-names" property value can be
+used to give a name to the communication channel to be used by the client user.
+
+Example:
+ qmp-client {
+ compatible = "qcom,qmp-client";
+ mbox-names = "aop";
+ mboxes = <&qmp_aop 0>,
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
new file mode 100644
index 0000000..f214c58
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
@@ -0,0 +1,33 @@
+Qualcomm Technologies, Inc. Graphics Clock & Reset Controller Binding
+--------------------------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,gpucc-sdm845",
+ "qcom,gfxcc-sdm845"
+
+- reg : shall contain base register offset and size.
+- #clock-cells : shall contain 1.
+- #reset-cells : shall contain 1.
+- #vdd_<rail>-supply : The logic rail supply.
+
+Optional properties :
+- #power-domain-cells : shall contain 1.
+
+Example:
+ clock_gfx: qcom,gfxcc@5090000 {
+ compatible = "qcom,gfxcc-sdm845";
+ reg = <0x5090000 0x9000>;
+ vdd_gfx-supply = <&pm8005_s1_level>;
+ vdd_mx-supply = <&pm8998_s6_level>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_gpucc: qcom,gpucc@5090000 {
+ compatible = "qcom,gpucc-sdm845";
+ reg = <0x5090000 0x9000>;
+ vdd_cx-supply = <&pm8998_s9_level>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt b/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
index 01b2424..67dc991 100644
--- a/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
+++ b/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
@@ -10,11 +10,20 @@
- qcom,core-dev-table: A mapping table of core frequency to a required bandwidth vote at the
given core frequency.
+Optional properties:
+- qcom,cachemiss-ev: The cache miss event that this monitor is supposed to measure.
+ Defaults to 0x17 if not specified.
+- qcom,inst-ev: The instruction count event that this monitor is supposed to measure.
+ Defaults to 0x08 if not specified.
+
+
Example:
qcom,arm-memlat-mon {
compatible = "qcom,arm-memlat-mon";
qcom,cpulist = <&CPU0 &CPU1>;
qcom,target-dev = <&memlat0>;
+ qcom,cachemiss-ev = <0x2A>;
+ qcom,inst-ev = <0x08>;
qcom,core-dev-table =
< 300000 1525>,
< 499200 3143>,
diff --git a/Documentation/devicetree/bindings/mailbox/qcom-tcs.txt b/Documentation/devicetree/bindings/mailbox/qcom-tcs.txt
index 4ef34bf..318ef30 100644
--- a/Documentation/devicetree/bindings/mailbox/qcom-tcs.txt
+++ b/Documentation/devicetree/bindings/mailbox/qcom-tcs.txt
@@ -81,6 +81,10 @@
ACTIVE_TCS
CONTROL_TCS
- Cell #2 (Number of TCS): <u32>
+- label:
+ Usage: optional
+ Value type: <string>
+ Definition: Name for the mailbox. The name would be used in trace logs.
EXAMPLE 1:
@@ -92,6 +96,7 @@
apps_rsc: mailbox@179e000 {
compatible = "qcom,tcs_drv";
+ label = "apps_rsc";
reg = <0x179E0000 0x10000>, <0x179E0D00 0x3000>;
interrupts = <0 5 0>;
#mbox-cells = <1>;
@@ -110,17 +115,18 @@
Second tuple: 0xAF20000 + 0x1C00
disp_rsc: mailbox@af20000 {
- status = "disabled";
- compatible = "qcom,tcs-drv";
- reg = <0xAF20000 0x10000>, <0xAF21C00 0x3000>;
- interrupts = <0 129 0>;
- #mbox-cells = <1>;
- qcom,drv-id = <0>;
- qcom,tcs-config = <SLEEP_TCS 1>,
- <WAKE_TCS 1>,
- <ACTIVE_TCS 0>,
- <CONTROL_TCS 1>;
- };
+ status = "disabled";
+ label = "disp_rsc";
+ compatible = "qcom,tcs-drv";
+ reg = <0xAF20000 0x10000>, <0xAF21C00 0x3000>;
+ interrupts = <0 129 0>;
+ #mbox-cells = <1>;
+ qcom,drv-id = <0>;
+ qcom,tcs-config = <SLEEP_TCS 1>,
+ <WAKE_TCS 1>,
+ <ACTIVE_TCS 0>,
+ <CONTROL_TCS 1>;
+ };
CLIENT:
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,lpi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,lpi-pinctrl.txt
new file mode 100644
index 0000000..57510ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,lpi-pinctrl.txt
@@ -0,0 +1,154 @@
+Qualcomm Technologies, Inc. LPI GPIO controller driver
+
+This DT bindings describes the GPIO controller driver
+being added for supporting LPI (Low Power Island) TLMM
+from QTI chipsets.
+
+Following properties are for LPI GPIO controller device main node.
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qcom,lpi-pinctrl"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Register base of the GPIO controller and length.
+
+- qcom,num-gpios:
+ Usage: required
+ Value type: <u32>
+ Definition: Number of GPIOs supported by the controller.
+
+- gpio-controller:
+ Usage: required
+ Value type: <none>
+ Definition: Used to mark the device node as a GPIO controller.
+
+- #gpio-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: Must be 2;
+ The first cell will be used to define gpio number and the
+ second denotes the flags for this gpio.
+
+Please refer to ../gpio/gpio.txt for general description of GPIO bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin or a list of pins. This configuration can include the
+mux function to select on those pin(s), and various pin configuration
+parameters, as listed below.
+
+SUBNODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+ Usage: required
+ Value type: <string-array>
+ Definition: List of gpio pins affected by the properties specified in
+ this subnode. Valid pins are: gpio0-gpio31 for LPI.
+
+- function:
+ Usage: required
+ Value type: <string>
+ Definition: Specify the alternative function to be configured for the
+ specified pins. Valid values are:
+ "gpio",
+ "func1",
+ "func2",
+ "func3",
+ "func4",
+ "func5"
+
+- bias-disable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configured as no pull.
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configured as pull down.
+
+- bias-bus-hold:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configured as bus-keeper mode.
+
+- bias-pull-up:
+ Usage: optional
+ Value type: <empty>
+ Definition: The specified pins should be configured as pull up.
+
+- input-enable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are put in input mode.
+
+- output-high:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ high.
+
+- output-low:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ low.
+
+- qcom,drive-strength:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the drive strength for the specified pins.
+
+Example:
+
+ lpi_tlmm: lpi_pinctrl@152c000 {
+ compatible = "qcom,lpi-pinctrl";
+ qcom,num-gpios = <32>;
+ reg = <0x152c000 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ hph_comp_active: hph_comp_active {
+ mux {
+ pins = "gpio22";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio22";
+ output-high;
+ qcom,drive-strength = <8>;
+ };
+ };
+
+ hph_comp_sleep: hph_comp_sleep {
+ mux {
+ pins = "gpio22";
+ function = "func1";
+ };
+
+ config {
+ pins = "gpio22";
+ qcom,drive-strength = <2>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 3ff3b2f..e0ab31f 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -181,6 +181,11 @@
- compatible : "qcom,msm-pcm-loopback"
+Optional properties:
+
+ - qcom,msm-pcm-loopback-low-latency : Flag indicating whether
+ the device node is of type low latency.
+
* msm-dai-q6
[First Level Nodes]
@@ -365,6 +370,10 @@
- compatible : "qcom,msm-cdc-pinctrl"
+Optional properties:
+ - qcom,lpi-gpios : This boolean property is added if GPIOs are under
+ LPI TLMM.
+
* msm-dai-slim
Required properties:
@@ -421,6 +430,11 @@
qcom,msm-pcm-low-latency;
};
+ qcom,msm-pcm-loopback-low-latency {
+ compatible = "qcom,msm-pcm-loopback";
+ qcom,msm-pcm-loopback-low-latency;
+ };
+
qcom,msm-pcm-routing {
compatible = "qcom,msm-pcm-routing";
};
@@ -829,17 +843,6 @@
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.
@@ -877,6 +880,19 @@
codec dai names should match to that of the phandle order given
in "asoc-codec".
Optional properties:
+- reg : Offset and length of the register region(s) for MI2S/PCM MUX.
+ Not applicable for all targets.
+- reg-names : Register region name(s) referenced in reg above.
+ Not applicable for all targets.
+ 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,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.
@@ -1510,10 +1526,10 @@
asoc-wsa-codec-prefixes = "SpkrMono";
};
-* MSMFALCON ASoC Machine driver
+* SDM660 ASoC Machine driver
Required properties:
-- compatible : "qcom,msmfalcon-asoc-snd"
+- compatible : "qcom,sdm660-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.
@@ -1539,6 +1555,7 @@
capacitor mode.
- qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external
capacitor mode.
+- qcom,wsa-disable : Boolean. Disables WSA speaker dailinks from sound node.
- 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.
@@ -1559,11 +1576,19 @@
- 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,cdc-pdm-gpios : phandle for pdm gpios.
+- qcom,cdc-comp-gpios : phandle for compander gpios.
+- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios.
+- qcom,cdc-sdw-gpios : phandle for soundwire clk and data gpios.
+- qcom,msm-mbhc-moist-cfg: This property is used to set moisture detection
+ threshold values for different codecs. First parameter is V(voltage)
+ second one is i(current), third one is r (resistance). Depending on the
+ codec set corresponding element in array and set others to 0.
Example:
sound {
- compatible = "qcom,msmfalcon-asoc-snd";
- qcom,model = "msmfalcon-snd-card";
+ compatible = "qcom,sdm660-asoc-snd";
+ qcom,model = "sdm660-snd-card";
qcom,msm-mclk-freq = <9600000>;
qcom,msm-mbhc-hphl-swh = <0>;
qcom,msm-mbhc-gnd-swh = <0>;
@@ -1579,24 +1604,11 @@
"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>;
+ qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>;
+ qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
+ qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
+ qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>;
asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
<&afe>, <&lsm>, <&routing>, <&lpa>;
@@ -1681,6 +1693,10 @@
- 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.
+- qcom,msm-mi2s-ext-mclk: This property is used to inform machine driver
+ if MCLK from MSM is used for any external audio connections. 1 means used
+ as external mclk source and 0 indicate not used. The first entry is
+ primary mclk; the second entry is secondary mclk, 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
@@ -1721,6 +1737,7 @@
qcom,mi2s-audio-intf;
qcom,auxpcm-audio-intf;
qcom,msm-mi2s-master = <1>, <0>, <1>, <1>;
+ qcom,msm-mi2s-ext-mclk = <1>, <1>, <0>, <1>;
reg = <0x1711a000 0x4>,
<0x1711b000 0x4>,
<0x1711c000 0x4>,
@@ -1732,6 +1749,8 @@
qcom,msm-mclk-freq = <9600000>;
qcom,msm-mbhc-hphl-swh = <0>;
qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,wsa-disable;
+ qcom,msm-mbhc-moist-cfg = <1>, <3>, <0>;
qcom,msm-hs-micbias-type = "internal";
qcom,msm-micbias1-ext-cap;
qcom,audio-routing =
@@ -2020,13 +2039,15 @@
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>, <&compr>;
+ <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&loopback1>;
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";
+ "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
<&dai_mi2s>, <&dai_mi2s_quat>,
<&afe_pcm_rx>, <&afe_pcm_tx>,
@@ -2060,11 +2081,11 @@
asoc-codec-names = "msm-stub-codec.1";
};
-* MSMFALCON ASoC Slimbus Machine driver
+* SDM660 ASoC Slimbus Machine driver
Required properties:
-- compatible : "qcom,msmfalcon-asoc-snd-tasha" for tasha codec,
- "qcom,msmfalcon-asoc-snd-tavil" for tavil codec.
+- compatible : "qcom,sdm660-asoc-snd-tasha" for tasha codec,
+ "qcom,sdm660-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.
@@ -2104,8 +2125,8 @@
Example:
sound-9335 {
- compatible = "qcom,msmfalcon-asoc-snd-tasha";
- qcom,model = "msmfalcon-tasha-snd-card";
+ compatible = "qcom,sdm660-asoc-snd-tasha";
+ qcom,model = "sdm660-tasha-snd-card";
qcom,audio-routing =
"RX_BIAS", "MCLK",
@@ -2233,6 +2254,11 @@
- 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
+- qcom,msm-mbhc-usbc-audio-supported : Property to specify if analog audio feature is
+ enabled or not.
+- qcom,usbc-analog-en1_gpio : EN1 GPIO to enable USB type-C analog audio
+- qcom,usbc-analog-en2_n_gpio : EN2 GPIO to enable USB type-C analog audio
+- qcom,usbc-analog-force_detect_gpio : Force detect GPIO to enable USB type-C analog audio
Example:
@@ -2306,6 +2332,10 @@
<&wsa881x_213>, <&wsa881x_214>;
qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
"SpkrRight", "SpkrLeft";
+ qcom,msm-mbhc-usbc-audio-supported = <1>;
+ qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>;
+ qcom,usbc-analog-en2_n_gpio = <&wcd_usbc_analog_en2n_gpio>;
+ qcom,usbc-analog-force_detect_gpio = <&wcd_usbc_analog_f_gpio>;
};
* MSMSTUB ASoC Machine driver
diff --git a/Documentation/devicetree/bindings/sound/wcd_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt
index c0a7a24..0df9417 100644
--- a/Documentation/devicetree/bindings/sound/wcd_codec.txt
+++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt
@@ -384,8 +384,8 @@
Tombak audio CODEC in SPMI mode
- compatible = "qcom,msm-codec-core",
- - compatible = "qcom,pmic-codec-digital"
- - compatible = "qcom,pmic-codec-analog"
+ - compatible = "qcom,msm-digital-codec"
+ - compatible = "qcom,pmic-analog-codec"
- reg: represents the slave base address provided to the peripheral.
- interrupt-parent : The parent interrupt controller.
- interrupts: List of interrupts in given SPMI peripheral.
@@ -438,19 +438,14 @@
Example:
-msm_dig_codec: qcom,msm-int-codec {
- compatible = "qcom,msm_int_core_codec";
- qcom,dig-cdc-base-addr = <0xc0f0000>;
+msm_digital_codec: msm-dig-codec@c0f0000 {
+ compatible = "qcom,msm-digital-codec";
+ reg = <0xc0f0000 0x0>;
};
-msm8x16_wcd_codec@f100 {
- compatible = "qcom,msm_int_pmic_analog_codec";
- reg = <0xf100 0x100>;
-};
-
-msm8x16_wcd_codec@f000{
- compatible = "qcom,msm_int_pmic_digital_codec";
- reg = <0xf000 0x100>;
+pmic_analog_codec: analog-codec@f000 {
+ compatible = "qcom,pmic-analog-codec";
+ reg = <0xf000 0x200>;
interrupt-parent = <&spmi_bus>;
interrupts = <0x1 0xf0 0x0>,
<0x1 0xf0 0x1>,
@@ -501,7 +496,41 @@
"cdc-vdda-cp";
qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
- qcom,dig-cdc-base-addr = <0xc0f0000>;
+};
+
+MSM based Soundwire audio codec
+
+Required properties:
+ - compatible = "qcom,msm-sdw-codec";
+ - reg: Specifies the soundwire codec base address for MSM digital
+ soundwire core registers.
+ - interrupts: Specifies the soundwire master interrupt number to Apps processor.
+ - interrupt-names: Specify the interrupt name from soundwire master.
+ - swr_master: This node is added as a child of MSM soundwire codec
+ and uses already existing driver soundwire master.
+ And there is/are subchild node(s) under soundwire master
+ which is also existing driver WSA881x that represents
+ soundwire slave devices.
+
+Example:
+
+msm_sdw_codec: qcom,msm-sdw-codec@152c1000 {
+ compatible = "qcom,msm-sdw-codec";
+ reg = <0x152c1000 0x0>;
+ interrupts = <0 161 0>;
+ interrupt-names = "swr_master_irq";
+
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_1: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x20170212>;
+ qcom,spkr-sd-n-gpio = <&tlmm 80 0>;
+ };
+ };
};
Tasha audio CODEC in I2C mode
diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt
index 88b6ea1..2cb5419 100644
--- a/Documentation/devicetree/bindings/thermal/thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/thermal.txt
@@ -168,6 +168,14 @@
by means of sensor ID. Additional coefficients are
interpreted as constant offset.
+- thermal-governor: Thermal governor to be used for this thermal zone.
+ Expected values are:
+ "step_wise": Use step wise governor.
+ "fair_share": Use fair share governor.
+ "user_space": Use user space governor.
+ "power_allocator": Use power allocator governor.
+ Type: string
+
- sustainable-power: An estimate of the sustainable power (in mW) that the
Type: unsigned thermal zone can dissipate at the desired
Size: one cell control temperature. For reference, the
@@ -175,6 +183,11 @@
2000mW, while on a 10'' tablet is around
4500mW.
+- tracks-low: Indicates that the temperature sensor tracks the low
+ Type: bool thresholds, so the governors may mitigate by ensuring
+ timing closures and other low temperature operating
+ issues.
+
Note: The delay properties are bound to the maximum dT/dt (temperature
derivative over time) in two situations for a thermal zone:
(i) - when passive cooling is activated (polling-delay-passive); and
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
new file mode 100644
index 0000000..1065456
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -0,0 +1,54 @@
+Qualcomm Technologies, Inc. TSENS driver
+
+Temperature sensor (TSENS) driver supports reading temperature from sensors
+across the MSM. The driver defaults to support a 12 bit ADC.
+
+The driver uses the Thermal sysfs framework to provide thermal
+clients the ability to read from supported on-die temperature sensors,
+set temperature thresholds for cool/warm thresholds and receive notification
+on temperature threshold events.
+
+TSENS node
+
+Required properties:
+- compatible : should be "qcom,msm8996-tsens" for 8996 TSENS driver.
+ should be "qcom,msm8953-tsens" for 8953 TSENS driver.
+ should be "qcom,msm8998-tsens" for 8998 TSENS driver.
+ should be "qcom,msmhamster-tsens" for hamster TSENS driver.
+ should be "qcom,sdm660-tsens" for 660 TSENS driver.
+ should be "qcom,sdm630-tsens" for 630 TSENS driver.
+ should be "qcom,sdm845-tsens" for SDM845 TSENS driver.
+ The compatible property is used to identify the respective controller to use
+ for the corresponding SoC.
+- reg : offset and length of the TSENS registers with associated property in reg-names
+ as "tsens_physical" for TSENS TM physical address region.
+- reg-names : resource names used for the physical address of the TSENS
+ registers. Should be "tsens_physical" for physical address of the TSENS.
+- interrupts : TSENS interrupt to notify Upper/Lower and Critical temperature threshold.
+- interrupt-names: Should be "tsens-upper-lower" for temperature threshold.
+ Add "tsens-critical" for Critical temperature threshold notification
+ in addition to "tsens-upper-lower" for 8996 TSENS since
+ 8996 supports Upper/Lower and Critical temperature threshold.
+- qcom,sensors : Total number of available Temperature sensors for TSENS.
+
+Optional properties:
+- qcom,sensor-id : If the flag is present map the TSENS sensors based on the
+ remote sensors that are enabled in HW. Ensure the mapping is not
+ more than the number of supported sensors.
+- qcom,client-id : If the flag is present use it to identify the SW ID mapping
+ used to associate it with the controller and the physical sensor
+ mapping within the controller. The physical sensor mapping within
+ each controller is done using the qcom,sensor-id property. If the
+ property is not present the SW ID mapping with default from 0 to
+ total number of supported sensors with each controller instance.
+
+Example:
+
+tsens@fc4a8000 {
+ compatible = "qcom,msm-tsens";
+ reg = <0xfc4a8000 0x2000>;,
+ reg-names = "tsens_physical";
+ interrupts = <0 184 0>;
+ interrupt-names = "tsens-upper-lower";
+ qcom,sensors = <11>;
+};
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 404a0e9..379dc99 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -74,3 +74,13 @@
"raw_rpmb_size_mult" is a mutliple of 128kB block.
RPMB size in byte is calculated by using the following equation:
RPMB partition size = 128kB x raw_rpmb_size_mult
+
+SD/MMC/SDIO Clock Gating Attribute
+==================================
+
+Read and write access is provided to following attribute.
+This attribute appears only if CONFIG_MMC_CLKGATE is enabled.
+
+ clkgate_delay Tune the clock gating delay with desired value in milliseconds.
+
+echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
diff --git a/Makefile b/Makefile
index d8f21b3..e70a1eb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 18
+SUBLEVEL = 20
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 7173ec9..8158c873 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -266,7 +266,7 @@
};
usb1: ohci@00400000 {
- compatible = "atmel,sama5d2-ohci", "usb-ohci";
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00400000 0x100000>;
interrupts = <41 IRQ_TYPE_LEVEL_HIGH 2>;
clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index b4332b7..31dde8b 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -289,6 +289,22 @@
at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
}
+static void sama5d3_ddr_standby(void)
+{
+ u32 lpr0;
+ u32 saved_lpr0;
+
+ saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
+ lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB;
+ lpr0 |= AT91_DDRSDRC_LPCB_POWER_DOWN;
+
+ at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
+
+ cpu_do_idle();
+
+ at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
+}
+
/* We manage both DDRAM/SDRAM controllers, we need more than one value to
* remember.
*/
@@ -323,7 +339,7 @@
{ .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
{ .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
{ .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
- { .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby },
+ { .compatible = "atmel,sama5d3-ddramc", .data = sama5d3_ddr_standby },
{ /*sentinel*/ }
};
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index d0d096e..ba0695b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1079,6 +1079,26 @@
DTBs to be built by default (instead of a standalone Image.gz.)
The image will built in arch/arm64/boot/Image.gz-dtb
+choice
+ prompt "Appended DTB Kernel Image name"
+ depends on BUILD_ARM64_APPENDED_DTB_IMAGE
+ help
+ Enabling this option will cause a specific kernel image Image or
+ Image.gz to be used for final image creation.
+ The image will built in arch/arm64/boot/IMAGE-NAME-dtb
+
+ config IMG_GZ_DTB
+ bool "Image.gz-dtb"
+ config IMG_DTB
+ bool "Image-dtb"
+endchoice
+
+config BUILD_ARM64_APPENDED_KERNEL_IMAGE_NAME
+ string
+ depends on BUILD_ARM64_APPENDED_DTB_IMAGE
+ default "Image.gz-dtb" if IMG_GZ_DTB
+ default "Image-dtb" if IMG_DTB
+
config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES
string "Default dtb names"
depends on BUILD_ARM64_APPENDED_DTB_IMAGE
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index f7a21a6..445aeb6 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -120,7 +120,7 @@
This enables support for the ARMv8 based Qualcomm chipsets.
config ARCH_SDM845
- bool "Enable Support for Qualcomm SDM845"
+ bool "Enable Support for Qualcomm Technologies Inc. SDM845"
depends on ARCH_QCOM
select COMMON_CLK_QCOM
select QCOM_GDSC
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index bba8d2c..13a64c9 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -96,7 +96,7 @@
# Default target when executing plain make
ifeq ($(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE),y)
-KBUILD_IMAGE := Image.gz-dtb
+KBUILD_IMAGE := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_KERNEL_IMAGE_NAME))
else
KBUILD_IMAGE := Image.gz
endif
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 3eea0af..c32324f 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -9,7 +9,9 @@
sdm845-v2-rumi.dtb \
sdm845-v2-mtp.dtb \
sdm845-v2-cdp.dtb \
- sdm845-qrd.dtb
+ sdm845-qrd.dtb \
+ sdm845-4k-panel-mtp.dtb \
+ sdm845-4k-panel-cdp.dtb
dtb-$(CONFIG_ARCH_SDM830) += sdm830-sim.dtb \
sdm830-rumi.dtb \
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
new file mode 100644
index 0000000..d5646bf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm845.dtsi"
+#include "sdm845-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel CDP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,board-id = <1 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
new file mode 100644
index 0000000..d641276
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm845.dtsi"
+#include "sdm845-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,board-id = <8 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index 2d2b264..4088f3b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -34,12 +34,27 @@
mbox-names = "apps_rsc", "disp_rsc";
mboxes = <&apps_rsc 0 &disp_rsc 0>;
+ /*RSCs*/
+ rsc_apps: rsc-apps {
+ cell-id = <MSM_BUS_RSC_APPS>;
+ label = "apps_rsc";
+ qcom,rsc-dev;
+ qcom,req_state = <2>;
+ };
+
+ rsc_disp: rsc-disp {
+ cell-id = <MSM_BUS_RSC_DISP>;
+ label = "disp_rsc";
+ qcom,rsc-dev;
+ qcom,req_state = <3>;
+ };
+
/*BCMs*/
bcm_acv: bcm-acv {
cell-id = <MSM_BUS_BCM_ACV>;
label = "ACV";
qcom,bcm-name = "ACV";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -47,7 +62,7 @@
cell-id = <MSM_BUS_BCM_ALC>;
label = "ALC";
qcom,bcm-name = "ALC";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -55,7 +70,7 @@
cell-id = <MSM_BUS_BCM_MC0>;
label = "MC0";
qcom,bcm-name = "MC0";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -63,7 +78,7 @@
cell-id = <MSM_BUS_BCM_SH0>;
label = "SH0";
qcom,bcm-name = "SH0";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -71,7 +86,7 @@
cell-id = <MSM_BUS_BCM_MM0>;
label = "MM0";
qcom,bcm-name = "MM0";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -79,7 +94,7 @@
cell-id = <MSM_BUS_BCM_SH1>;
label = "SH1";
qcom,bcm-name = "SH1";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -87,7 +102,7 @@
cell-id = <MSM_BUS_BCM_MM1>;
label = "MM1";
qcom,bcm-name = "MM1";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -95,7 +110,7 @@
cell-id = <MSM_BUS_BCM_SH2>;
label = "SH2";
qcom,bcm-name = "SH2";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -103,7 +118,7 @@
cell-id = <MSM_BUS_BCM_MM2>;
label = "MM2";
qcom,bcm-name = "MM2";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -111,7 +126,7 @@
cell-id = <MSM_BUS_BCM_SH3>;
label = "SH3";
qcom,bcm-name = "SH3";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -119,7 +134,7 @@
cell-id = <MSM_BUS_BCM_MM3>;
label = "MM3";
qcom,bcm-name = "MM3";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -127,7 +142,7 @@
cell-id = <MSM_BUS_BCM_SH4>;
label = "SH4";
qcom,bcm-name = "SH4";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -135,7 +150,7 @@
cell-id = <MSM_BUS_BCM_SH5>;
label = "SH5";
qcom,bcm-name = "SH5";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -143,7 +158,7 @@
cell-id = <MSM_BUS_BCM_MM5>;
label = "MM5";
qcom,bcm-name = "MM5";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -151,7 +166,7 @@
cell-id = <MSM_BUS_BCM_SN0>;
label = "SN0";
qcom,bcm-name = "SN0";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -159,7 +174,7 @@
cell-id = <MSM_BUS_BCM_CE0>;
label = "CE0";
qcom,bcm-name = "CE0";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -167,7 +182,7 @@
cell-id = <MSM_BUS_BCM_IP0>;
label = "IP0";
qcom,bcm-name = "IP0";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -175,7 +190,7 @@
cell-id = <MSM_BUS_BCM_CN0>;
label = "CN0";
qcom,bcm-name = "CN0";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -183,7 +198,7 @@
cell-id = <MSM_BUS_BCM_SN1>;
label = "SN1";
qcom,bcm-name = "SN1";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -191,7 +206,7 @@
cell-id = <MSM_BUS_BCM_SN2>;
label = "SN2";
qcom,bcm-name = "SN2";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -199,7 +214,7 @@
cell-id = <MSM_BUS_BCM_SN3>;
label = "SN3";
qcom,bcm-name = "SN3";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -207,7 +222,7 @@
cell-id = <MSM_BUS_BCM_SN4>;
label = "SN4";
qcom,bcm-name = "SN4";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -215,7 +230,7 @@
cell-id = <MSM_BUS_BCM_SN5>;
label = "SN5";
qcom,bcm-name = "SN5";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -223,7 +238,7 @@
cell-id = <MSM_BUS_BCM_SN6>;
label = "SN6";
qcom,bcm-name = "SN6";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -231,7 +246,7 @@
cell-id = <MSM_BUS_BCM_SN7>;
label = "SN7";
qcom,bcm-name = "SN7";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -239,7 +254,7 @@
cell-id = <MSM_BUS_BCM_SN8>;
label = "SN8";
qcom,bcm-name = "SN8";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -247,7 +262,7 @@
cell-id = <MSM_BUS_BCM_SN9>;
label = "SN9";
qcom,bcm-name = "SN9";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -255,7 +270,7 @@
cell-id = <MSM_BUS_BCM_SN11>;
label = "SN11";
qcom,bcm-name = "SN11";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -263,7 +278,7 @@
cell-id = <MSM_BUS_BCM_SN12>;
label = "SN12";
qcom,bcm-name = "SN12";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -271,7 +286,7 @@
cell-id = <MSM_BUS_BCM_SN14>;
label = "SN14";
qcom,bcm-name = "SN14";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -279,7 +294,7 @@
cell-id = <MSM_BUS_BCM_SN15>;
label = "SN15";
qcom,bcm-name = "SN15";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -287,7 +302,7 @@
cell-id = <MSM_BUS_BCM_MC0_DISPLAY>;
label = "MC0_DISPLAY";
qcom,bcm-name = "MC0";
- qcom,drv-id = <0>;
+ qcom,rscs = <&rsc_disp>;
qcom,bcm-dev;
};
@@ -295,7 +310,7 @@
cell-id = <MSM_BUS_BCM_SH0_DISPLAY>;
label = "SH0_DISPLAY";
qcom,bcm-name = "SH0";
- qcom,drv-id = <0>;
+ qcom,rscs = <&rsc_disp>;
qcom,bcm-dev;
};
@@ -303,7 +318,7 @@
cell-id = <MSM_BUS_BCM_MM0_DISPLAY>;
label = "MM0_DISPLAY";
qcom,bcm-name = "MM0";
- qcom,drv-id = <0>;
+ qcom,rscs = <&rsc_disp>;
qcom,bcm-dev;
};
@@ -311,7 +326,7 @@
cell-id = <MSM_BUS_BCM_MM1_DISPLAY>;
label = "MM1_DISPLAY";
qcom,bcm-name = "MM1";
- qcom,drv-id = <0>;
+ qcom,rscs = <&rsc_disp>;
qcom,bcm-dev;
};
@@ -319,7 +334,7 @@
cell-id = <MSM_BUS_BCM_MM2_DISPLAY>;
label = "MM2_DISPLAY";
qcom,bcm-name = "MM2";
- qcom,drv-id = <0>;
+ qcom,rscs = <&rsc_disp>;
qcom,bcm-dev;
};
@@ -327,7 +342,7 @@
cell-id = <MSM_BUS_BCM_MM3_DISPLAY>;
label = "MM3_DISPLAY";
qcom,bcm-name = "MM3";
- qcom,drv-id = <0>;
+ qcom,rscs = <&rsc_disp>;
qcom,bcm-dev;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 67dd934..ca325c0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -801,6 +801,7 @@
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
qcom,mode-threshold-currents = <0 10000>;
+ pm8998_l24-parent-supply = <&pm8998_l12>;
pm8998_l24: regulator-l24 {
regulator-name = "pm8998_l24";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 5d81487..1b697fb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -102,7 +102,7 @@
dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 {
compatible = "qcom,dsi-display";
- label = "dsi_sharp_4k_dsc_video";
+ label = "dsi_sharp_4k_dsc_video_display";
qcom,display-type = "primary";
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -125,7 +125,7 @@
dsi_sharp_4k_dsc_cmd_display: qcom,dsi-display@1 {
compatible = "qcom,dsi-display";
- label = "dsi_sharp_4k_dsc_cmd";
+ label = "dsi_sharp_4k_dsc_cmd_display";
qcom,display-type = "primary";
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -148,7 +148,7 @@
dsi_sharp_1080_cmd_display: qcom,dsi-display@2 {
compatible = "qcom,dsi-display";
- label = "dsi_sharp_1080_cmd";
+ label = "dsi_sharp_1080_cmd_display";
qcom,display-type = "primary";
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -171,7 +171,7 @@
dsi_dual_sharp_1080_120hz_cmd_display: qcom,dsi-display@3 {
compatible = "qcom,dsi-display";
- label = "dsi_dual_sharp_1080_120hz_cmd";
+ label = "dsi_dual_sharp_1080_120hz_cmd_display";
qcom,display-type = "primary";
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -194,7 +194,7 @@
dsi_dual_nt35597_truly_video_display: qcom,dsi-display@4 {
compatible = "qcom,dsi-display";
- label = "dsi_dual_nt35597_truly_video";
+ label = "dsi_dual_nt35597_truly_video_display";
qcom,display-type = "primary";
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -217,7 +217,7 @@
dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@5 {
compatible = "qcom,dsi-display";
- label = "dsi_dual_nt35597_truly_cmd";
+ label = "dsi_dual_nt35597_truly_cmd_display";
qcom,display-type = "primary";
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -240,7 +240,7 @@
dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@6 {
compatible = "qcom,dsi-display";
- label = "dsi_nt35597_truly_dsc_cmd";
+ label = "dsi_nt35597_truly_dsc_cmd_display";
qcom,display-type = "primary";
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -263,7 +263,7 @@
dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 {
compatible = "qcom,dsi-display";
- label = "dsi_nt35597_truly_dsc_video";
+ label = "dsi_nt35597_truly_dsc_video_display";
qcom,display-type = "primary";
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index c5340a8..ab4c253 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -112,6 +112,7 @@
qcom,sde-sspp-qseed-off = <0xa00>;
qcom,sde-mixer-linewidth = <2560>;
qcom,sde-sspp-linewidth = <2560>;
+ qcom,sde-wb-linewidth = <4096>;
qcom,sde-mixer-blendstages = <0xb>;
qcom,sde-highest-bank-bit = <0x2>;
qcom,sde-panic-per-pipe;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 5c33436..c4184c4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -552,6 +552,160 @@
< 1958400 >;
};
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "performance";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ bwmon: qcom,cpu-bwmon {
+ compatible = "qcom,bimc-bwmon4";
+ reg = <0x1436400 0x300>, <0x1436300 0x200>;
+ reg-names = "base", "global_base";
+ interrupts = <0 581 4>;
+ qcom,mport = <0>;
+ qcom,hw-timer-hz = <19200000>;
+ qcom,target-dev = <&cpubw>;
+ };
+
+ memlat_cpu0: qcom,memlat-cpu0 {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ memlat_cpu4: qcom,memlat-cpu4 {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ status = "ok";
+ qcom,bw-tbl =
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ devfreq_memlat_0: qcom,cpu0-memlat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,target-dev = <&memlat_cpu0>;
+ qcom,cachemiss-ev = <0x2A>;
+ qcom,core-dev-table =
+ < 300000 762 >,
+ < 748800 1720 >,
+ < 979200 2929 >,
+ < 1209600 3879 >,
+ < 1516800 4943 >,
+ < 1593600 5931 >;
+ };
+
+ devfreq_memlat_4: qcom,cpu4-memlat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+ qcom,target-dev = <&memlat_cpu4>;
+ qcom,cachemiss-ev = <0x2A>;
+ qcom,core-dev-table =
+ < 300000 762 >,
+ < 1036800 2929 >,
+ < 1190400 3879 >,
+ < 1574400 4943 >,
+ < 1804800 5931 >,
+ < 1958400 6881 >;
+ };
+
+ l3_cpu0: qcom,l3-cpu0 {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>;
+ governor = "performance";
+ freq-tbl-khz =
+ < 300000 >,
+ < 422400 >,
+ < 499200 >,
+ < 576000 >,
+ < 652800 >,
+ < 729600 >,
+ < 806400 >,
+ < 883200 >,
+ < 960000 >;
+ };
+
+ l3_cpu4: qcom,l3-cpu4 {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>;
+ governor = "performance";
+ freq-tbl-khz =
+ < 300000 >,
+ < 422400 >,
+ < 499200 >,
+ < 576000 >,
+ < 652800 >,
+ < 729600 >,
+ < 806400 >,
+ < 883200 >,
+ < 960000 >;
+ };
+
+ devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,target-dev = <&l3_cpu0>;
+ qcom,cachemiss-ev = <0x17>;
+ qcom,core-dev-table =
+ < 300000 300000 >,
+ < 748800 576000 >,
+ < 979200 652800 >,
+ < 1209600 806400 >,
+ < 1516800 883200 >,
+ < 1593600 960000 >;
+ };
+
+ devfreq_l3lat_4: qcom,cpu4-l3lat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+ qcom,target-dev = <&l3_cpu4>;
+ qcom,cachemiss-ev = <0x17>;
+ qcom,core-dev-table =
+ < 300000 300000 >,
+ < 1036800 652800 >,
+ < 1190400 806400 >,
+ < 1574400 883200 >,
+ < 1651200 960000 >;
+ };
+
clock_gcc: qcom,gcc@100000 {
compatible = "qcom,gcc-sdm845";
reg = <0x100000 0x1f0000>;
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 2e72456..bf8082e 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -318,6 +318,7 @@
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
CONFIG_DRM=y
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
+CONFIG_DRM_SDE_RSC=y
CONFIG_FB_VIRTUAL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 688e130..4b73772 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -331,6 +331,7 @@
CONFIG_QCOM_KGSL=y
CONFIG_DRM=y
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
+CONFIG_DRM_SDE_RSC=y
CONFIG_FB_VIRTUAL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index d1472eb..4ad25a5 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -47,9 +47,6 @@
struct thread_info {
unsigned long flags; /* low level flags */
mm_segment_t addr_limit; /* address limit */
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
- u64 ttbr0; /* saved TTBR0_EL1 */
-#endif
struct task_struct *task; /* main task structure */
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
u64 ttbr0; /* saved TTBR0_EL1 */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 7d66bba..2c03b01 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -33,7 +33,8 @@
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
-arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
+arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_trace_counters.o \
+ perf_trace_user.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c
index 769f24e..d7e90d9 100644
--- a/arch/arm64/kernel/kaslr.c
+++ b/arch/arm64/kernel/kaslr.c
@@ -131,11 +131,15 @@
/*
* The kernel Image should not extend across a 1GB/32MB/512MB alignment
* boundary (for 4KB/16KB/64KB granule kernels, respectively). If this
- * happens, increase the KASLR offset by the size of the kernel image.
+ * happens, increase the KASLR offset by the size of the kernel image
+ * rounded up by SWAPPER_BLOCK_SIZE.
*/
if ((((u64)_text + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT) !=
- (((u64)_end + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT))
- offset = (offset + (u64)(_end - _text)) & mask;
+ (((u64)_end + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT)) {
+ u64 kimg_sz = _end - _text;
+ offset = (offset + round_up(kimg_sz, SWAPPER_BLOCK_SIZE))
+ & mask;
+ }
if (IS_ENABLED(CONFIG_KASAN))
/*
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 6d47969..2f8d275 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -840,12 +840,10 @@
struct hw_perf_event *hwc = &event->hw;
unsigned long evtype = hwc->config_base & ARMV8_PMU_EVTYPE_EVENT;
- /* Always place a cycle counter into the cycle counter. */
+ /* Place the first cycle counter request into the cycle counter. */
if (evtype == ARMV8_PMUV3_PERFCTR_CPU_CYCLES) {
- if (test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask))
- return -EAGAIN;
-
- return ARMV8_IDX_CYCLE_COUNTER;
+ if (!test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask))
+ return ARMV8_IDX_CYCLE_COUNTER;
}
/*
diff --git a/arch/arm64/kernel/perf_trace_counters.c b/arch/arm64/kernel/perf_trace_counters.c
new file mode 100644
index 0000000..1f0b74a
--- /dev/null
+++ b/arch/arm64/kernel/perf_trace_counters.c
@@ -0,0 +1,177 @@
+/* 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/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/cpu.h>
+#include <linux/tracepoint.h>
+#include <trace/events/sched.h>
+#define CREATE_TRACE_POINTS
+#include "perf_trace_counters.h"
+
+static unsigned int tp_pid_state;
+
+DEFINE_PER_CPU(u32, cntenset_val);
+DEFINE_PER_CPU(u32, previous_ccnt);
+DEFINE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts);
+DEFINE_PER_CPU(u32, old_pid);
+DEFINE_PER_CPU(u32, hotplug_flag);
+
+#define USE_CPUHP_STATE CPUHP_AP_ONLINE
+
+static int tracectr_cpu_hotplug_coming_up(unsigned int cpu)
+{
+ per_cpu(hotplug_flag, cpu) = 1;
+
+ return 0;
+}
+
+static void setup_prev_cnts(u32 cpu, u32 cnten_val)
+{
+ int i;
+
+ if (cnten_val & CC)
+ per_cpu(previous_ccnt, cpu) =
+ read_sysreg(pmccntr_el0);
+
+ for (i = 0; i < NUM_L1_CTRS; i++) {
+ if (cnten_val & (1 << i)) {
+ /* Select */
+ write_sysreg(i, pmselr_el0);
+ isb();
+ /* Read value */
+ per_cpu(previous_l1_cnts[i], cpu) =
+ read_sysreg(pmxevcntr_el0);
+ }
+ }
+}
+
+void tracectr_notifier(void *ignore, bool preempt,
+ struct task_struct *prev, struct task_struct *next)
+{
+ u32 cnten_val;
+ int current_pid;
+ u32 cpu = task_thread_info(next)->cpu;
+
+ if (tp_pid_state != 1)
+ return;
+ current_pid = next->pid;
+ if (per_cpu(old_pid, cpu) != -1) {
+ cnten_val = read_sysreg(pmcntenset_el0);
+ per_cpu(cntenset_val, cpu) = cnten_val;
+ /* Disable all the counters that were enabled */
+ write_sysreg(cnten_val, pmcntenclr_el0);
+
+ if (per_cpu(hotplug_flag, cpu) == 1) {
+ per_cpu(hotplug_flag, cpu) = 0;
+ setup_prev_cnts(cpu, cnten_val);
+ } else {
+ trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu),
+ current_pid);
+ }
+
+ /* Enable all the counters that were disabled */
+ write_sysreg(cnten_val, pmcntenset_el0);
+ }
+ per_cpu(old_pid, cpu) = current_pid;
+}
+
+static void enable_tp_pid(void)
+{
+ if (tp_pid_state == 0) {
+ tp_pid_state = 1;
+ register_trace_sched_switch(tracectr_notifier, NULL);
+ }
+}
+
+static void disable_tp_pid(void)
+{
+ if (tp_pid_state == 1) {
+ tp_pid_state = 0;
+ unregister_trace_sched_switch(tracectr_notifier, NULL);
+ }
+}
+
+static ssize_t read_enabled_perftp_file_bool(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buf[2];
+
+ buf[1] = '\n';
+ if (tp_pid_state == 0)
+ buf[0] = '0';
+ else
+ buf[0] = '1';
+ return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled_perftp_file_bool(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buf[32];
+ size_t buf_size;
+
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ switch (buf[0]) {
+ case 'y':
+ case 'Y':
+ case '1':
+ enable_tp_pid();
+ break;
+ case 'n':
+ case 'N':
+ case '0':
+ disable_tp_pid();
+ break;
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_perftp = {
+ .read = read_enabled_perftp_file_bool,
+ .write = write_enabled_perftp_file_bool,
+ .llseek = default_llseek,
+};
+
+int __init init_tracecounters(void)
+{
+ struct dentry *dir;
+ struct dentry *file;
+ unsigned int value = 1;
+ int cpu, rc;
+
+ dir = debugfs_create_dir("perf_debug_tp", NULL);
+ if (!dir)
+ return -ENOMEM;
+ file = debugfs_create_file("enabled", 0660, dir,
+ &value, &fops_perftp);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
+ for_each_possible_cpu(cpu)
+ per_cpu(old_pid, cpu) = -1;
+ rc = cpuhp_setup_state_nocalls(USE_CPUHP_STATE,
+ "tracectr_cpu_hotplug",
+ tracectr_cpu_hotplug_coming_up,
+ NULL);
+ return 0;
+}
+
+int __exit exit_tracecounters(void)
+{
+ cpuhp_remove_state_nocalls(USE_CPUHP_STATE);
+ return 0;
+}
+late_initcall(init_tracecounters);
diff --git a/arch/arm64/kernel/perf_trace_counters.h b/arch/arm64/kernel/perf_trace_counters.h
new file mode 100644
index 0000000..660f6ce
--- /dev/null
+++ b/arch/arm64/kernel/perf_trace_counters.h
@@ -0,0 +1,110 @@
+/* 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM perf_trace_counters
+
+#if !defined(_PERF_TRACE_COUNTERS_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _PERF_TRACE_COUNTERS_H_
+
+/* Ctr index for PMCNTENSET/CLR */
+#define CC 0x80000000
+#define C0 0x1
+#define C1 0x2
+#define C2 0x4
+#define C3 0x8
+#define C4 0x10
+#define C5 0x20
+#define C_ALL (CC | C0 | C1 | C2 | C3 | C4 | C5)
+#define NUM_L1_CTRS 6
+
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/tracepoint.h>
+
+DECLARE_PER_CPU(u32, cntenset_val);
+DECLARE_PER_CPU(u32, previous_ccnt);
+DECLARE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts);
+TRACE_EVENT(sched_switch_with_ctrs,
+
+ TP_PROTO(pid_t prev, pid_t next),
+
+ TP_ARGS(prev, next),
+
+ TP_STRUCT__entry(
+ __field(pid_t, old_pid)
+ __field(pid_t, new_pid)
+ __field(u32, cctr)
+ __field(u32, ctr0)
+ __field(u32, ctr1)
+ __field(u32, ctr2)
+ __field(u32, ctr3)
+ __field(u32, ctr4)
+ __field(u32, ctr5)
+ ),
+
+ TP_fast_assign(
+ u32 cpu = smp_processor_id();
+ u32 i;
+ u32 cnten_val;
+ u32 total_ccnt = 0;
+ u32 total_cnt = 0;
+ u32 delta_l1_cnts[NUM_L1_CTRS];
+
+ __entry->old_pid = prev;
+ __entry->new_pid = next;
+
+ cnten_val = per_cpu(cntenset_val, cpu);
+
+ if (cnten_val & CC) {
+ /* Read value */
+ total_ccnt = read_sysreg(pmccntr_el0);
+ __entry->cctr = total_ccnt -
+ per_cpu(previous_ccnt, cpu);
+ per_cpu(previous_ccnt, cpu) = total_ccnt;
+ }
+ for (i = 0; i < NUM_L1_CTRS; i++) {
+ if (cnten_val & (1 << i)) {
+ /* Select */
+ write_sysreg(i, pmselr_el0);
+ isb();
+ /* Read value */
+ total_cnt = read_sysreg(pmxevcntr_el0);
+ delta_l1_cnts[i] = total_cnt -
+ per_cpu(previous_l1_cnts[i], cpu);
+ per_cpu(previous_l1_cnts[i], cpu) =
+ total_cnt;
+ } else
+ delta_l1_cnts[i] = 0;
+ }
+
+ __entry->ctr0 = delta_l1_cnts[0];
+ __entry->ctr1 = delta_l1_cnts[1];
+ __entry->ctr2 = delta_l1_cnts[2];
+ __entry->ctr3 = delta_l1_cnts[3];
+ __entry->ctr4 = delta_l1_cnts[4];
+ __entry->ctr5 = delta_l1_cnts[5];
+ ),
+
+ TP_printk("prev_pid=%d, next_pid=%d, CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, CTR4: %u, CTR5: %u",
+ __entry->old_pid, __entry->new_pid,
+ __entry->cctr,
+ __entry->ctr0, __entry->ctr1,
+ __entry->ctr2, __entry->ctr3,
+ __entry->ctr4, __entry->ctr5)
+);
+
+#endif
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/arm64/kernel
+#define TRACE_INCLUDE_FILE perf_trace_counters
+#include <trace/define_trace.h>
diff --git a/arch/arm64/kernel/perf_trace_user.c b/arch/arm64/kernel/perf_trace_user.c
new file mode 100644
index 0000000..5a83cc5
--- /dev/null
+++ b/arch/arm64/kernel/perf_trace_user.c
@@ -0,0 +1,96 @@
+/* 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/perf_event.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/preempt.h>
+#include <linux/stat.h>
+#include <asm/uaccess.h>
+
+#define CREATE_TRACE_POINTS
+#include "perf_trace_user.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM perf_trace_counters
+
+#define TRACE_USER_MAX_BUF_SIZE 100
+
+static ssize_t perf_trace_write(struct file *file,
+ const char __user *user_string_in,
+ size_t len, loff_t *ppos)
+{
+ u32 cnten_val;
+ int rc;
+ char buf[TRACE_USER_MAX_BUF_SIZE + 1];
+ ssize_t length;
+
+ if (len == 0)
+ return 0;
+
+ length = len > TRACE_USER_MAX_BUF_SIZE ? TRACE_USER_MAX_BUF_SIZE : len;
+
+ rc = copy_from_user(buf, user_string_in, length);
+ if (rc) {
+ pr_err("%s copy_from_user failed, rc=%d\n", __func__, rc);
+ return length;
+ }
+
+ /* Remove any trailing newline and make sure string is terminated */
+ if (buf[length - 1] == '\n')
+ buf[length - 1] = '\0';
+ else
+ buf[length] = '\0';
+
+ /*
+ * Disable preemption to ensure that all the performance counter
+ * accesses happen on the same cpu
+ */
+ preempt_disable();
+ /* stop counters, call the trace function, restart them */
+
+ cnten_val = read_sysreg(pmcntenset_el0);
+ /* Disable all the counters that were enabled */
+ write_sysreg(cnten_val, pmcntenclr_el0);
+
+ trace_perf_trace_user(buf, cnten_val);
+
+ /* Enable all the counters that were disabled */
+ write_sysreg(cnten_val, pmcntenset_el0);
+ preempt_enable();
+
+ return length;
+}
+
+static const struct file_operations perf_trace_fops = {
+ .write = perf_trace_write
+};
+
+static int __init init_perf_trace(void)
+{
+ struct dentry *dir;
+ struct dentry *file;
+ unsigned int value = 1;
+
+ dir = debugfs_create_dir("msm_perf", NULL);
+ if (!dir)
+ return -ENOMEM;
+ file = debugfs_create_file("trace_marker", 0220, dir,
+ &value, &perf_trace_fops);
+ if (!file)
+ return -ENOMEM;
+
+ return 0;
+}
+
+late_initcall(init_perf_trace);
diff --git a/arch/arm64/kernel/perf_trace_user.h b/arch/arm64/kernel/perf_trace_user.h
new file mode 100644
index 0000000..d592392
--- /dev/null
+++ b/arch/arm64/kernel/perf_trace_user.h
@@ -0,0 +1,84 @@
+/* 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.
+ */
+#if !defined(_PERF_TRACE_USER_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _PERF_TRACE_USER_H_
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM perf_trace_counters
+
+#include <linux/tracepoint.h>
+
+#define CNTENSET_CC 0x80000000
+#define NUM_L1_CTRS 6
+
+TRACE_EVENT(perf_trace_user,
+ TP_PROTO(char *string, u32 cnten_val),
+ TP_ARGS(string, cnten_val),
+
+ TP_STRUCT__entry(
+ __field(u32, cctr)
+ __field(u32, ctr0)
+ __field(u32, ctr1)
+ __field(u32, ctr2)
+ __field(u32, ctr3)
+ __field(u32, ctr4)
+ __field(u32, ctr5)
+ __string(user_string, string)
+ ),
+
+ TP_fast_assign(
+ u32 cnt;
+ u32 l1_cnts[NUM_L1_CTRS];
+ int i;
+
+ if (cnten_val & CNTENSET_CC) {
+ /* Read value */
+ cnt = read_sysreg(pmccntr_el0);
+ __entry->cctr = cnt;
+ } else
+ __entry->cctr = 0;
+ for (i = 0; i < NUM_L1_CTRS; i++) {
+ if (cnten_val & (1 << i)) {
+ /* Select */
+ write_sysreg(i, pmselr_el0);
+ isb();
+ /* Read value */
+ cnt = read_sysreg(pmxevcntr_el0);
+ l1_cnts[i] = cnt;
+ } else {
+ l1_cnts[i] = 0;
+ }
+ }
+
+ __entry->ctr0 = l1_cnts[0];
+ __entry->ctr1 = l1_cnts[1];
+ __entry->ctr2 = l1_cnts[2];
+ __entry->ctr3 = l1_cnts[3];
+ __entry->ctr4 = l1_cnts[4];
+ __entry->ctr5 = l1_cnts[5];
+ __assign_str(user_string, string);
+ ),
+
+ TP_printk("CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, CTR4: %u, CTR5: %u, MSG=%s",
+ __entry->cctr,
+ __entry->ctr0, __entry->ctr1,
+ __entry->ctr2, __entry->ctr3,
+ __entry->ctr4, __entry->ctr5,
+ __get_str(user_string)
+ )
+ );
+
+#endif
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/arm64/kernel
+#define TRACE_INCLUDE_FILE perf_trace_user
+#include <trace/define_trace.h>
diff --git a/arch/c6x/kernel/ptrace.c b/arch/c6x/kernel/ptrace.c
index 3c494e8..a511ac1 100644
--- a/arch/c6x/kernel/ptrace.c
+++ b/arch/c6x/kernel/ptrace.c
@@ -69,46 +69,6 @@
0, sizeof(*regs));
}
-static int gpr_set(struct task_struct *target,
- const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
-{
- int ret;
- struct pt_regs *regs = task_pt_regs(target);
-
- /* Don't copyin TSR or CSR */
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- ®s,
- 0, PT_TSR * sizeof(long));
- if (ret)
- return ret;
-
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- PT_TSR * sizeof(long),
- (PT_TSR + 1) * sizeof(long));
- if (ret)
- return ret;
-
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- ®s,
- (PT_TSR + 1) * sizeof(long),
- PT_CSR * sizeof(long));
- if (ret)
- return ret;
-
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- PT_CSR * sizeof(long),
- (PT_CSR + 1) * sizeof(long));
- if (ret)
- return ret;
-
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- ®s,
- (PT_CSR + 1) * sizeof(long), -1);
- return ret;
-}
-
enum c6x_regset {
REGSET_GPR,
};
@@ -120,7 +80,6 @@
.size = sizeof(u32),
.align = sizeof(u32),
.get = gpr_get,
- .set = gpr_set
},
};
diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
index 9207554..0dc1c8f 100644
--- a/arch/h8300/kernel/ptrace.c
+++ b/arch/h8300/kernel/ptrace.c
@@ -95,7 +95,8 @@
long *reg = (long *)®s;
/* build user regs in buffer */
- for (r = 0; r < ARRAY_SIZE(register_offset); r++)
+ BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0);
+ for (r = 0; r < sizeof(regs) / sizeof(long); r++)
*reg++ = h8300_get_reg(target, r);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
@@ -113,7 +114,8 @@
long *reg;
/* build user regs in buffer */
- for (reg = (long *)®s, r = 0; r < ARRAY_SIZE(register_offset); r++)
+ BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0);
+ for (reg = (long *)®s, r = 0; r < sizeof(regs) / sizeof(long); r++)
*reg++ = h8300_get_reg(target, r);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
@@ -122,7 +124,7 @@
return ret;
/* write back to pt_regs */
- for (reg = (long *)®s, r = 0; r < ARRAY_SIZE(register_offset); r++)
+ for (reg = (long *)®s, r = 0; r < sizeof(regs) / sizeof(long); r++)
h8300_put_reg(target, r, *reg++);
return 0;
}
diff --git a/arch/metag/kernel/ptrace.c b/arch/metag/kernel/ptrace.c
index 7563628..5e2dc7d 100644
--- a/arch/metag/kernel/ptrace.c
+++ b/arch/metag/kernel/ptrace.c
@@ -24,6 +24,16 @@
* user_regset definitions.
*/
+static unsigned long user_txstatus(const struct pt_regs *regs)
+{
+ unsigned long data = (unsigned long)regs->ctx.Flags;
+
+ if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
+ data |= USER_GP_REGS_STATUS_CATCH_BIT;
+
+ return data;
+}
+
int metag_gp_regs_copyout(const struct pt_regs *regs,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
@@ -62,9 +72,7 @@
if (ret)
goto out;
/* TXSTATUS */
- data = (unsigned long)regs->ctx.Flags;
- if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
- data |= USER_GP_REGS_STATUS_CATCH_BIT;
+ data = user_txstatus(regs);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&data, 4*25, 4*26);
if (ret)
@@ -119,6 +127,7 @@
if (ret)
goto out;
/* TXSTATUS */
+ data = user_txstatus(regs);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&data, 4*25, 4*26);
if (ret)
@@ -244,6 +253,8 @@
unsigned long long *ptr;
int ret, i;
+ if (count < 4*13)
+ return -EINVAL;
/* Read the entire pipeline before making any changes */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&rp, 0, 4*13);
@@ -303,7 +314,7 @@
const void *kbuf, const void __user *ubuf)
{
int ret;
- void __user *tls;
+ void __user *tls = target->thread.tls_ptr;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
if (ret)
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index a92994d..bf83dc1 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -485,7 +485,8 @@
&target->thread.fpu,
0, sizeof(elf_fpregset_t));
- for (i = 0; i < NUM_FPU_REGS; i++) {
+ BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
+ for (i = 0; i < NUM_FPU_REGS && count >= sizeof(elf_fpreg_t); i++) {
err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&fpr_val, i * sizeof(elf_fpreg_t),
(i + 1) * sizeof(elf_fpreg_t));
diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
index 72dac0b..b350ac5 100644
--- a/arch/powerpc/kernel/idle_book3s.S
+++ b/arch/powerpc/kernel/idle_book3s.S
@@ -439,9 +439,23 @@
_GLOBAL(pnv_wakeup_tb_loss)
ld r1,PACAR1(r13)
/*
- * Before entering any idle state, the NVGPRs are saved in the stack
- * and they are restored before switching to the process context. Hence
- * until they are restored, they are free to be used.
+ * Before entering any idle state, the NVGPRs are saved in the stack.
+ * If there was a state loss, or PACA_NAPSTATELOST was set, then the
+ * NVGPRs are restored. If we are here, it is likely that state is lost,
+ * but not guaranteed -- neither ISA207 nor ISA300 tests to reach
+ * here are the same as the test to restore NVGPRS:
+ * PACA_THREAD_IDLE_STATE test for ISA207, PSSCR test for ISA300,
+ * and SRR1 test for restoring NVGPRs.
+ *
+ * We are about to clobber NVGPRs now, so set NAPSTATELOST to
+ * guarantee they will always be restored. This might be tightened
+ * with careful reading of specs (particularly for ISA300) but this
+ * is already a slow wakeup path and it's simpler to be safe.
+ */
+ li r0,1
+ stb r0,PACA_NAPSTATELOST(r13)
+
+ /*
*
* Save SRR1 and LR in NVGPRs as they might be clobbered in
* opal_call() (called in CHECK_HMI_INTERRUPT). SRR1 is required
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index ac082dd..7037ca3 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -313,7 +313,7 @@
}
if (!ret) {
- unsigned long y;
+ unsigned long y = regs->y;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&y,
diff --git a/arch/x86/include/asm/kvm_page_track.h b/arch/x86/include/asm/kvm_page_track.h
index c2b8d24..6226cb0e 100644
--- a/arch/x86/include/asm/kvm_page_track.h
+++ b/arch/x86/include/asm/kvm_page_track.h
@@ -35,6 +35,7 @@
};
void kvm_page_track_init(struct kvm *kvm);
+void kvm_page_track_cleanup(struct kvm *kvm);
void kvm_page_track_free_memslot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont);
diff --git a/arch/x86/kvm/page_track.c b/arch/x86/kvm/page_track.c
index b431539..85024e0 100644
--- a/arch/x86/kvm/page_track.c
+++ b/arch/x86/kvm/page_track.c
@@ -156,6 +156,14 @@
return !!ACCESS_ONCE(slot->arch.gfn_track[mode][index]);
}
+void kvm_page_track_cleanup(struct kvm *kvm)
+{
+ struct kvm_page_track_notifier_head *head;
+
+ head = &kvm->arch.track_notifier_head;
+ cleanup_srcu_struct(&head->track_srcu);
+}
+
void kvm_page_track_init(struct kvm *kvm)
{
struct kvm_page_track_notifier_head *head;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 731044e..e5bc139 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7976,6 +7976,7 @@
kvm_free_vcpus(kvm);
kvfree(rcu_dereference_check(kvm->arch.apic_map, 1));
kvm_mmu_uninit_vm(kvm);
+ kvm_page_track_cleanup(kvm);
}
void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 81caceb..ee54ad0 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -629,17 +629,8 @@
{
struct blk_mq_timeout_data *data = priv;
- if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) {
- /*
- * If a request wasn't started before the queue was
- * marked dying, kill it here or it'll go unnoticed.
- */
- if (unlikely(blk_queue_dying(rq->q))) {
- rq->errors = -EIO;
- blk_mq_end_request(rq, rq->errors);
- }
+ if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags))
return;
- }
if (time_after_eq(jiffies, rq->deadline)) {
if (!blk_mark_rq_complete(rq))
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index d19b09c..54fc90e 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -245,7 +245,7 @@
struct alg_sock *ask = alg_sk(sk);
struct hash_ctx *ctx = ask->private;
struct ahash_request *req = &ctx->req;
- char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req))];
+ char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req)) ? : 1];
struct sock *sk2;
struct alg_sock *ask2;
struct hash_ctx *ctx2;
diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c
index bf43b5d..83f1439 100644
--- a/drivers/auxdisplay/img-ascii-lcd.c
+++ b/drivers/auxdisplay/img-ascii-lcd.c
@@ -218,6 +218,7 @@
{ .compatible = "img,boston-lcd", .data = &boston_config },
{ .compatible = "mti,malta-lcd", .data = &malta_config },
{ .compatible = "mti,sead3-lcd", .data = &sead3_config },
+ { /* sentinel */ }
};
/**
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 4a99ac7..9959c76 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -55,6 +55,7 @@
struct amd768_priv {
void __iomem *iobase;
struct pci_dev *pcidev;
+ u32 pmbase;
};
static int amd_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
@@ -148,33 +149,58 @@
if (pmbase == 0)
return -EIO;
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- if (!devm_request_region(&pdev->dev, pmbase + PMBASE_OFFSET,
- PMBASE_SIZE, DRV_NAME)) {
+ if (!request_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE, DRV_NAME)) {
dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
pmbase + 0xF0);
- return -EBUSY;
+ err = -EBUSY;
+ goto out;
}
- priv->iobase = devm_ioport_map(&pdev->dev, pmbase + PMBASE_OFFSET,
- PMBASE_SIZE);
+ priv->iobase = ioport_map(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
if (!priv->iobase) {
pr_err(DRV_NAME "Cannot map ioport\n");
- return -ENOMEM;
+ err = -EINVAL;
+ goto err_iomap;
}
amd_rng.priv = (unsigned long)priv;
+ priv->pmbase = pmbase;
priv->pcidev = pdev;
pr_info(DRV_NAME " detected\n");
- return devm_hwrng_register(&pdev->dev, &amd_rng);
+ err = hwrng_register(&amd_rng);
+ if (err) {
+ pr_err(DRV_NAME " registering failed (%d)\n", err);
+ goto err_hwrng;
+ }
+ return 0;
+
+err_hwrng:
+ ioport_unmap(priv->iobase);
+err_iomap:
+ release_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+out:
+ kfree(priv);
+ return err;
}
static void __exit mod_exit(void)
{
+ struct amd768_priv *priv;
+
+ priv = (struct amd768_priv *)amd_rng.priv;
+
+ hwrng_unregister(&amd_rng);
+
+ ioport_unmap(priv->iobase);
+
+ release_region(priv->pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+
+ kfree(priv);
}
module_init(mod_init);
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index e7a2459..e1d421a 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -31,6 +31,9 @@
#include <linux/module.h>
#include <linux/pci.h>
+
+#define PFX KBUILD_MODNAME ": "
+
#define GEODE_RNG_DATA_REG 0x50
#define GEODE_RNG_STATUS_REG 0x54
@@ -82,6 +85,7 @@
static int __init mod_init(void)
{
+ int err = -ENODEV;
struct pci_dev *pdev = NULL;
const struct pci_device_id *ent;
void __iomem *mem;
@@ -89,27 +93,43 @@
for_each_pci_dev(pdev) {
ent = pci_match_id(pci_tbl, pdev);
- if (ent) {
- rng_base = pci_resource_start(pdev, 0);
- if (rng_base == 0)
- return -ENODEV;
-
- mem = devm_ioremap(&pdev->dev, rng_base, 0x58);
- if (!mem)
- return -ENOMEM;
- geode_rng.priv = (unsigned long)mem;
-
- pr_info("AMD Geode RNG detected\n");
- return devm_hwrng_register(&pdev->dev, &geode_rng);
- }
+ if (ent)
+ goto found;
}
-
/* Device not found. */
- return -ENODEV;
+ goto out;
+
+found:
+ rng_base = pci_resource_start(pdev, 0);
+ if (rng_base == 0)
+ goto out;
+ err = -ENOMEM;
+ mem = ioremap(rng_base, 0x58);
+ if (!mem)
+ goto out;
+ geode_rng.priv = (unsigned long)mem;
+
+ pr_info("AMD Geode RNG detected\n");
+ err = hwrng_register(&geode_rng);
+ if (err) {
+ pr_err(PFX "RNG registering failed (%d)\n",
+ err);
+ goto err_unmap;
+ }
+out:
+ return err;
+
+err_unmap:
+ iounmap(mem);
+ goto out;
}
static void __exit mod_exit(void)
{
+ void __iomem *mem = (void __iomem *)geode_rng.priv;
+
+ hwrng_unregister(&geode_rng);
+ iounmap(mem);
}
module_init(mod_init);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 31ea544..cf874a1 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -216,3 +216,11 @@
frequency and voltage requests for multiple clusters via the
existence of multiple OSM domains.
Say Y if you want to support OSM clocks.
+
+config MSM_GPUCC_SDM845
+ tristate "SDM845 Graphics Clock Controller"
+ depends on MSM_GCC_SDM845
+ help
+ Support for the graphics clock controller on Qualcomm Technologies, Inc.
+ sdm845 devices.
+ Say Y if you want to support graphics controller devices.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index d52a751..836f0c7 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -32,8 +32,9 @@
obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o
obj-$(CONFIG_MSM_GCC_SDM845) += gcc-sdm845.o
+obj-$(CONFIG_MSM_GPUCC_SDM845) += gpucc-sdm845.o
obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
-obj-$(CONFIG_MSM_VIDEOCC_SDM845) += videocc-sdm845.o
+obj-$(CONFIG_MSM_VIDEOCC_SDM845) += videocc-sdm845.o
\ No newline at end of file
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
new file mode 100644
index 0000000..a5a7488
--- /dev/null
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (c) 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/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <linux/clk.h>
+#include <linux/clk/qcom.h>
+#include <dt-bindings/clock/qcom,gpucc-sdm845.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+#include "clk-alpha-pll.h"
+#include "vdd-level-sdm845.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+#define F_SLEW(f, s, h, m, n, sf) { (f), (s), (2 * (h) - 1), (m), (n), (sf) }
+
+static int vdd_gx_corner[] = {
+ RPMH_REGULATOR_LEVEL_OFF, /* VDD_GX_NONE */
+ RPMH_REGULATOR_LEVEL_MIN_SVS, /* VDD_GX_MIN */
+ RPMH_REGULATOR_LEVEL_LOW_SVS, /* VDD_GX_LOWER */
+ RPMH_REGULATOR_LEVEL_SVS, /* VDD_GX_LOW */
+ RPMH_REGULATOR_LEVEL_SVS_L1, /* VDD_GX_LOW_L1 */
+ RPMH_REGULATOR_LEVEL_NOM, /* VDD_GX_NOMINAL */
+ RPMH_REGULATOR_LEVEL_NOM_L1, /* VDD_GX_NOMINAL_L1 */
+ RPMH_REGULATOR_LEVEL_TURBO, /* VDD_GX_HIGH */
+ RPMH_REGULATOR_LEVEL_TURBO_L1, /* VDD_GX_HIGH_L1 */
+ RPMH_REGULATOR_LEVEL_MAX, /* VDD_GX_MAX */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_mx, VDD_CX_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_gfx, VDD_GX_NUM, 1, vdd_gx_corner);
+
+enum {
+ P_BI_TCXO,
+ P_CORE_BI_PLL_TEST_SE,
+ P_GPLL0_OUT_MAIN,
+ P_GPLL0_OUT_MAIN_DIV,
+ P_GPU_CC_PLL0_OUT_EVEN,
+ P_GPU_CC_PLL0_OUT_MAIN,
+ P_GPU_CC_PLL0_OUT_ODD,
+ P_GPU_CC_PLL1_OUT_EVEN,
+ P_GPU_CC_PLL1_OUT_MAIN,
+ P_GPU_CC_PLL1_OUT_ODD,
+};
+
+static const struct parent_map gpu_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPU_CC_PLL0_OUT_MAIN, 1 },
+ { P_GPU_CC_PLL1_OUT_MAIN, 3 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpu_cc_parent_names_0[] = {
+ "bi_tcxo",
+ "gpu_cc_pll0",
+ "gpu_cc_pll1",
+ "gpll0",
+ "gpll0_out_even",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gpu_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPU_CC_PLL0_OUT_EVEN, 1 },
+ { P_GPU_CC_PLL0_OUT_ODD, 2 },
+ { P_GPU_CC_PLL1_OUT_EVEN, 3 },
+ { P_GPU_CC_PLL1_OUT_ODD, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpu_cc_parent_names_1[] = {
+ "bi_tcxo",
+ "gpu_cc_pll0_out_even",
+ "gpu_cc_pll0_out_odd",
+ "gpu_cc_pll1_out_even",
+ "gpu_cc_pll1_out_odd",
+ "gpll0",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gpu_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpu_cc_parent_names_2[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll0",
+ "core_bi_pll_test_se",
+};
+
+static struct pll_vco fabia_vco[] = {
+ { 250000000, 2000000000, 0 },
+ { 125000000, 1000000000, 1 },
+};
+
+static const struct pll_config gpu_cc_pll0_config = {
+ .l = 0x1d,
+ .frac = 0x2aaa,
+};
+
+static struct clk_alpha_pll gpu_cc_pll0 = {
+ .offset = 0x0,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
+ .type = FABIA_PLL,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll0",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_fabia_pll_ops,
+ VDD_MX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_fabia_even[] = {
+ { 0x0, 1 },
+ { 0x1, 2 },
+ { 0x3, 4 },
+ { 0x7, 8 },
+ {},
+};
+
+static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_fabia_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll0_out_even",
+ .parent_names = (const char *[]){ "gpu_cc_pll0" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_generic_pll_postdiv_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
+ F(400000000, P_GPLL0_OUT_MAIN, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_gmu_clk_src = {
+ .cmd_rcgr = 0x1120,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .enable_safe_config = true,
+ .parent_map = gpu_cc_parent_map_0,
+ .freq_tbl = ftbl_gpu_cc_gmu_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gmu_clk_src",
+ .parent_names = gpu_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ VDD_CX_FMAX_MAP2(
+ MIN, 200000000,
+ LOW, 400000000),
+ },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = {
+ F_SLEW(147000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 294000000),
+ F_SLEW(210000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 420000000),
+ F_SLEW(338000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 676000000),
+ F_SLEW(425000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 850000000),
+ F_SLEW(600000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 1200000000),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = {
+ .cmd_rcgr = 0x101c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .enable_safe_config = true,
+ .parent_map = gpu_cc_parent_map_1,
+ .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gfx3d_clk_src",
+ .parent_names = gpu_cc_parent_names_1,
+ .num_parents = 7,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ VDD_GX_FMAX_MAP8(
+ MIN, 147000000,
+ LOWER, 210000000,
+ LOW, 280000000,
+ LOW_L1, 338000000,
+ NOMINAL, 425000000,
+ NOMINAL_L1, 487000000,
+ HIGH, 548000000,
+ HIGH_L1, 600000000),
+ },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_rbcpr_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_rbcpr_clk_src = {
+ .cmd_rcgr = 0x10b0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_2,
+ .freq_tbl = ftbl_gpu_cc_rbcpr_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_rbcpr_clk_src",
+ .parent_names = gpu_cc_parent_names_2,
+ .num_parents = 4,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ VDD_CX_FMAX_MAP2(
+ MIN, 19200000,
+ NOMINAL, 50000000),
+ },
+};
+
+static struct clk_branch gpu_cc_acd_ahb_clk = {
+ .halt_reg = 0x1168,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1168,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_acd_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_acd_cxo_clk = {
+ .halt_reg = 0x1164,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1164,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_acd_cxo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_ahb_clk = {
+ .halt_reg = 0x1078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1078,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_crc_ahb_clk = {
+ .halt_reg = 0x107c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x107c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_crc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_apb_clk = {
+ .halt_reg = 0x1088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_apb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_gfx3d_clk = {
+ .halt_reg = 0x10a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_gfx3d_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gx_gfx3d_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = {
+ .halt_reg = 0x10a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_gfx3d_slv_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gx_gfx3d_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_gmu_clk = {
+ .halt_reg = 0x1098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1098,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_gmu_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gmu_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {
+ .halt_reg = 0x108c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x108c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_snoc_dvm_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cxo_aon_clk = {
+ .halt_reg = 0x1004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cxo_aon_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cxo_clk = {
+ .halt_reg = 0x109c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x109c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cxo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_debug_clk = {
+ .halt_reg = 0x1100,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1100,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_debug_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_cxo_clk = {
+ .halt_reg = 0x1060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1060,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_cxo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_gfx3d_clk = {
+ .halt_reg = 0x1054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gfx3d_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gx_gfx3d_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_gmu_clk = {
+ .halt_reg = 0x1064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gmu_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gmu_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_vsense_clk = {
+ .halt_reg = 0x1058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_vsense_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_pll_test_clk = {
+ .halt_reg = 0x110c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll_test_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_rbcpr_ahb_clk = {
+ .halt_reg = 0x10f4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10f4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_rbcpr_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_rbcpr_clk = {
+ .halt_reg = 0x10f0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_rbcpr_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_rbcpr_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *gpu_cc_sdm845_clocks[] = {
+ [GPU_CC_ACD_AHB_CLK] = &gpu_cc_acd_ahb_clk.clkr,
+ [GPU_CC_ACD_CXO_CLK] = &gpu_cc_acd_cxo_clk.clkr,
+ [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
+ [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
+ [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr,
+ [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr,
+ [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr,
+ [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
+ [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
+ [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
+ [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
+ [GPU_CC_DEBUG_CLK] = &gpu_cc_debug_clk.clkr,
+ [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
+ [GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr,
+ [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
+ [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr,
+ [GPU_CC_PLL_TEST_CLK] = &gpu_cc_pll_test_clk.clkr,
+ [GPU_CC_RBCPR_AHB_CLK] = &gpu_cc_rbcpr_ahb_clk.clkr,
+ [GPU_CC_RBCPR_CLK] = &gpu_cc_rbcpr_clk.clkr,
+ [GPU_CC_RBCPR_CLK_SRC] = &gpu_cc_rbcpr_clk_src.clkr,
+};
+
+static struct clk_regmap *gpu_cc_gfx_sdm845_clocks[] = {
+ [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
+ [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr,
+ [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr,
+ [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr,
+};
+
+static const struct qcom_reset_map gpu_cc_sdm845_resets[] = {
+ [GPUCC_GPU_CC_ACD_BCR] = { 0x1160 },
+ [GPUCC_GPU_CC_CX_BCR] = { 0x1068 },
+ [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x10a0 },
+ [GPUCC_GPU_CC_GMU_BCR] = { 0x111c },
+ [GPUCC_GPU_CC_GX_BCR] = { 0x1008 },
+ [GPUCC_GPU_CC_RBCPR_BCR] = { 0x10ac },
+ [GPUCC_GPU_CC_SPDM_BCR] = { 0x1110 },
+ [GPUCC_GPU_CC_XO_BCR] = { 0x1000 },
+};
+
+static const struct regmap_config gpu_cc_sdm845_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x8008,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gpu_cc_sdm845_desc = {
+ .config = &gpu_cc_sdm845_regmap_config,
+ .clks = gpu_cc_sdm845_clocks,
+ .num_clks = ARRAY_SIZE(gpu_cc_sdm845_clocks),
+ .resets = gpu_cc_sdm845_resets,
+ .num_resets = ARRAY_SIZE(gpu_cc_sdm845_resets),
+};
+
+static const struct qcom_cc_desc gpu_cc_gfx_sdm845_desc = {
+ .config = &gpu_cc_sdm845_regmap_config,
+ .clks = gpu_cc_gfx_sdm845_clocks,
+ .num_clks = ARRAY_SIZE(gpu_cc_gfx_sdm845_clocks),
+};
+
+static const struct of_device_id gpu_cc_sdm845_match_table[] = {
+ { .compatible = "qcom,gpucc-sdm845" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table);
+
+static const struct of_device_id gpu_cc_gfx_sdm845_match_table[] = {
+ { .compatible = "qcom,gfxcc-sdm845" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_gfx_sdm845_match_table);
+
+static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ struct resource *res;
+ void __iomem *base;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Failed to get resources for clock_gfxcc.\n");
+ return -EINVAL;
+ }
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (IS_ERR(base)) {
+ dev_err(&pdev->dev, "Failed to ioremap the GFX CC base.\n");
+ return PTR_ERR(base);
+ }
+
+ regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ gpu_cc_gfx_sdm845_desc.config);
+ if (IS_ERR(regmap)) {
+ dev_err(&pdev->dev, "Failed to init regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ /* Get MX voltage regulator for GPU PLL graphic clock. */
+ vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx");
+ if (IS_ERR(vdd_mx.regulator[0])) {
+ if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_mx regulator\n");
+ return PTR_ERR(vdd_mx.regulator[0]);
+ }
+
+ /* GFX voltage regulators for GFX3D graphic clock. */
+ vdd_gfx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx");
+ if (IS_ERR(vdd_gfx.regulator[0])) {
+ if (PTR_ERR(vdd_gfx.regulator[0]) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get vdd_gfx regulator\n");
+ return PTR_ERR(vdd_gfx.regulator[0]);
+ }
+
+ clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config);
+
+ ret = qcom_cc_really_probe(pdev, &gpu_cc_gfx_sdm845_desc, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register GFX CC clocks\n");
+ return ret;
+ }
+
+ clk_prepare_enable(gpu_cc_cxo_clk.clkr.hw.clk);
+
+ dev_info(&pdev->dev, "Registered GFX CC clocks.\n");
+
+ return ret;
+}
+
+static struct platform_driver gpu_cc_gfx_sdm845_driver = {
+ .probe = gpu_cc_gfx_sdm845_probe,
+ .driver = {
+ .name = "gfxcc-sdm845",
+ .of_match_table = gpu_cc_gfx_sdm845_match_table,
+ },
+};
+
+static int __init gpu_cc_gfx_sdm845_init(void)
+{
+ return platform_driver_register(&gpu_cc_gfx_sdm845_driver);
+}
+arch_initcall(gpu_cc_gfx_sdm845_init);
+
+static void __exit gpu_cc_gfx_sdm845_exit(void)
+{
+ platform_driver_unregister(&gpu_cc_gfx_sdm845_driver);
+}
+module_exit(gpu_cc_gfx_sdm845_exit);
+
+static int gpu_cc_sdm845_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret = 0;
+
+ regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Get CX voltage regulator for CX and GMU clocks. */
+ vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx");
+ if (IS_ERR(vdd_cx.regulator[0])) {
+ if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_cx regulator\n");
+ return PTR_ERR(vdd_cx.regulator[0]);
+ }
+
+ ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register GPU CC clocks\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "Registered GPU CC clocks.\n");
+
+ return ret;
+}
+
+static struct platform_driver gpu_cc_sdm845_driver = {
+ .probe = gpu_cc_sdm845_probe,
+ .driver = {
+ .name = "gpu_cc-sdm845",
+ .of_match_table = gpu_cc_sdm845_match_table,
+ },
+};
+
+static int __init gpu_cc_sdm845_init(void)
+{
+ return platform_driver_register(&gpu_cc_sdm845_driver);
+}
+core_initcall(gpu_cc_sdm845_init);
+
+static void __exit gpu_cc_sdm845_exit(void)
+{
+ platform_driver_unregister(&gpu_cc_sdm845_driver);
+}
+module_exit(gpu_cc_sdm845_exit);
+
+MODULE_DESCRIPTION("QTI GPU_CC SDM845 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:gpu_cc-sdm845");
diff --git a/drivers/clk/qcom/vdd-level-sdm845.h b/drivers/clk/qcom/vdd-level-sdm845.h
index 1771c15..6f876ba 100644
--- a/drivers/clk/qcom/vdd-level-sdm845.h
+++ b/drivers/clk/qcom/vdd-level-sdm845.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * 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
@@ -98,6 +98,31 @@
}, \
.num_rate_max = VDD_CX_NUM
+#define VDD_MX_FMAX_MAP4(l1, f1, l2, f2, l3, f3, l4, f4) \
+ .vdd_class = &vdd_mx, \
+ .rate_max = (unsigned long[VDD_CX_NUM]) { \
+ [VDD_CX_##l1] = (f1), \
+ [VDD_CX_##l2] = (f2), \
+ [VDD_CX_##l3] = (f3), \
+ [VDD_CX_##l4] = (f4), \
+ }, \
+ .num_rate_max = VDD_CX_NUM
+
+#define VDD_GX_FMAX_MAP8(l1, f1, l2, f2, l3, f3, l4, f4, l5, f5, l6, f6, \
+ l7, f7, l8, f8) \
+ .vdd_class = &vdd_gfx, \
+ .rate_max = (unsigned long[VDD_GX_NUM]) { \
+ [VDD_GX_##l1] = (f1), \
+ [VDD_GX_##l2] = (f2), \
+ [VDD_GX_##l3] = (f3), \
+ [VDD_GX_##l4] = (f4), \
+ [VDD_GX_##l5] = (f5), \
+ [VDD_GX_##l6] = (f6), \
+ [VDD_GX_##l7] = (f7), \
+ [VDD_GX_##l8] = (f8), \
+ }, \
+ .num_rate_max = VDD_GX_NUM
+
enum vdd_cx_levels {
VDD_CX_NONE,
VDD_CX_MIN, /* MIN SVS */
@@ -109,6 +134,19 @@
VDD_CX_NUM,
};
+enum vdd_gx_levels {
+ VDD_GX_NONE,
+ VDD_GX_MIN, /* MIN SVS */
+ VDD_GX_LOWER, /* SVS2 */
+ VDD_GX_LOW, /* SVS */
+ VDD_GX_LOW_L1, /* SVSL1 */
+ VDD_GX_NOMINAL, /* NOM */
+ VDD_GX_NOMINAL_L1, /* NOM1 */
+ VDD_GX_HIGH, /* TURBO */
+ VDD_GX_HIGH_L1, /* TURBO1 */
+ VDD_GX_NUM,
+};
+
/* Need to use the correct VI/VL mappings */
static int vdd_corner[] = {
RPMH_REGULATOR_LEVEL_OFF, /* VDD_CX_NONE */
diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
index fc75a33..8ca07fe 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
@@ -608,7 +608,7 @@
0x150, 0, 4, 24, 2, BIT(31),
CLK_SET_RATE_PARENT);
-static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(31), 0);
+static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(30), 0);
static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x140, BIT(31), 0);
diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
index ebb1b31..ee78104 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.c
+++ b/drivers/clk/sunxi-ng/ccu_mp.c
@@ -85,6 +85,10 @@
unsigned int m, p;
u32 reg;
+ /* Adjust parent_rate according to pre-dividers */
+ ccu_mux_helper_adjust_parent_for_prediv(&cmp->common, &cmp->mux,
+ -1, &parent_rate);
+
reg = readl(cmp->common.base + cmp->common.reg);
m = reg >> cmp->m.shift;
@@ -114,6 +118,10 @@
unsigned int m, p;
u32 reg;
+ /* Adjust parent_rate according to pre-dividers */
+ ccu_mux_helper_adjust_parent_for_prediv(&cmp->common, &cmp->mux,
+ -1, &parent_rate);
+
max_m = cmp->m.max ?: 1 << cmp->m.width;
max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index cafa633..f796e36 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -283,11 +283,14 @@
*/
int ccp_enqueue_cmd(struct ccp_cmd *cmd)
{
- struct ccp_device *ccp = ccp_get_device();
+ struct ccp_device *ccp;
unsigned long flags;
unsigned int i;
int ret;
+ /* Some commands might need to be sent to a specific device */
+ ccp = cmd->ccp ? cmd->ccp : ccp_get_device();
+
if (!ccp)
return -ENODEV;
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
index e5d9278..8d0eeb4 100644
--- a/drivers/crypto/ccp/ccp-dmaengine.c
+++ b/drivers/crypto/ccp/ccp-dmaengine.c
@@ -390,6 +390,7 @@
goto err;
ccp_cmd = &cmd->ccp_cmd;
+ ccp_cmd->ccp = chan->ccp;
ccp_pt = &ccp_cmd->u.passthru_nomap;
ccp_cmd->flags = CCP_CMD_MAY_BACKLOG;
ccp_cmd->flags |= CCP_CMD_PASSTHRU_NO_DMA_MAP;
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 286447a..152552d 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -334,6 +334,7 @@
int rc = VM_FAULT_SIGBUS;
phys_addr_t phys;
pfn_t pfn;
+ unsigned int fault_size = PAGE_SIZE;
if (check_vma(dax_dev, vma, __func__))
return VM_FAULT_SIGBUS;
@@ -344,6 +345,9 @@
return VM_FAULT_SIGBUS;
}
+ if (fault_size != dax_region->align)
+ return VM_FAULT_SIGBUS;
+
phys = pgoff_to_phys(dax_dev, vmf->pgoff, PAGE_SIZE);
if (phys == -1) {
dev_dbg(dev, "%s: phys_to_pgoff(%#lx) failed\n", __func__,
@@ -389,6 +393,7 @@
phys_addr_t phys;
pgoff_t pgoff;
pfn_t pfn;
+ unsigned int fault_size = PMD_SIZE;
if (check_vma(dax_dev, vma, __func__))
return VM_FAULT_SIGBUS;
@@ -405,6 +410,16 @@
return VM_FAULT_SIGBUS;
}
+ if (fault_size < dax_region->align)
+ return VM_FAULT_SIGBUS;
+ else if (fault_size > dax_region->align)
+ return VM_FAULT_FALLBACK;
+
+ /* if we are outside of the VMA */
+ if (pmd_addr < vma->vm_start ||
+ (pmd_addr + PMD_SIZE) > vma->vm_end)
+ return VM_FAULT_SIGBUS;
+
pgoff = linear_page_index(vma, pmd_addr);
phys = pgoff_to_phys(dax_dev, pgoff, PMD_SIZE);
if (phys == -1) {
diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c
index 0fb63e9..ed83185 100644
--- a/drivers/devfreq/arm-memlat-mon.c
+++ b/drivers/devfreq/arm-memlat-mon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * 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
@@ -34,7 +34,7 @@
enum ev_index {
INST_IDX,
- L2DM_IDX,
+ CM_IDX,
CYC_IDX,
NUM_EVENTS
};
@@ -51,6 +51,8 @@
struct event_data events[NUM_EVENTS];
ktime_t prev_ts;
bool init_pending;
+ unsigned long cache_miss_event;
+ unsigned long inst_event;
};
static DEFINE_PER_CPU(struct memlat_hwmon_data, pm_data);
@@ -111,7 +113,7 @@
read_event(&hw_data->events[INST_IDX]);
hw->core_stats[cpu_idx].mem_count =
- read_event(&hw_data->events[L2DM_IDX]);
+ read_event(&hw_data->events[CM_IDX]);
cyc_cnt = read_event(&hw_data->events[CYC_IDX]);
hw->core_stats[cpu_idx].freq = compute_freq(hw_data, cyc_cnt);
@@ -192,19 +194,19 @@
if (IS_ERR(attr))
return PTR_ERR(attr);
- attr->config = INST_EV;
+ attr->config = hw_data->inst_event;
pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
if (IS_ERR(pevent))
goto err_out;
hw_data->events[INST_IDX].pevent = pevent;
perf_event_enable(hw_data->events[INST_IDX].pevent);
- attr->config = L2DM_EV;
+ attr->config = hw_data->cache_miss_event;
pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
if (IS_ERR(pevent))
goto err_out;
- hw_data->events[L2DM_IDX].pevent = pevent;
- perf_event_enable(hw_data->events[L2DM_IDX].pevent);
+ hw_data->events[CM_IDX].pevent = pevent;
+ perf_event_enable(hw_data->events[CM_IDX].pevent);
attr->config = CYC_EV;
pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
@@ -300,6 +302,7 @@
struct memlat_hwmon *hw;
struct cpu_grp_info *cpu_grp;
int cpu, ret;
+ u32 cachemiss_ev, inst_ev;
cpu_grp = devm_kzalloc(dev, sizeof(*cpu_grp), GFP_KERNEL);
if (!cpu_grp)
@@ -325,8 +328,26 @@
if (!hw->core_stats)
return -ENOMEM;
- for_each_cpu(cpu, &cpu_grp->cpus)
+ ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev",
+ &cachemiss_ev);
+ if (ret) {
+ dev_dbg(dev, "Cache Miss event not specified. Using def:0x%x\n",
+ L2DM_EV);
+ cachemiss_ev = L2DM_EV;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "qcom,inst-ev", &inst_ev);
+ if (ret) {
+ dev_dbg(dev, "Inst event not specified. Using def:0x%x\n",
+ INST_EV);
+ inst_ev = INST_EV;
+ }
+
+ for_each_cpu(cpu, &cpu_grp->cpus) {
hw->core_stats[cpu - cpumask_first(&cpu_grp->cpus)].id = cpu;
+ (&per_cpu(pm_data, cpu))->cache_miss_event = cachemiss_ev;
+ (&per_cpu(pm_data, cpu))->inst_event = inst_ev;
+ }
hw->start_hwmon = &start_hwmon;
hw->stop_hwmon = &stop_hwmon;
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
index 09e6a73..6f3c891 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
@@ -3507,9 +3507,13 @@
max_mclk = 80000;
}
} else if (adev->asic_type == CHIP_OLAND) {
- if ((adev->pdev->device == 0x6604) &&
- (adev->pdev->subsystem_vendor == 0x1028) &&
- (adev->pdev->subsystem_device == 0x066F)) {
+ if ((adev->pdev->revision == 0xC7) ||
+ (adev->pdev->revision == 0x80) ||
+ (adev->pdev->revision == 0x81) ||
+ (adev->pdev->revision == 0x83) ||
+ (adev->pdev->revision == 0x87) ||
+ (adev->pdev->device == 0x6604) ||
+ (adev->pdev->device == 0x6605)) {
max_sclk = 75000;
}
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 6e0447f..72ec93d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1382,6 +1382,7 @@
pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
phy_power_on(dp->phy);
analogix_dp_init_dp(dp);
@@ -1414,9 +1415,15 @@
goto err_disable_pm_runtime;
}
+ phy_power_off(dp->phy);
+ pm_runtime_put(dev);
+
return 0;
err_disable_pm_runtime:
+
+ phy_power_off(dp->phy);
+ pm_runtime_put(dev);
pm_runtime_disable(dev);
return ret;
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2e42a05..50acd79 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1382,6 +1382,15 @@
return ret < 0 ? ret : 0;
}
+void release_crtc_commit(struct completion *completion)
+{
+ struct drm_crtc_commit *commit = container_of(completion,
+ typeof(*commit),
+ flip_done);
+
+ drm_crtc_commit_put(commit);
+}
+
/**
* drm_atomic_helper_setup_commit - setup possibly nonblocking commit
* @state: new modeset state to be committed
@@ -1474,6 +1483,8 @@
}
crtc_state->event->base.completion = &commit->flip_done;
+ crtc_state->event->base.completion_release = release_crtc_commit;
+ drm_crtc_commit_get(commit);
}
return 0;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index e84faec..f5815e1 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -686,8 +686,8 @@
assert_spin_locked(&dev->event_lock);
if (e->completion) {
- /* ->completion might disappear as soon as it signalled. */
complete_all(e->completion);
+ e->completion_release(e->completion);
e->completion = NULL;
}
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 71000d5..70b47ca 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -113,3 +113,13 @@
driver during fatal errors and enable some display-driver logging
into an internal buffer (this avoids logging overhead).
+config DRM_SDE_RSC
+ bool "Enable sde resource state coordinator(rsc) driver"
+ depends on DRM_MSM
+ help
+ The SDE DRM RSC provides display Resource State Coordinator support
+ to vote the ab/ib bandwidth for primary display. Each rsc client
+ can vote their active state. Any active request from any client
+ avoids the display core power collapse. A client can also register
+ for display core power collapse events on rsc.
+
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index d9a49f8..b5d78b1 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -50,10 +50,11 @@
sde_io_util.o \
sde/sde_hw_reg_dma_v1_color_proc.o \
sde/sde_hw_color_proc_v4.o \
- sde_rsc.o \
- sde_rsc_hw.o \
sde/sde_hw_ad4.o \
+msm_drm-$(CONFIG_DRM_SDE_RSC) += sde_rsc.o \
+ sde_rsc_hw.o \
+
# use drm gpu driver only if qcom_kgsl driver not available
ifneq ($(CONFIG_QCOM_KGSL),y)
msm_drm-y += adreno/adreno_device.o \
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b51187d..a904dcd 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -134,7 +134,10 @@
CRTC_PROP_CORE_CLK,
CRTC_PROP_CORE_AB,
CRTC_PROP_CORE_IB,
+ CRTC_PROP_MEM_AB,
+ CRTC_PROP_MEM_IB,
CRTC_PROP_ROT_PREFILL_BW,
+ CRTC_PROP_ROT_CLK,
/* total # of properties */
CRTC_PROP_COUNT
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 9caadca..5d4648e 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -399,9 +399,12 @@
/* convert fb val to drm framebuffer and prepare it */
c_state->out_fb =
drm_framebuffer_lookup(connector->dev, val);
- if (!c_state->out_fb) {
+ if (!c_state->out_fb && val) {
SDE_ERROR("failed to look up fb %lld\n", val);
rc = -EFAULT;
+ } else if (!c_state->out_fb && !val) {
+ SDE_DEBUG("cleared fb_id\n");
+ rc = 0;
} else {
msm_framebuffer_set_kmap(c_state->out_fb,
c_conn->fb_kmap);
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 307c617..db2c515 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -18,13 +18,13 @@
#include <linux/sort.h>
#include <linux/clk.h>
#include <linux/bitmap.h>
+#include <linux/sde_rsc.h>
#include "msm_prop.h"
#include "sde_kms.h"
#include "sde_trace.h"
#include "sde_crtc.h"
-#include "sde_rsc.h"
#include "sde_core_perf.h"
static struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index b6a37b7..ec15215 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -467,12 +467,6 @@
sde_connector_prepare_fence(conn);
}
- if (cstate->num_connectors > 0 && cstate->connectors[0]->encoder)
- cstate->intf_mode = sde_encoder_get_intf_mode(
- cstate->connectors[0]->encoder);
- else
- cstate->intf_mode = INTF_MODE_NONE;
-
/* prepare main output fence */
sde_fence_prepare(&sde_crtc->output_fence);
}
@@ -514,6 +508,22 @@
spin_unlock_irqrestore(&dev->event_lock, flags);
}
+enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc)
+{
+ struct drm_encoder *encoder;
+
+ if (!crtc || !crtc->dev) {
+ SDE_ERROR("invalid crtc\n");
+ return INTF_MODE_NONE;
+ }
+
+ drm_for_each_encoder(encoder, crtc->dev)
+ if (encoder->crtc == crtc)
+ return sde_encoder_get_intf_mode(encoder);
+
+ return INTF_MODE_NONE;
+}
+
static void sde_crtc_vblank_cb(void *data)
{
struct drm_crtc *crtc = (struct drm_crtc *)data;
@@ -1723,9 +1733,21 @@
SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA,
CRTC_PROP_CORE_IB);
msm_property_install_range(&sde_crtc->property_info,
+ "mem_ab", 0x0, 0, U64_MAX,
+ SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+ CRTC_PROP_MEM_AB);
+ msm_property_install_range(&sde_crtc->property_info,
+ "mem_ib", 0x0, 0, U64_MAX,
+ SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+ CRTC_PROP_MEM_IB);
+ msm_property_install_range(&sde_crtc->property_info,
"rot_prefill_bw", 0, 0, U64_MAX,
catalog->perf.max_bw_high * 1000ULL,
CRTC_PROP_ROT_PREFILL_BW);
+ msm_property_install_range(&sde_crtc->property_info,
+ "rot_clk", 0, 0, U64_MAX,
+ sde_kms->perf.max_core_clk_rate,
+ CRTC_PROP_ROT_CLK);
msm_property_install_blob(&sde_crtc->property_info, "capabilities",
DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
@@ -2021,7 +2043,7 @@
seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc));
- seq_printf(s, "intf_mode: %d\n", cstate->intf_mode);
+ seq_printf(s, "intf_mode: %d\n", sde_crtc_get_intf_mode(crtc));
seq_printf(s, "bw_ctl: %llu\n", cstate->cur_perf.bw_ctl);
seq_printf(s, "core_clk_rate: %u\n", cstate->cur_perf.core_clk_rate);
seq_printf(s, "max_per_pipe_ib: %llu\n",
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index f389196..0647ff4 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -316,16 +316,10 @@
void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
/**
- * sde_crtc_get_intf_mode - get interface mode of the given crtc
+ * sde_crtc_get_intf_mode - get primary interface mode of the given crtc
* @crtc: Pointert to crtc
*/
-static inline enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc)
-{
- struct sde_crtc_state *cstate =
- crtc ? to_sde_crtc_state(crtc->state) : NULL;
-
- return cstate ? cstate->intf_mode : INTF_MODE_NONE;
-}
+enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc);
/**
* sde_crtc_get_client_type - check the crtc type- rt, nrt, rsc, etc.
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 69d21fb..274dc6f 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -19,6 +19,7 @@
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/sde_rsc.h>
#include "msm_drv.h"
#include "sde_kms.h"
@@ -32,7 +33,6 @@
#include "sde_formats.h"
#include "sde_encoder_phys.h"
#include "sde_color_processing.h"
-#include "sde_rsc.h"
#include "sde_power_handle.h"
#include "sde_hw_dsc.h"
@@ -1857,7 +1857,7 @@
sde_enc->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX, name,
disp_info->is_primary);
if (IS_ERR_OR_NULL(sde_enc->rsc_client)) {
- SDE_ERROR("sde rsc client create failed :%ld\n",
+ SDE_DEBUG("sde rsc client create failed :%ld\n",
PTR_ERR(sde_enc->rsc_client));
sde_enc->rsc_client = NULL;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 7aa9a29..b9e802f 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -16,6 +16,7 @@
#define __SDE_ENCODER_PHYS_H__
#include <linux/jiffies.h>
+#include <linux/sde_rsc.h>
#include "sde_kms.h"
#include "sde_hw_intf.h"
@@ -27,8 +28,6 @@
#include "sde_encoder.h"
#include "sde_connector.h"
-#include "sde_rsc.h"
-
#define SDE_ENCODER_NAME_MAX 16
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 2eb947d..fc68820 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1500,6 +1500,8 @@
rot_cmd->secure = state->fb->flags & DRM_MODE_FB_SECURE ? true : false;
rot_cmd->prefill_bw = sde_crtc_get_property(sde_cstate,
CRTC_PROP_ROT_PREFILL_BW);
+ rot_cmd->clkrate = sde_crtc_get_property(sde_cstate,
+ CRTC_PROP_ROT_CLK);
rot_cmd->dst_writeback = psde->sbuf_writeback;
if (sde_crtc_get_intf_mode(state->crtc) == INTF_MODE_VIDEO)
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index 2464551..a9a7d4f 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -27,7 +27,7 @@
#include <soc/qcom/rpmh.h>
#include <drm/drmP.h>
#include <drm/drm_irq.h>
-#include "sde_rsc.h"
+#include "sde_rsc_priv.h"
/* this time is ~0.02ms */
#define RSC_BACKOFF_TIME_NS 20000
@@ -105,6 +105,7 @@
return client;
}
+EXPORT_SYMBOL(sde_rsc_client_create);
/**
* sde_rsc_client_destroy() - Destroy the sde rsc client.
@@ -141,6 +142,7 @@
end:
return;
}
+EXPORT_SYMBOL(sde_rsc_client_destroy);
struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
void (*cb_func)(uint32_t event_type, void *usr), void *usr)
@@ -178,6 +180,7 @@
return evt;
}
+EXPORT_SYMBOL(sde_rsc_register_event);
void sde_rsc_unregister_event(struct sde_rsc_event *event)
{
@@ -204,6 +207,7 @@
end:
return;
}
+EXPORT_SYMBOL(sde_rsc_unregister_event);
static int sde_rsc_clk_enable(struct sde_power_handle *phandle,
struct sde_power_client *pclient, bool enable)
@@ -583,6 +587,7 @@
mutex_unlock(&rsc->client_lock);
return rc;
}
+EXPORT_SYMBOL(sde_rsc_client_state_update);
/**
* sde_rsc_client_vote() - ab/ib vote from rsc client
@@ -661,6 +666,7 @@
mutex_unlock(&rsc->client_lock);
return rc;
}
+EXPORT_SYMBOL(sde_rsc_client_vote);
static int _sde_debugfs_status_show(struct seq_file *s, void *data)
{
diff --git a/drivers/gpu/drm/msm/sde_rsc.h b/drivers/gpu/drm/msm/sde_rsc.h
deleted file mode 100644
index 2775d21..0000000
--- a/drivers/gpu/drm/msm/sde_rsc.h
+++ /dev/null
@@ -1,368 +0,0 @@
-/* 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 _SDE_RSC_H_
-#define _SDE_RSC_H_
-
-#include <linux/kernel.h>
-#include <linux/sde_io_util.h>
-
-#include <soc/qcom/tcs.h>
-#include "sde_power_handle.h"
-
-#define SDE_RSC_COMPATIBLE "disp_rscc"
-
-#define MAX_RSC_CLIENT_NAME_LEN 128
-
-/* primary display rsc index */
-#define SDE_RSC_INDEX 0
-
-/* rsc index max count */
-#define MAX_RSC_COUNT 5
-
-struct sde_rsc_priv;
-
-/**
- * event will be triggered before sde core power collapse,
- * mdss gdsc is still on
- */
-#define SDE_RSC_EVENT_PRE_CORE_PC 0x1
-/**
- * event will be triggered after sde core collapse complete,
- * mdss gdsc is off now
- */
-#define SDE_RSC_EVENT_POST_CORE_PC 0x2
-/**
- * event will be triggered before restoring the sde core from power collapse,
- * mdss gdsc is still off
- */
-#define SDE_RSC_EVENT_PRE_CORE_RESTORE 0x4
-/**
- * event will be triggered after restoring the sde core from power collapse,
- * mdss gdsc is on now
- */
-#define SDE_RSC_EVENT_POST_CORE_RESTORE 0x8
-/**
- * event attached with solver state enabled
- * all clients in clk_state or cmd_state
- */
-#define SDE_RSC_EVENT_SOLVER_ENABLED 0x10
-/**
- * event attached with solver state disabled
- * one of the client requested for vid state
- */
-#define SDE_RSC_EVENT_SOLVER_DISABLED 0x20
-
-/**
- * rsc_mode_req: sde rsc mode request information
- * MODE_READ: read vsync status
- * MODE0_UPDATE: mode0 status , this should be 0x0
- * MODE1_UPDATE: mode1 status , this should be 0x1
- * MODE2_UPDATE: mode2 status , this should be 0x2
- */
-enum rsc_mode_req {
- MODE_READ,
- MODE0_UPDATE = 0x1,
- MODE1_UPDATE = 0x2,
- MODE2_UPDATE = 0x3,
-};
-
-/**
- * rsc_vsync_req: sde rsc vsync request information
- * VSYNC_READ: read vsync status
- * VSYNC_ENABLE: enable rsc wrapper vsync status
- * VSYNC_DISABLE: disable rsc wrapper vsync status
- */
-enum rsc_vsync_req {
- VSYNC_READ,
- VSYNC_ENABLE,
- VSYNC_DISABLE,
-};
-
-/**
- * sde_rsc_state: sde rsc state information
- * SDE_RSC_IDLE_STATE: A client requests for idle state when there is no
- * pixel or cmd transfer expected. An idle vote from
- * all clients lead to power collapse state.
- * SDE_RSC_CLK_STATE: A client requests for clk state when it wants to
- * only avoid mode-2 entry/exit. For ex: V4L2 driver,
- * sde power handle, etc.
- * SDE_RSC_CMD_STATE: A client requests for cmd state when it wants to
- * enable the solver mode.
- * SDE_RSC_VID_STATE: A client requests for vid state it wants to avoid
- * solver enable because client is fetching data from
- * continuously.
- */
-enum sde_rsc_state {
- SDE_RSC_IDLE_STATE,
- SDE_RSC_CLK_STATE,
- SDE_RSC_CMD_STATE,
- SDE_RSC_VID_STATE,
-};
-
-/**
- * struct sde_rsc_client: stores the rsc client for sde driver
- * @name: name of the client
- * @current_state: current client state
- * @crtc_id: crtc_id associated with this rsc client.
- * @rsc_index: rsc index of a client - only index "0" valid.
- * @list: list to attach client master list
- */
-struct sde_rsc_client {
- char name[MAX_RSC_CLIENT_NAME_LEN];
- short current_state;
- int crtc_id;
- u32 rsc_index;
- struct list_head list;
-};
-
-/**
- * struct sde_rsc_event: local event registration entry structure
- * @cb_func: Pointer to desired callback function
- * @usr: User pointer to pass to callback on event trigger
- * @rsc_index: rsc index of a client - only index "0" valid.
- * @event_type: refer comments in event_register
- * @list: list to attach event master list
- */
-struct sde_rsc_event {
- void (*cb_func)(uint32_t event_type, void *usr);
- void *usr;
- u32 rsc_index;
- uint32_t event_type;
- struct list_head list;
-};
-
-/**
- * struct sde_rsc_hw_ops - sde resource state coordinator hardware ops
- * @init: Initialize the sequencer, solver, qtimer,
- etc. hardware blocks on RSC.
- * @tcs_wait: Waits for TCS block OK to allow sending a
- * TCS command.
- * @hw_vsync: Enables the vsync on RSC block.
- * @tcs_use_ok: set TCS set to high to allow RSC to use it.
- * @mode2_entry: Request to entry mode2 when all clients are
- * requesting power collapse.
- * @mode2_exit: Request to exit mode2 when one of the client
- * is requesting against the power collapse
- * @is_amc_mode: Check current amc mode status
- * @state_update: Enable/override the solver based on rsc state
- * status (command/video)
- * @mode_show: shows current mode status, mode0/1/2
- * @debug_show: Show current debug status.
- */
-
-struct sde_rsc_hw_ops {
- int (*init)(struct sde_rsc_priv *rsc);
- int (*tcs_wait)(struct sde_rsc_priv *rsc);
- int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
- char *buffer, int buffer_size, u32 mode);
- int (*tcs_use_ok)(struct sde_rsc_priv *rsc);
- int (*mode2_entry)(struct sde_rsc_priv *rsc);
- int (*mode2_exit)(struct sde_rsc_priv *rsc);
- bool (*is_amc_mode)(struct sde_rsc_priv *rsc);
- int (*state_update)(struct sde_rsc_priv *rsc, enum sde_rsc_state state);
- int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc);
- int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request,
- char *buffer, int buffer_size, bool mode);
-};
-
-/**
- * struct sde_rsc_cmd_config: provides panel configuration to rsc
- * when client is command mode. It is not required to set it during
- * video mode.
- *
- * @fps: panel te interval
- * @vtotal: current vertical total (height + vbp + vfp)
- * @jitter: panel can set the jitter to wake up rsc/solver early
- * This value causes mdp core to exit certain mode
- * early. Default is 10% jitter
- * @prefill_lines: max prefill lines based on panel
- */
-struct sde_rsc_cmd_config {
- u32 fps;
- u32 vtotal;
- u32 jitter;
- u32 prefill_lines;
-};
-
-/**
- * struct sde_rsc_timer_config: this is internal configuration between
- * rsc and rsc_hw API.
- *
- * @static_wakeup_time_ns: wrapper backoff time in nano seconds
- * @rsc_backoff_time_ns: rsc backoff time in nano seconds
- * @pdc_backoff_time_ns: pdc backoff time in nano seconds
- * @rsc_mode_threshold_time_ns: rsc mode threshold time in nano seconds
- * @rsc_time_slot_0_ns: mode-0 time slot threshold in nano seconds
- * @rsc_time_slot_1_ns: mode-1 time slot threshold in nano seconds
- * @rsc_time_slot_2_ns: mode-2 time slot threshold in nano seconds
- */
-struct sde_rsc_timer_config {
- u32 static_wakeup_time_ns;
-
- u32 rsc_backoff_time_ns;
- u32 pdc_backoff_time_ns;
- u32 rsc_mode_threshold_time_ns;
- u32 rsc_time_slot_0_ns;
- u32 rsc_time_slot_1_ns;
- u32 rsc_time_slot_2_ns;
-};
-
-/**
- * struct sde_rsc_priv: sde resource state coordinator(rsc) private handle
- * @version: rsc sequence version
- * @phandle: module power handle for clocks
- * @pclient: module power client of phandle
- * @fs: "MDSS GDSC" handle
- *
- * @drv_io: sde drv io data mapping
- * @wrapper_io: wrapper io data mapping
- *
- * @client_list: current rsc client list handle
- * @event_list: current rsc event list handle
- * @client_lock: current rsc client synchronization lock
- *
- * timer_config: current rsc timer configuration
- * cmd_config: current panel config
- * current_state: current rsc state (video/command), solver
- * override/enabled.
- * debug_mode: enables the logging for each register read/write
- * debugfs_root: debugfs file system root node
- *
- * hw_ops: sde rsc hardware operations
- * power_collapse: if all clients are in IDLE state then it enters in
- * mode2 state and enable the power collapse state
- * power_collapse_block:By default, rsc move to mode-2 if all clients are in
- * invalid state. It can be blocked by this boolean entry.
- * primary_client: A client which is allowed to make command state request
- * and ab/ib vote on display rsc
- * master_drm: Primary client waits for vsync on this drm object based
- * on crtc id
- */
-struct sde_rsc_priv {
- u32 version;
- struct sde_power_handle phandle;
- struct sde_power_client *pclient;
- struct regulator *fs;
-
- struct dss_io_data drv_io;
- struct dss_io_data wrapper_io;
-
- struct list_head client_list;
- struct list_head event_list;
- struct mutex client_lock;
-
- struct sde_rsc_timer_config timer_config;
- struct sde_rsc_cmd_config cmd_config;
- u32 current_state;
-
- u32 debug_mode;
- struct dentry *debugfs_root;
-
- struct sde_rsc_hw_ops hw_ops;
- bool power_collapse;
- bool power_collapse_block;
- struct sde_rsc_client *primary_client;
-
- struct drm_device *master_drm;
-};
-
-/**
- * sde_rsc_client_create() - create the client for sde rsc.
- * Different displays like DSI, HDMI, DP, WB, etc should call this
- * api to register their vote for rpmh. They still need to vote for
- * power handle to get the clocks.
-
- * @rsc_index: A client will be created on this RSC. As of now only
- * SDE_RSC_INDEX is valid rsc index.
- * @name: Caller needs to provide some valid string to identify
- * the client. "primary", "dp", "hdmi" are suggested name.
- * @is_primary: Caller needs to provide information if client is primary
- * or not. Primary client votes will be redirected to
- * display rsc.
- * @config: fps, vtotal, porches, etc configuration for command mode
- * panel
- *
- * Return: client node pointer.
- */
-struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *name,
- bool is_primary_display);
-
-/**
- * sde_rsc_client_destroy() - Destroy the sde rsc client.
- *
- * @client: Client pointer provided by sde_rsc_client_create().
- *
- * Return: none
- */
-void sde_rsc_client_destroy(struct sde_rsc_client *client);
-
-/**
- * sde_rsc_client_state_update() - rsc client state update
- * Video mode, cmd mode and clk state are supported as modes. A client need to
- * set this property during panel time. A switching client can set the
- * property to change the state
- *
- * @client: Client pointer provided by sde_rsc_client_create().
- * @state: Client state - video/cmd
- * @config: fps, vtotal, porches, etc configuration for command mode
- * panel
- * @crtc_id: current client's crtc id
- *
- * Return: error code.
- */
-int sde_rsc_client_state_update(struct sde_rsc_client *client,
- enum sde_rsc_state state,
- struct sde_rsc_cmd_config *config, int crtc_id);
-
-/**
- * sde_rsc_client_vote() - ab/ib vote from rsc client
- *
- * @client: Client pointer provided by sde_rsc_client_create().
- * @ab: aggregated bandwidth vote from client.
- * @ib: instant bandwidth vote from client.
- *
- * Return: error code.
- */
-int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
- u64 ab_vote, u64 ib_vote);
-
-/**
- * sde_rsc_hw_register() - register hardware API
- *
- * @client: Client pointer provided by sde_rsc_client_create().
- *
- * Return: error code.
- */
-int sde_rsc_hw_register(struct sde_rsc_priv *rsc);
-
-/**
- * sde_rsc_register_event - register a callback function for an event
- * @rsc_index: A client will be created on this RSC. As of now only
- * SDE_RSC_INDEX is valid rsc index.
- * @event_type: event type to register; client sets 0x3 if it wants
- * to register for CORE_PC and CORE_RESTORE - both events.
- * @cb_func: Pointer to desired callback function
- * @usr: User pointer to pass to callback on event trigger
- * Returns: sde_rsc_event pointer on success
- */
-struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
- void (*cb_func)(uint32_t event_type, void *usr), void *usr);
-
-/**
- * sde_rsc_unregister_event - unregister callback for an event
- * @sde_rsc_event: event returned by sde_rsc_register_event
- */
-void sde_rsc_unregister_event(struct sde_rsc_event *event);
-
-#endif /* _SDE_RSC_H_ */
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index dd7f37a..fb963ee 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -17,7 +17,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
-#include "sde_rsc.h"
+#include "sde_rsc_priv.h"
/* display rsc offset */
#define SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0 0x020
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
new file mode 100644
index 0000000..2563c85
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -0,0 +1,181 @@
+/* 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 _SDE_RSC_PRIV_H_
+#define _SDE_RSC_PRIV_H_
+
+#include <linux/kernel.h>
+#include <linux/sde_io_util.h>
+#include <linux/sde_rsc.h>
+
+#include <soc/qcom/tcs.h>
+#include "sde_power_handle.h"
+
+#define SDE_RSC_COMPATIBLE "disp_rscc"
+
+#define MAX_RSC_COUNT 5
+
+struct sde_rsc_priv;
+
+/**
+ * rsc_mode_req: sde rsc mode request information
+ * MODE_READ: read vsync status
+ * MODE0_UPDATE: mode0 status , this should be 0x0
+ * MODE1_UPDATE: mode1 status , this should be 0x1
+ * MODE2_UPDATE: mode2 status , this should be 0x2
+ */
+enum rsc_mode_req {
+ MODE_READ,
+ MODE0_UPDATE = 0x1,
+ MODE1_UPDATE = 0x2,
+ MODE2_UPDATE = 0x3,
+};
+
+/**
+ * rsc_vsync_req: sde rsc vsync request information
+ * VSYNC_READ: read vsync status
+ * VSYNC_ENABLE: enable rsc wrapper vsync status
+ * VSYNC_DISABLE: disable rsc wrapper vsync status
+ */
+enum rsc_vsync_req {
+ VSYNC_READ,
+ VSYNC_ENABLE,
+ VSYNC_DISABLE,
+};
+
+/**
+ * struct sde_rsc_hw_ops - sde resource state coordinator hardware ops
+ * @init: Initialize the sequencer, solver, qtimer,
+ etc. hardware blocks on RSC.
+ * @tcs_wait: Waits for TCS block OK to allow sending a
+ * TCS command.
+ * @hw_vsync: Enables the vsync on RSC block.
+ * @tcs_use_ok: set TCS set to high to allow RSC to use it.
+ * @mode2_entry: Request to entry mode2 when all clients are
+ * requesting power collapse.
+ * @mode2_exit: Request to exit mode2 when one of the client
+ * is requesting against the power collapse
+ * @is_amc_mode: Check current amc mode status
+ * @state_update: Enable/override the solver based on rsc state
+ * status (command/video)
+ * @mode_show: shows current mode status, mode0/1/2
+ * @debug_show: Show current debug status.
+ */
+
+struct sde_rsc_hw_ops {
+ int (*init)(struct sde_rsc_priv *rsc);
+ int (*tcs_wait)(struct sde_rsc_priv *rsc);
+ int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
+ char *buffer, int buffer_size, u32 mode);
+ int (*tcs_use_ok)(struct sde_rsc_priv *rsc);
+ int (*mode2_entry)(struct sde_rsc_priv *rsc);
+ int (*mode2_exit)(struct sde_rsc_priv *rsc);
+ bool (*is_amc_mode)(struct sde_rsc_priv *rsc);
+ int (*state_update)(struct sde_rsc_priv *rsc, enum sde_rsc_state state);
+ int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc);
+ int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request,
+ char *buffer, int buffer_size, bool mode);
+};
+
+/**
+ * struct sde_rsc_timer_config: this is internal configuration between
+ * rsc and rsc_hw API.
+ *
+ * @static_wakeup_time_ns: wrapper backoff time in nano seconds
+ * @rsc_backoff_time_ns: rsc backoff time in nano seconds
+ * @pdc_backoff_time_ns: pdc backoff time in nano seconds
+ * @rsc_mode_threshold_time_ns: rsc mode threshold time in nano seconds
+ * @rsc_time_slot_0_ns: mode-0 time slot threshold in nano seconds
+ * @rsc_time_slot_1_ns: mode-1 time slot threshold in nano seconds
+ * @rsc_time_slot_2_ns: mode-2 time slot threshold in nano seconds
+ */
+struct sde_rsc_timer_config {
+ u32 static_wakeup_time_ns;
+
+ u32 rsc_backoff_time_ns;
+ u32 pdc_backoff_time_ns;
+ u32 rsc_mode_threshold_time_ns;
+ u32 rsc_time_slot_0_ns;
+ u32 rsc_time_slot_1_ns;
+ u32 rsc_time_slot_2_ns;
+};
+
+/**
+ * struct sde_rsc_priv: sde resource state coordinator(rsc) private handle
+ * @version: rsc sequence version
+ * @phandle: module power handle for clocks
+ * @pclient: module power client of phandle
+ * @fs: "MDSS GDSC" handle
+ *
+ * @drv_io: sde drv io data mapping
+ * @wrapper_io: wrapper io data mapping
+ *
+ * @client_list: current rsc client list handle
+ * @event_list: current rsc event list handle
+ * @client_lock: current rsc client synchronization lock
+ *
+ * timer_config: current rsc timer configuration
+ * cmd_config: current panel config
+ * current_state: current rsc state (video/command), solver
+ * override/enabled.
+ * debug_mode: enables the logging for each register read/write
+ * debugfs_root: debugfs file system root node
+ *
+ * hw_ops: sde rsc hardware operations
+ * power_collapse: if all clients are in IDLE state then it enters in
+ * mode2 state and enable the power collapse state
+ * power_collapse_block:By default, rsc move to mode-2 if all clients are in
+ * invalid state. It can be blocked by this boolean entry.
+ * primary_client: A client which is allowed to make command state request
+ * and ab/ib vote on display rsc
+ * master_drm: Primary client waits for vsync on this drm object based
+ * on crtc id
+ */
+struct sde_rsc_priv {
+ u32 version;
+ struct sde_power_handle phandle;
+ struct sde_power_client *pclient;
+ struct regulator *fs;
+
+ struct dss_io_data drv_io;
+ struct dss_io_data wrapper_io;
+
+ struct list_head client_list;
+ struct list_head event_list;
+ struct mutex client_lock;
+
+ struct sde_rsc_timer_config timer_config;
+ struct sde_rsc_cmd_config cmd_config;
+ u32 current_state;
+
+ u32 debug_mode;
+ struct dentry *debugfs_root;
+
+ struct sde_rsc_hw_ops hw_ops;
+ bool power_collapse;
+ bool power_collapse_block;
+ struct sde_rsc_client *primary_client;
+
+ struct drm_device *master_drm;
+};
+
+/**
+ * sde_rsc_hw_register() - register hardware API
+ *
+ * @client: Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: error code.
+ */
+int sde_rsc_hw_register(struct sde_rsc_priv *rsc);
+
+#endif /* _SDE_RSC_PRIV_H_ */
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 3fa38fa..4d1f1ad 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2055,12 +2055,13 @@
return 0;
/*
- * On A5xx, read RBBM_STATUS3:SMMU_STALLED_ON_FAULT (BIT 24) to
- * tell if this function was entered after a pagefault. If so, only
+ * On A5xx and A6xx, read RBBM_STATUS3:SMMU_STALLED_ON_FAULT (BIT 24)
+ * to tell if this function was entered after a pagefault. If so, only
* proceed if the fault handler has already run in the IRQ thread,
* else return early to give the fault handler a chance to run.
*/
- if (!(fault & ADRENO_IOMMU_PAGE_FAULT) && adreno_is_a5xx(adreno_dev)) {
+ if (!(fault & ADRENO_IOMMU_PAGE_FAULT) &&
+ (adreno_is_a5xx(adreno_dev) || adreno_is_a6xx(adreno_dev))) {
unsigned int val;
mutex_lock(&device->mutex);
@@ -2086,7 +2087,7 @@
*/
if (!(fault & ADRENO_HARD_FAULT)) {
adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, ®);
- if (adreno_is_a5xx(adreno_dev))
+ if (adreno_is_a5xx(adreno_dev) || adreno_is_a6xx(adreno_dev))
reg |= 1 | (1 << 1);
else
reg |= (1 << 27) | (1 << 28);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 78182b7..32175f5 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -796,10 +796,10 @@
dwords += 6;
/*
- * REG_TO_MEM packet on A5xx needs another ordinal.
+ * REG_TO_MEM packet on A5xx and above needs another ordinal.
* Add 2 more dwords since we do profiling before and after.
*/
- if (adreno_is_a5xx(adreno_dev))
+ if (!ADRENO_LEGACY_PM4(adreno_dev))
dwords += 2;
/*
@@ -816,7 +816,7 @@
if (test_bit(CMDOBJ_PROFILE, &cmdobj->priv)) {
kernel_profiling = true;
dwords += 6;
- if (adreno_is_a5xx(adreno_dev))
+ if (!ADRENO_LEGACY_PM4(adreno_dev))
dwords += 2;
}
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index be34547..1606e7f 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -506,12 +506,15 @@
wait_for_completion(&info->waitevent);
- if (channel->rescind) {
- ret = -ENODEV;
- goto post_msg_err;
- }
-
post_msg_err:
+ /*
+ * If the channel has been rescinded;
+ * we will be awakened by the rescind
+ * handler; set the error code to zero so we don't leak memory.
+ */
+ if (channel->rescind)
+ ret = 0;
+
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&info->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index cb95315..d8bc4b9 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -779,6 +779,7 @@
/* Allocate the channel object and save this offer. */
newchannel = alloc_channel();
if (!newchannel) {
+ vmbus_release_relid(offer->child_relid);
pr_err("Unable to allocate channel object\n");
return;
}
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 6f0a51a..d439736 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -218,8 +218,10 @@
else
intel_th_trace_enable(thdev);
- if (ret)
+ if (ret) {
pm_runtime_put(&thdev->dev);
+ module_put(thdrv->driver.owner);
+ }
return ret;
}
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index c3cfacc..2de1f52 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -151,7 +151,9 @@
{
struct iio_dev *indio_dev = private;
struct tiadc_device *adc_dev = iio_priv(indio_dev);
- unsigned int status, config;
+ unsigned int status, config, adc_fsm;
+ unsigned short count = 0;
+
status = tiadc_readl(adc_dev, REG_IRQSTATUS);
/*
@@ -165,6 +167,15 @@
tiadc_writel(adc_dev, REG_CTRL, config);
tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN
| IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES);
+
+ /* wait for idle state.
+ * ADC needs to finish the current conversion
+ * before disabling the module
+ */
+ do {
+ adc_fsm = tiadc_readl(adc_dev, REG_ADCFSM);
+ } while (adc_fsm != 0x10 && count++ < 100);
+
tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
return IRQ_HANDLED;
} else if (status & IRQENB_FIFO1THRES) {
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index a3cce3a..ecf592d 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -51,8 +51,6 @@
st->report_state.report_id,
st->report_state.index,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
-
- poll_value = hid_sensor_read_poll_value(st);
} else {
int val;
@@ -89,7 +87,9 @@
sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
sizeof(state_val), &state_val);
- if (state && poll_value)
+ if (state)
+ poll_value = hid_sensor_read_poll_value(st);
+ if (poll_value > 0)
msleep_interruptible(poll_value * 2);
return 0;
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index 2173531..dd3fcd1 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -767,7 +767,7 @@
return ret;
}
-static int __exit ak8974_remove(struct i2c_client *i2c)
+static int ak8974_remove(struct i2c_client *i2c)
{
struct iio_dev *indio_dev = i2c_get_clientdata(i2c);
struct ak8974 *ak8974 = iio_priv(indio_dev);
@@ -849,7 +849,7 @@
.of_match_table = of_match_ptr(ak8974_of_match),
},
.probe = ak8974_probe,
- .remove = __exit_p(ak8974_remove),
+ .remove = ak8974_remove,
.id_table = ak8974_id,
};
module_i2c_driver(ak8974_driver);
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index d96aa27..db64adf 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -141,6 +141,9 @@
interface = intf->cur_altsetting;
+ if (interface->desc.bNumEndpoints < 2)
+ return -ENODEV;
+
epirq = &interface->endpoint[0].desc;
epout = &interface->endpoint[1].desc;
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index 9cc6d05..23c191a 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -700,6 +700,10 @@
int error = -ENOMEM;
interface = intf->cur_altsetting;
+
+ if (interface->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
endpoint = &interface->endpoint[0].desc;
if (!usb_endpoint_is_int_in(endpoint))
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 9c0ea36..f4e8fbe 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -1667,6 +1667,10 @@
return -EINVAL;
alt = pcu->ctrl_intf->cur_altsetting;
+
+ if (alt->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
pcu->ep_ctrl = &alt->endpoint[0].desc;
pcu->max_ctrl_size = usb_endpoint_maxp(pcu->ep_ctrl);
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index 79c964c..6e7ff95 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -875,6 +875,10 @@
int ret, pipe, i;
interface = intf->cur_altsetting;
+
+ if (interface->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
endpoint = &interface->endpoint[0].desc;
if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index b93fe83..518e8a7 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1290,10 +1290,8 @@
/* handle buttons */
if (pkt_id == SS4_PACKET_ID_STICK) {
f->ts_left = !!(SS4_BTN_V2(p) & 0x01);
- if (!(priv->flags & ALPS_BUTTONPAD)) {
- f->ts_right = !!(SS4_BTN_V2(p) & 0x02);
- f->ts_middle = !!(SS4_BTN_V2(p) & 0x04);
- }
+ f->ts_right = !!(SS4_BTN_V2(p) & 0x02);
+ f->ts_middle = !!(SS4_BTN_V2(p) & 0x04);
} else {
f->left = !!(SS4_BTN_V2(p) & 0x01);
if (!(priv->flags & ALPS_BUTTONPAD)) {
@@ -2461,14 +2459,34 @@
int num_y_electrode;
int x_pitch, y_pitch, x_phys, y_phys;
- num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
- num_y_electrode = SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ num_x_electrode =
+ SS4PLUS_NUMSENSOR_XOFFSET + (otp[0][2] & 0x0F);
+ num_y_electrode =
+ SS4PLUS_NUMSENSOR_YOFFSET + ((otp[0][2] >> 4) & 0x0F);
- priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
- priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+ priv->x_max =
+ (num_x_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE;
+ priv->y_max =
+ (num_y_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE;
- x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM;
- y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM;
+ x_pitch = (otp[0][1] & 0x0F) + SS4PLUS_MIN_PITCH_MM;
+ y_pitch = ((otp[0][1] >> 4) & 0x0F) + SS4PLUS_MIN_PITCH_MM;
+
+ } else {
+ num_x_electrode =
+ SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
+ num_y_electrode =
+ SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F);
+
+ priv->x_max =
+ (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+ priv->y_max =
+ (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+
+ x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM;
+ y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM;
+ }
x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */
y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */
@@ -2484,7 +2502,10 @@
{
unsigned char is_btnless;
- is_btnless = (otp[1][1] >> 3) & 0x01;
+ if (IS_SS4PLUS_DEV(priv->dev_id))
+ is_btnless = (otp[1][0] >> 1) & 0x01;
+ else
+ is_btnless = (otp[1][1] >> 3) & 0x01;
if (is_btnless)
priv->flags |= ALPS_BUTTONPAD;
@@ -2492,6 +2513,21 @@
return 0;
}
+static int alps_update_dual_info_ss4_v2(unsigned char otp[][4],
+ struct alps_data *priv)
+{
+ bool is_dual = false;
+
+ if (IS_SS4PLUS_DEV(priv->dev_id))
+ is_dual = (otp[0][0] >> 4) & 0x01;
+
+ if (is_dual)
+ priv->flags |= ALPS_DUALPOINT |
+ ALPS_DUALPOINT_WITH_PRESSURE;
+
+ return 0;
+}
+
static int alps_set_defaults_ss4_v2(struct psmouse *psmouse,
struct alps_data *priv)
{
@@ -2507,6 +2543,8 @@
alps_update_btn_info_ss4_v2(otp, priv);
+ alps_update_dual_info_ss4_v2(otp, priv);
+
return 0;
}
@@ -2752,10 +2790,6 @@
if (alps_set_defaults_ss4_v2(psmouse, priv))
return -EIO;
- if (priv->fw_ver[1] == 0x1)
- priv->flags |= ALPS_DUALPOINT |
- ALPS_DUALPOINT_WITH_PRESSURE;
-
break;
}
@@ -2826,10 +2860,7 @@
ec[2] >= 0x90 && ec[2] <= 0x9d) {
protocol = &alps_v3_protocol_data;
} else if (e7[0] == 0x73 && e7[1] == 0x03 &&
- e7[2] == 0x14 && ec[1] == 0x02) {
- protocol = &alps_v8_protocol_data;
- } else if (e7[0] == 0x73 && e7[1] == 0x03 &&
- e7[2] == 0x28 && ec[1] == 0x01) {
+ (e7[2] == 0x14 || e7[2] == 0x28)) {
protocol = &alps_v8_protocol_data;
} else {
psmouse_dbg(psmouse,
@@ -2839,7 +2870,8 @@
}
if (priv) {
- /* Save the Firmware version */
+ /* Save Device ID and Firmware version */
+ memcpy(priv->dev_id, e7, 3);
memcpy(priv->fw_ver, ec, 3);
error = alps_set_protocol(psmouse, priv, protocol);
if (error)
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index b9417e2..dbfd260 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -54,6 +54,16 @@
#define SS4_MASK_NORMAL_BUTTONS 0x07
+#define SS4PLUS_COUNT_PER_ELECTRODE 128
+#define SS4PLUS_NUMSENSOR_XOFFSET 16
+#define SS4PLUS_NUMSENSOR_YOFFSET 5
+#define SS4PLUS_MIN_PITCH_MM 37
+
+#define IS_SS4PLUS_DEV(_b) (((_b[0]) == 0x73) && \
+ ((_b[1]) == 0x03) && \
+ ((_b[2]) == 0x28) \
+ )
+
#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \
((_b[1] << 3) & 0x0078) | \
((_b[1] << 2) & 0x0380) | \
@@ -263,6 +273,7 @@
int addr_command;
u16 proto_version;
u8 byte0, mask0;
+ u8 dev_id[3];
u8 fw_ver[3];
int flags;
int x_max;
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index ed1935f..da5458d 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -218,17 +218,19 @@
static int elan_check_ASUS_special_fw(struct elan_tp_data *data)
{
- if (data->ic_type != 0x0E)
- return false;
-
- switch (data->product_id) {
- case 0x05 ... 0x07:
- case 0x09:
- case 0x13:
+ if (data->ic_type == 0x0E) {
+ switch (data->product_id) {
+ case 0x05 ... 0x07:
+ case 0x09:
+ case 0x13:
+ return true;
+ }
+ } else if (data->ic_type == 0x08 && data->product_id == 0x26) {
+ /* ASUS EeeBook X205TA */
return true;
- default:
- return false;
}
+
+ return false;
}
static int __elan_initialize(struct elan_tp_data *data)
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 0cdd958..25eab45 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -120,6 +120,13 @@
},
},
{
+ /* Dell Embedded Box PC 3000 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"),
+ },
+ },
+ {
/* OQO Model 01 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c
index cd85205..df4bea9 100644
--- a/drivers/input/tablet/hanwang.c
+++ b/drivers/input/tablet/hanwang.c
@@ -340,6 +340,9 @@
int error;
int i;
+ if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL);
input_dev = input_allocate_device();
if (!hanwang || !input_dev) {
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index e850d7e..4d9d649 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -122,6 +122,9 @@
struct input_dev *input_dev;
int error = -ENOMEM;
+ if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
input_dev = input_allocate_device();
if (!kbtab || !input_dev)
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index aefb6e1..4c0eeca 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -527,6 +527,9 @@
if (iface_desc->desc.bInterfaceClass != 0xFF)
return -ENODEV;
+ if (iface_desc->desc.bNumEndpoints < 5)
+ return -ENODEV;
+
/* Use endpoint #4 (0x86). */
endpoint = &iface_desc->endpoint[4].desc;
if (endpoint->bEndpointAddress != TOUCH_ENDPOINT)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 37dfe0a..0850563 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -322,9 +322,6 @@
void (*device_reset)(struct arm_smmu_device *smmu);
phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
dma_addr_t iova);
- void (*iova_to_phys_fault)(struct iommu_domain *domain,
- dma_addr_t iova, phys_addr_t *phys1,
- phys_addr_t *phys_post_tlbiall);
};
struct arm_smmu_impl_def_reg {
@@ -499,6 +496,7 @@
struct arm_smmu_domain {
struct arm_smmu_device *smmu;
+ struct device *dev;
struct io_pgtable_ops *pgtbl_ops;
struct io_pgtable_cfg pgtbl_cfg;
spinlock_t pgtbl_lock;
@@ -1141,32 +1139,21 @@
dma_addr_t iova, u32 fsr)
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- struct arm_smmu_device *smmu;
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
phys_addr_t phys;
phys_addr_t phys_post_tlbiall;
- smmu = smmu_domain->smmu;
-
- if (smmu->arch_ops && smmu->arch_ops->iova_to_phys_fault) {
- smmu->arch_ops->iova_to_phys_fault(domain, iova, &phys,
- &phys_post_tlbiall);
- } else {
- phys = arm_smmu_iova_to_phys_hard(domain, iova);
- arm_smmu_tlb_inv_context(smmu_domain);
- phys_post_tlbiall = arm_smmu_iova_to_phys_hard(domain, iova);
- }
+ phys = arm_smmu_iova_to_phys_hard(domain, iova);
+ arm_smmu_tlb_inv_context(smmu_domain);
+ phys_post_tlbiall = arm_smmu_iova_to_phys_hard(domain, iova);
if (phys != phys_post_tlbiall) {
dev_err(smmu->dev,
"ATOS results differed across TLBIALL...\n"
"Before: %pa After: %pa\n", &phys, &phys_post_tlbiall);
}
- if (!phys_post_tlbiall) {
- dev_err(smmu->dev,
- "ATOS still failed. If the page tables look good (check the software table walk) then hardware might be misbehaving.\n");
- }
- return phys_post_tlbiall;
+ return (phys == 0 ? phys_post_tlbiall : phys);
}
static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
@@ -1260,8 +1247,11 @@
dev_err(smmu->dev,
"SOFTWARE TABLE WALK FAILED! Looks like %s accessed an unmapped address!\n",
dev_name(smmu->dev));
- dev_err(smmu->dev,
- "hard iova-to-phys (ATOS)=%pa\n", &phys_atos);
+ if (phys_atos)
+ dev_err(smmu->dev, "hard iova-to-phys (ATOS)=%pa\n",
+ &phys_atos);
+ else
+ dev_err(smmu->dev, "hard iova-to-phys (ATOS) failed\n");
dev_err(smmu->dev, "SID=0x%x\n", frsynra);
}
ret = IRQ_NONE;
@@ -1493,7 +1483,8 @@
}
static int arm_smmu_init_domain_context(struct iommu_domain *domain,
- struct arm_smmu_device *smmu)
+ struct arm_smmu_device *smmu,
+ struct device *dev)
{
int irq, start, ret = 0;
unsigned long ias, oas;
@@ -1642,6 +1633,7 @@
};
smmu_domain->smmu = smmu;
+ smmu_domain->dev = dev;
pgtbl_ops = alloc_io_pgtable_ops(fmt, &smmu_domain->pgtbl_cfg,
smmu_domain);
if (!pgtbl_ops) {
@@ -2130,7 +2122,7 @@
return ret;
/* Ensure that the domain is finalised */
- ret = arm_smmu_init_domain_context(domain, smmu);
+ ret = arm_smmu_init_domain_context(domain, smmu, dev);
if (ret < 0)
goto out_power_off;
@@ -2331,9 +2323,11 @@
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
if (smmu_domain->smmu->arch_ops &&
- smmu_domain->smmu->arch_ops->iova_to_phys_hard)
- return smmu_domain->smmu->arch_ops->iova_to_phys_hard(
+ smmu_domain->smmu->arch_ops->iova_to_phys_hard) {
+ ret = smmu_domain->smmu->arch_ops->iova_to_phys_hard(
domain, iova);
+ return ret;
+ }
spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS &&
@@ -3068,64 +3062,27 @@
qsmmuv2_resume(smmu);
}
-static phys_addr_t __qsmmuv2_iova_to_phys_hard(struct iommu_domain *domain,
- dma_addr_t iova, bool halt)
+static phys_addr_t qsmmuv2_iova_to_phys_hard(struct iommu_domain *domain,
+ dma_addr_t iova)
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_device *smmu = smmu_domain->smmu;
int ret;
phys_addr_t phys = 0;
unsigned long flags;
+ u32 sctlr, sctlr_orig, fsr;
+ void __iomem *cb_base;
ret = arm_smmu_power_on(smmu_domain->smmu->pwr);
if (ret)
- return 0;
+ return ret;
- if (halt) {
- ret = qsmmuv2_halt(smmu);
- if (ret)
- goto out_power_off;
- }
-
- spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
- spin_lock(&smmu->atos_lock);
- phys = __arm_smmu_iova_to_phys_hard(domain, iova);
- spin_unlock(&smmu->atos_lock);
- spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
-
- if (halt)
- qsmmuv2_resume(smmu);
-
-out_power_off:
- arm_smmu_power_off(smmu_domain->smmu->pwr);
- return phys;
-}
-
-static phys_addr_t qsmmuv2_iova_to_phys_hard(struct iommu_domain *domain,
- dma_addr_t iova)
-{
- return __qsmmuv2_iova_to_phys_hard(domain, iova, true);
-}
-
-static void qsmmuv2_iova_to_phys_fault(
- struct iommu_domain *domain,
- dma_addr_t iova, phys_addr_t *phys,
- phys_addr_t *phys_post_tlbiall)
-{
- struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
- struct arm_smmu_device *smmu;
- void __iomem *cb_base;
- u64 sctlr, sctlr_orig;
- u32 fsr;
-
- smmu = smmu_domain->smmu;
- cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ spin_lock_irqsave(&smmu->atos_lock, flags);
+ cb_base = ARM_SMMU_CB_BASE(smmu) +
+ ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx);
qsmmuv2_halt_nowait(smmu);
-
writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME);
-
qsmmuv2_wait_for_halt(smmu);
/* clear FSR to allow ATOS to log any faults */
@@ -3137,20 +3094,21 @@
sctlr = sctlr_orig & ~SCTLR_CFCFG;
writel_relaxed(sctlr, cb_base + ARM_SMMU_CB_SCTLR);
- *phys = __qsmmuv2_iova_to_phys_hard(domain, iova, false);
- arm_smmu_tlb_inv_context(smmu_domain);
- *phys_post_tlbiall = __qsmmuv2_iova_to_phys_hard(domain, iova, false);
+ phys = __arm_smmu_iova_to_phys_hard(domain, iova);
/* restore SCTLR */
writel_relaxed(sctlr_orig, cb_base + ARM_SMMU_CB_SCTLR);
qsmmuv2_resume(smmu);
+ spin_unlock_irqrestore(&smmu->atos_lock, flags);
+
+ arm_smmu_power_off(smmu_domain->smmu->pwr);
+ return phys;
}
struct arm_smmu_arch_ops qsmmuv2_arch_ops = {
.device_reset = qsmmuv2_device_reset,
.iova_to_phys_hard = qsmmuv2_iova_to_phys_hard,
- .iova_to_phys_fault = qsmmuv2_iova_to_phys_fault,
};
static void arm_smmu_context_bank_reset(struct arm_smmu_device *smmu)
@@ -3996,6 +3954,10 @@
#define TBU_DBG_TIMEOUT_US 30000
+struct qsmmuv500_archdata {
+ struct list_head tbus;
+};
+
struct qsmmuv500_tbu_device {
struct list_head list;
struct device *dev;
@@ -4013,10 +3975,10 @@
static int qsmmuv500_tbu_power_on_all(struct arm_smmu_device *smmu)
{
struct qsmmuv500_tbu_device *tbu;
- struct list_head *list = smmu->archdata;
+ struct qsmmuv500_archdata *data = smmu->archdata;
int ret = 0;
- list_for_each_entry(tbu, list, list) {
+ list_for_each_entry(tbu, &data->tbus, list) {
ret = arm_smmu_power_on(tbu->pwr);
if (ret)
break;
@@ -4024,7 +3986,7 @@
if (!ret)
return 0;
- list_for_each_entry_continue_reverse(tbu, list, list) {
+ list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
arm_smmu_power_off(tbu->pwr);
}
return ret;
@@ -4033,9 +3995,9 @@
static void qsmmuv500_tbu_power_off_all(struct arm_smmu_device *smmu)
{
struct qsmmuv500_tbu_device *tbu;
- struct list_head *list = smmu->archdata;
+ struct qsmmuv500_archdata *data = smmu->archdata;
- list_for_each_entry_reverse(tbu, list, list) {
+ list_for_each_entry_reverse(tbu, &data->tbus, list) {
arm_smmu_power_off(tbu->pwr);
}
}
@@ -4101,10 +4063,10 @@
static int qsmmuv500_halt_all(struct arm_smmu_device *smmu)
{
struct qsmmuv500_tbu_device *tbu;
- struct list_head *list = smmu->archdata;
+ struct qsmmuv500_archdata *data = smmu->archdata;
int ret = 0;
- list_for_each_entry(tbu, list, list) {
+ list_for_each_entry(tbu, &data->tbus, list) {
ret = qsmmuv500_tbu_halt(tbu);
if (ret)
break;
@@ -4113,7 +4075,7 @@
if (!ret)
return 0;
- list_for_each_entry_continue_reverse(tbu, list, list) {
+ list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
qsmmuv500_tbu_resume(tbu);
}
return ret;
@@ -4122,9 +4084,9 @@
static void qsmmuv500_resume_all(struct arm_smmu_device *smmu)
{
struct qsmmuv500_tbu_device *tbu;
- struct list_head *list = smmu->archdata;
+ struct qsmmuv500_archdata *data = smmu->archdata;
- list_for_each_entry(tbu, list, list) {
+ list_for_each_entry(tbu, &data->tbus, list) {
qsmmuv500_tbu_resume(tbu);
}
}
@@ -4169,15 +4131,15 @@
static int qsmmuv500_arch_init(struct arm_smmu_device *smmu)
{
struct device *dev = smmu->dev;
- struct list_head *list;
+ struct qsmmuv500_archdata *data;
int ret;
- list = devm_kzalloc(dev, sizeof(*list), GFP_KERNEL);
- if (!list)
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
return -ENOMEM;
- INIT_LIST_HEAD(list);
- smmu->archdata = list;
+ INIT_LIST_HEAD(&data->tbus);
+ smmu->archdata = data;
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
if (ret)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 34be95e..b9e50c1 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -915,7 +915,7 @@
* which we used for the IOMMU lookup. Strictly speaking
* we could do this for all PCI devices; we only need to
* get the BDF# from the scope table for ACPI matches. */
- if (pdev->is_virtfn)
+ if (pdev && pdev->is_virtfn)
goto got_pdev;
*bus = drhd->devices[i].bus;
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index c041db6..0db8a6d 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -151,4 +151,11 @@
Support for communication with the hardened-RPM blocks in
Qualcomm Technologies Inc (QTI) SoCs using TCS hardware mailbox.
+config MSM_QMP
+ bool "QTI Mailbox Protocol(QMP)"
+ depends on MSM_SMEM
+ help
+ QMP is a lightweight communication protocol for sending messages to
+ a remote processor. This protocol fits into the Generic Mailbox
+ Framework. QMP uses a mailbox located in shared memory.
endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 0a01d79..3c811d3 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -31,3 +31,5 @@
obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o
obj-$(CONFIG_QTI_RPMH_MBOX) += qti-tcs.o
+
+obj-$(CONFIG_MSM_QMP) += msm_qmp.o
diff --git a/drivers/mailbox/msm_qmp.c b/drivers/mailbox/msm_qmp.c
new file mode 100644
index 0000000..dd022d3
--- /dev/null
+++ b/drivers/mailbox/msm_qmp.c
@@ -0,0 +1,811 @@
+/* Copyright (c) 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/io.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/kthread.h>
+#include <linux/workqueue.h>
+#include <linux/mailbox/qmp.h>
+
+#define QMP_MAGIC 0x4d41494c /* MAIL */
+#define QMP_VERSION 0x1
+#define QMP_FEATURES 0x0
+#define QMP_NUM_CHANS 0x1
+#define QMP_TOUT_MS 5000
+#define QMP_TX_TOUT_MS 2000
+
+#define QMP_MBOX_LINK_DOWN 0xFFFF0000
+#define QMP_MBOX_LINK_UP 0x0000FFFF
+#define QMP_MBOX_CH_DISCONNECTED 0xFFFF0000
+#define QMP_MBOX_CH_CONNECTED 0x0000FFFF
+
+#define MSG_RAM_ALIGN_BYTES 3
+
+/**
+ * enum qmp_local_state - definition of the local state machine
+ * @LINK_DISCONNECTED: Init state, waiting for ucore to start
+ * @LINK_NEGOTIATION: Set local link state to up, wait for ucore ack
+ * @LINK_CONNECTED: Link state up, channel not connected
+ * @LOCAL_CONNECTING: Channel opening locally, wait for ucore ack
+ * @LOCAL_CONNECTED: Channel opened locally
+ * @CHANNEL_CONNECTED: Channel fully opened
+ * @LOCAL_DISCONNECTING: Channel closing locally, wait for ucore ack
+ */
+enum qmp_local_state {
+ LINK_DISCONNECTED,
+ LINK_NEGOTIATION,
+ LINK_CONNECTED,
+ LOCAL_CONNECTING,
+ LOCAL_CONNECTED,
+ CHANNEL_CONNECTED,
+ LOCAL_DISCONNECTING,
+};
+
+/**
+ * struct channel_desc - description of a core's link, channel and mailbox state
+ * @link_state Current link state of core
+ * @link_state_ack Ack for other core to use when link state changes
+ * @ch_state Current channel state of core
+ * @ch_state_ack Ack for other core to use when channel state changes
+ * @mailbox_size Size of this core's mailbox
+ * @mailbox_offset Location of core's mailbox from a base smem location
+ */
+struct channel_desc {
+ u32 link_state;
+ u32 link_state_ack;
+ u32 ch_state;
+ u32 ch_state_ack;
+ u32 mailbox_size;
+ u32 mailbox_offset;
+};
+
+/**
+ * struct mbox_desc - description of the protocol's mailbox state
+ * @magic Magic number field to be set by ucore
+ * @version Version field to be set by ucore
+ * @features Features field to be set by ucore
+ * @ucore Channel descriptor to hold state of ucore
+ * @mcore Channel descriptor to hold state of mcore
+ * @reserved Reserved in case of future use
+ *
+ * This structure resides in SMEM and contains the control information for the
+ * mailbox channel. Each core in the link will have one channel descriptor
+ */
+struct mbox_desc {
+ u32 magic;
+ u32 version;
+ u32 features;
+ struct channel_desc ucore;
+ struct channel_desc mcore;
+ u32 reserved;
+};
+
+/**
+ * struct qmp_core_version - local structure to hold version and features
+ * @version Version field to indicate what version the ucore supports
+ * @features Features field to indicate what features the ucore supports
+ */
+struct qmp_core_version {
+ u32 version;
+ u32 features;
+};
+
+/**
+ * struct qmp_device - local information for managing a single mailbox
+ * @dev: The device that corresponds to this mailbox
+ * @mbox: The mbox controller for this mailbox
+ * @name: The name of this mailbox
+ * @local_state: Current state of the mailbox protocol
+ * @link_complete: Use to block until link negotiation with remote proc
+ * is complete
+ * @ch_complete: Use to block until the channel is fully opened
+ * @tx_sent: True if tx is sent and remote proc has not sent ack
+ * @ch_in_use: True if this mailbox's channel owned by a client
+ * @rx_buf: buffer to pass to client, holds copied data from mailbox
+ * @version: Version and features received during link negotiation
+ * @mcore_mbox_offset: Offset of mcore mbox from the msgram start
+ * @mcore_mbox_size: Size of the mcore mbox
+ * @desc: Reference to the mailbox descriptor in SMEM
+ * @msgram: Reference to the start of msgram
+ * @irq_mask: Mask written to @tx_irq_reg to trigger irq
+ * @tx_irq_reg: Reference to the register to send an irq to remote proc
+ * @rx_reset_reg: Reference to the register to reset the rx irq, if
+ * applicable
+ * @rx_irq_line: The incoming interrupt line
+ * @tx_irq_count: Number of tx interrupts triggered
+ * @rx_irq_count: Number of rx interrupts received
+ * @kwork: Work to be executed when an irq is received
+ * @kworker: Handle to entitiy to process incoming data
+ * @task: Handle to task context used to run @kworker
+ * @state_lock: Serialize mailbox state changes
+ * @dwork: Delayed work to detect timed out tx
+ * @tx_lock: Serialize access for writes to mailbox
+ */
+struct qmp_device {
+ struct device *dev;
+ struct mbox_controller *mbox;
+ const char *name;
+ enum qmp_local_state local_state;
+ struct completion link_complete;
+ struct completion ch_complete;
+ bool tx_sent;
+ bool ch_in_use;
+ struct qmp_pkt rx_pkt;
+ struct qmp_core_version version;
+ u32 mcore_mbox_offset;
+ u32 mcore_mbox_size;
+ void __iomem *desc;
+ void __iomem *msgram;
+ u32 irq_mask;
+ void __iomem *tx_irq_reg;
+ void __iomem *rx_reset_reg;
+ u32 rx_irq_line;
+ u32 tx_irq_count;
+ u32 rx_irq_count;
+ struct kthread_work kwork;
+ struct kthread_worker kworker;
+ struct task_struct *task;
+ struct mutex state_lock;
+ struct delayed_work dwork;
+ spinlock_t tx_lock;
+};
+
+/**
+ * send_irq() - send an irq to a remote entity as an event signal.
+ * @mdev: Which remote entity that should receive the irq.
+ */
+static void send_irq(struct qmp_device *mdev)
+{
+ /*
+ * Any data associated with this event must be visable to the remote
+ * before the interrupt is triggered
+ */
+ wmb();
+ writel_relaxed(mdev->irq_mask, mdev->tx_irq_reg);
+ mdev->tx_irq_count++;
+}
+
+/**
+ * qmp_irq_handler() - handle irq from remote entitity.
+ * @irq: irq number for the trggered interrupt.
+ * @priv: private pointer to qmp mbox device.
+ */
+irqreturn_t qmp_irq_handler(int irq, void *priv)
+{
+ struct qmp_device *mdev = (struct qmp_device *)priv;
+
+ if (mdev->rx_reset_reg)
+ writel_relaxed(mdev->irq_mask, mdev->rx_reset_reg);
+
+ kthread_queue_work(&mdev->kworker, &mdev->kwork);
+ mdev->rx_irq_count++;
+
+ return IRQ_HANDLED;
+}
+
+static void memcpy32_toio(void *dest, void *src, size_t size)
+{
+ u32 *dest_local = (u32 *)dest;
+ u32 *src_local = (u32 *)src;
+
+ WARN_ON(size & MSG_RAM_ALIGN_BYTES);
+ size /= sizeof(u32);
+ while (size--)
+ iowrite32(*src_local++, dest_local++);
+}
+
+static void memcpy32_fromio(void *dest, void *src, size_t size)
+{
+ u32 *dest_local = (u32 *)dest;
+ u32 *src_local = (u32 *)src;
+
+ WARN_ON(size & MSG_RAM_ALIGN_BYTES);
+ size /= sizeof(u32);
+ while (size--)
+ *dest_local++ = ioread32(src_local++);
+}
+
+/**
+ * set_ucore_link_ack() - set the link ack in the ucore channel desc.
+ * @mdev: the mailbox for the field that is being set.
+ * @state: the value to set the ack field to.
+ */
+static void set_ucore_link_ack(struct qmp_device *mdev, u32 state)
+{
+ u32 offset;
+
+ offset = offsetof(struct mbox_desc, ucore);
+ offset += offsetof(struct channel_desc, link_state_ack);
+ iowrite32(state, mdev->desc + offset);
+}
+
+/**
+ * set_ucore_ch_ack() - set the channel ack in the ucore channel desc.
+ * @mdev: the mailbox for the field that is being set.
+ * @state: the value to set the ack field to.
+ */
+static void set_ucore_ch_ack(struct qmp_device *mdev, u32 state)
+{
+ u32 offset;
+
+ offset = offsetof(struct mbox_desc, ucore);
+ offset += offsetof(struct channel_desc, ch_state_ack);
+ iowrite32(state, mdev->desc + offset);
+}
+
+/**
+ * set_mcore_ch() - set the channel state in the mcore channel desc.
+ * @mdev: the mailbox for the field that is being set.
+ * @state: the value to set the channel field to.
+ */
+static void set_mcore_ch(struct qmp_device *mdev, u32 state)
+{
+ u32 offset;
+
+ offset = offsetof(struct mbox_desc, mcore);
+ offset += offsetof(struct channel_desc, ch_state);
+ iowrite32(state, mdev->desc + offset);
+}
+
+/**
+ * qmp_notify_timeout() - Notify client of tx timeout with -EIO
+ * @work: Structure for work that was scheduled.
+ */
+static void qmp_notify_timeout(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct qmp_device *mdev = container_of(dwork, struct qmp_device, dwork);
+ struct mbox_chan *chan = &mdev->mbox->chans[0];
+ int err = -EIO;
+
+ pr_err("%s: qmp tx timeout for %s\n", __func__, mdev->name);
+ mbox_chan_txdone(chan, err);
+}
+
+/**
+ * qmp_startup() - Start qmp mailbox channel for communication. Waits for
+ * remote subsystem to open channel if link is not
+ * initated or until timeout.
+ * @chan: mailbox channel that is being opened.
+ *
+ * Return: 0 on succes or standard Linux error code.
+ */
+static int qmp_startup(struct mbox_chan *chan)
+{
+ struct qmp_device *mdev = chan->con_priv;
+
+ if (!mdev)
+ return -EINVAL;
+
+ mutex_lock(&mdev->state_lock);
+ if (mdev->local_state == CHANNEL_CONNECTED) {
+ mutex_unlock(&mdev->state_lock);
+ return -EINVAL;
+ }
+ if (!completion_done(&mdev->link_complete)) {
+ mutex_unlock(&mdev->state_lock);
+ return -EAGAIN;
+ }
+
+ set_mcore_ch(mdev, QMP_MBOX_CH_CONNECTED);
+ mdev->local_state = LOCAL_CONNECTING;
+ mutex_unlock(&mdev->state_lock);
+
+ send_irq(mdev);
+ wait_for_completion_interruptible_timeout(&mdev->ch_complete,
+ msecs_to_jiffies(QMP_TOUT_MS));
+ return 0;
+}
+
+static inline void qmp_schedule_tx_timeout(struct qmp_device *mdev)
+{
+ schedule_delayed_work(&mdev->dwork, msecs_to_jiffies(QMP_TX_TOUT_MS));
+}
+
+/**
+ * qmp_send_data() - Copy the data to the channel's mailbox and notify
+ * remote subsystem of new data. This function will
+ * return an error if the previous message sent has
+ * not been read. Cannot Sleep.
+ * @chan: mailbox channel that data is to be sent over.
+ * @data: Data to be sent to remote processor, should be in the format of
+ * a qmp_pkt.
+ *
+ * Return: 0 on succes or standard Linux error code.
+ */
+static int qmp_send_data(struct mbox_chan *chan, void *data)
+{
+ struct qmp_device *mdev = chan->con_priv;
+ struct qmp_pkt *pkt = (struct qmp_pkt *)data;
+ void __iomem *addr;
+ unsigned long flags;
+
+ if (!mdev || !data || mdev->local_state != CHANNEL_CONNECTED)
+ return -EINVAL;
+
+ spin_lock_irqsave(&mdev->tx_lock, flags);
+ addr = mdev->msgram + mdev->mcore_mbox_offset;
+ if (ioread32(addr)) {
+ spin_unlock_irqrestore(&mdev->tx_lock, flags);
+ return -EBUSY;
+ }
+
+ if (pkt->size + sizeof(pkt->size) > mdev->mcore_mbox_size) {
+ spin_unlock_irqrestore(&mdev->tx_lock, flags);
+ return -EINVAL;
+ }
+ memcpy32_toio(addr + sizeof(pkt->size), pkt->data, pkt->size);
+ iowrite32(pkt->size, addr);
+ mdev->tx_sent = true;
+ send_irq(mdev);
+ qmp_schedule_tx_timeout(mdev);
+ spin_unlock_irqrestore(&mdev->tx_lock, flags);
+ return 0;
+}
+
+/**
+ * qmp_shutdown() - Disconnect this mailbox channel so the client does not
+ * receive anymore data and can reliquish control
+ * of the channel
+ * @chan: mailbox channel to be shutdown.
+ */
+static void qmp_shutdown(struct mbox_chan *chan)
+{
+ struct qmp_device *mdev = chan->con_priv;
+
+ mutex_lock(&mdev->state_lock);
+ if (mdev->local_state != LINK_DISCONNECTED) {
+ mdev->local_state = LOCAL_DISCONNECTING;
+ set_mcore_ch(mdev, QMP_MBOX_CH_DISCONNECTED);
+ send_irq(mdev);
+ }
+ mdev->ch_in_use = false;
+ mutex_unlock(&mdev->state_lock);
+}
+
+/**
+ * qmp_last_tx_done() - qmp does not support polling operations, print
+ * error of unexpected usage and return true to
+ * resume operation.
+ * @chan: Corresponding mailbox channel for requested last tx.
+ *
+ * Return: true
+ */
+static bool qmp_last_tx_done(struct mbox_chan *chan)
+{
+ pr_err("In %s, unexpected usage of last_tx_done\n", __func__);
+ return true;
+}
+
+/**
+ * qmp_recv_data() - received notification that data is available in the
+ * mailbox. Copy data from mailbox and pass to client.
+ * @mdev: mailbox device that received the notification.
+ * @mbox_of: offset of mailbox from msgram start.
+ */
+static void qmp_recv_data(struct qmp_device *mdev, u32 mbox_of)
+{
+ void __iomem *addr;
+ struct qmp_pkt *pkt;
+
+ addr = mdev->msgram + mbox_of;
+ pkt = &mdev->rx_pkt;
+ pkt->size = ioread32(addr);
+
+ if (pkt->size > mdev->mcore_mbox_size)
+ pr_err("%s: Invalid mailbox packet\n", __func__);
+ else {
+ memcpy32_fromio(pkt->data, addr + sizeof(pkt->size), pkt->size);
+ mbox_chan_received_data(&mdev->mbox->chans[0], &pkt);
+ }
+ iowrite32(0, addr);
+ send_irq(mdev);
+}
+
+/**
+ * init_mcore_state() - initialize the mcore state of a mailbox.
+ * @mdev: mailbox device to be initialized.
+ */
+static void init_mcore_state(struct qmp_device *mdev)
+{
+ struct channel_desc mcore;
+ u32 offset = offsetof(struct mbox_desc, mcore);
+
+ mcore.link_state = QMP_MBOX_LINK_UP;
+ mcore.link_state_ack = QMP_MBOX_LINK_DOWN;
+ mcore.ch_state = QMP_MBOX_CH_DISCONNECTED;
+ mcore.ch_state_ack = QMP_MBOX_CH_DISCONNECTED;
+ mcore.mailbox_size = mdev->mcore_mbox_size;
+ mcore.mailbox_offset = mdev->mcore_mbox_offset;
+ memcpy32_toio(mdev->desc + offset, &mcore, sizeof(mcore));
+}
+
+/**
+ * __qmp_rx_worker() - Handle incoming messages from remote processor.
+ * @mdev: mailbox device that received notification.
+ */
+static void __qmp_rx_worker(struct qmp_device *mdev)
+{
+ u32 msg_len;
+ struct mbox_desc desc;
+
+ memcpy_fromio(&desc, mdev->desc, sizeof(desc));
+ if (desc.magic != QMP_MAGIC)
+ return;
+
+ mutex_lock(&mdev->state_lock);
+ switch (mdev->local_state) {
+ case LINK_DISCONNECTED:
+ mdev->version.version = desc.version;
+ mdev->version.features = desc.features;
+ set_ucore_link_ack(mdev, desc.ucore.link_state);
+ if (desc.mcore.mailbox_size) {
+ mdev->mcore_mbox_size = desc.mcore.mailbox_size;
+ mdev->mcore_mbox_offset = desc.mcore.mailbox_offset;
+ }
+ init_mcore_state(mdev);
+ mdev->local_state = LINK_NEGOTIATION;
+ mdev->rx_pkt.data = devm_kzalloc(mdev->dev,
+ desc.ucore.mailbox_size,
+ GFP_KERNEL);
+ if (!mdev->rx_pkt.data) {
+ pr_err("In %s: failed to allocate rx pkt\n", __func__);
+ break;
+ }
+ send_irq(mdev);
+ break;
+ case LINK_NEGOTIATION:
+ if (desc.mcore.link_state_ack != QMP_MBOX_LINK_UP ||
+ desc.mcore.link_state != QMP_MBOX_LINK_UP) {
+ pr_err("In %s: rx interrupt without negotiation ack\n",
+ __func__);
+ break;
+ }
+ mdev->local_state = LINK_CONNECTED;
+ complete_all(&mdev->link_complete);
+ break;
+ case LINK_CONNECTED:
+ if (desc.ucore.ch_state == desc.ucore.ch_state_ack) {
+ pr_err("In %s: rx interrupt without channel open\n",
+ __func__);
+ break;
+ }
+ set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+ send_irq(mdev);
+ break;
+ case LOCAL_CONNECTING:
+ if (desc.mcore.ch_state_ack == QMP_MBOX_CH_CONNECTED &&
+ desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED)
+ mdev->local_state = LOCAL_CONNECTED;
+
+ if (desc.ucore.ch_state != desc.ucore.ch_state_ack) {
+ set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+ send_irq(mdev);
+ }
+ if (mdev->local_state == LOCAL_CONNECTED &&
+ desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED &&
+ desc.ucore.ch_state == QMP_MBOX_CH_CONNECTED) {
+ mdev->local_state = CHANNEL_CONNECTED;
+ complete_all(&mdev->ch_complete);
+ }
+ break;
+ case LOCAL_CONNECTED:
+ if (desc.ucore.ch_state == desc.ucore.ch_state_ack) {
+ pr_err("In %s: rx interrupt without remote channel open\n",
+ __func__);
+ break;
+ }
+ set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+ mdev->local_state = CHANNEL_CONNECTED;
+ send_irq(mdev);
+ complete_all(&mdev->ch_complete);
+ break;
+ case CHANNEL_CONNECTED:
+ if (desc.ucore.ch_state == QMP_MBOX_CH_DISCONNECTED) {
+ set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+ mdev->local_state = LOCAL_CONNECTED;
+ send_irq(mdev);
+ }
+
+ msg_len = ioread32(mdev->msgram + desc.ucore.mailbox_offset);
+ if (msg_len)
+ qmp_recv_data(mdev, desc.ucore.mailbox_offset);
+
+ if (mdev->tx_sent) {
+ msg_len = ioread32(mdev->msgram +
+ mdev->mcore_mbox_offset);
+ if (msg_len == 0) {
+ mdev->tx_sent = false;
+ cancel_delayed_work(&mdev->dwork);
+ mbox_chan_txdone(&mdev->mbox->chans[0], 0);
+ }
+ }
+ break;
+ case LOCAL_DISCONNECTING:
+ if (desc.mcore.ch_state_ack == QMP_MBOX_CH_DISCONNECTED &&
+ desc.mcore.ch_state == desc.mcore.ch_state_ack)
+ mdev->local_state = LINK_CONNECTED;
+ reinit_completion(&mdev->ch_complete);
+ break;
+ default:
+ pr_err("In %s: Local Channel State corrupted\n", __func__);
+ }
+ mutex_unlock(&mdev->state_lock);
+}
+
+static void rx_worker(struct kthread_work *work)
+{
+ struct qmp_device *mdev;
+
+ mdev = container_of(work, struct qmp_device, kwork);
+ __qmp_rx_worker(mdev);
+}
+
+/**
+ * qmp_mbox_of_xlate() - Returns a mailbox channel to be used for this mailbox
+ * device. Make sure the channel is not already in use.
+ * @mbox: Mailbox device controlls the requested channel.
+ * @spec: Device tree arguments to specify which channel is requested.
+ */
+static struct mbox_chan *qmp_mbox_of_xlate(struct mbox_controller *mbox,
+ const struct of_phandle_args *spec)
+{
+ struct qmp_device *mdev = dev_get_drvdata(mbox->dev);
+ unsigned int channel = spec->args[0];
+
+ if (!mdev || channel >= mbox->num_chans)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&mdev->state_lock);
+ if (mdev->ch_in_use) {
+ pr_err("%s, mbox channel already in use %s\n", __func__,
+ mdev->name);
+ mutex_unlock(&mdev->state_lock);
+ return ERR_PTR(-EBUSY);
+ }
+ mdev->ch_in_use = true;
+ mutex_unlock(&mdev->state_lock);
+ return &mbox->chans[0];
+}
+
+/**
+ * parse_devicetree() - Parse the device tree information for QMP, map io
+ * memory and register for needed interrupts
+ * @pdev: platform device for this driver.
+ * @mdev: mailbox device to hold the device tree configuration.
+ *
+ * Return: 0 on succes or standard Linux error code.
+ */
+static int qmp_parse_devicetree(struct platform_device *pdev,
+ struct qmp_device *mdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ char *key;
+ int rc;
+ const char *subsys_name;
+ u32 rx_irq_line, tx_irq_mask;
+ u32 desc_of = 0;
+ u32 mbox_of = 0;
+ u32 mbox_size = 0;
+ struct resource *msgram_r, *tx_irq_reg_r;
+
+ key = "label";
+ subsys_name = of_get_property(node, key, NULL);
+ if (!subsys_name) {
+ pr_err("%s: missing key %s\n", __func__, key);
+ return -ENODEV;
+ }
+
+ key = "msgram";
+ msgram_r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+ if (!msgram_r) {
+ pr_err("%s: missing key %s\n", __func__, key);
+ return -ENODEV;
+ }
+
+ key = "irq-reg-base";
+ tx_irq_reg_r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+ if (!tx_irq_reg_r) {
+ pr_err("%s: missing key %s\n", __func__, key);
+ return -ENODEV;
+ }
+
+ key = "qcom,irq-mask";
+ rc = of_property_read_u32(node, key, &tx_irq_mask);
+ if (rc) {
+ pr_err("%s: missing key %s\n", __func__, key);
+ return -ENODEV;
+ }
+
+ key = "interrupts";
+ rx_irq_line = irq_of_parse_and_map(node, 0);
+ if (!rx_irq_line) {
+ pr_err("%s: missing key %s\n", __func__, key);
+ return -ENODEV;
+ }
+
+ key = "mbox-desc-offset";
+ rc = of_property_read_u32(node, key, &desc_of);
+ if (rc) {
+ pr_err("%s: missing key %s\n", __func__, key);
+ return -ENODEV;
+ }
+
+ key = "mbox-offset";
+ rc = of_property_read_u32(node, key, &mbox_of);
+ if (!rc)
+ mdev->mcore_mbox_offset = mbox_of;
+
+ key = "mbox-size";
+ rc = of_property_read_u32(node, key, &mbox_size);
+ if (!rc)
+ mdev->mcore_mbox_size = mbox_size;
+
+ mdev->name = subsys_name;
+ mdev->msgram = devm_ioremap_nocache(&pdev->dev, msgram_r->start,
+ resource_size(msgram_r));
+ if (!mdev->msgram)
+ return -ENOMEM;
+
+ mdev->desc = mdev->msgram + desc_of;
+ if (!mdev->desc)
+ return -ENOMEM;
+
+ mdev->irq_mask = tx_irq_mask;
+ mdev->tx_irq_reg = devm_ioremap_nocache(&pdev->dev, tx_irq_reg_r->start,
+ resource_size(tx_irq_reg_r));
+ if (!mdev->tx_irq_reg)
+ return -ENOMEM;
+
+ mdev->rx_irq_line = rx_irq_line;
+ return 0;
+}
+
+/**
+ * cleanup_workqueue() - Flush all work and stop the thread for this mailbox.
+ * @mdev: mailbox device to cleanup.
+ */
+static void cleanup_workqueue(struct qmp_device *mdev)
+{
+ kthread_flush_worker(&mdev->kworker);
+ kthread_stop(mdev->task);
+ mdev->task = NULL;
+}
+
+static struct mbox_chan_ops qmp_mbox_ops = {
+ .startup = qmp_startup,
+ .shutdown = qmp_shutdown,
+ .send_data = qmp_send_data,
+ .last_tx_done = qmp_last_tx_done,
+};
+
+static const struct of_device_id qmp_mbox_match_table[] = {
+ { .compatible = "qcom,qmp-mbox" },
+ {},
+};
+
+static int qmp_mbox_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct mbox_controller *mbox;
+ struct qmp_device *mdev;
+ struct mbox_chan *chans;
+ int ret = 0;
+
+ mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, mdev);
+
+ ret = qmp_parse_devicetree(pdev, mdev);
+ if (ret)
+ return ret;
+
+ mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+
+ chans = devm_kzalloc(&pdev->dev, sizeof(*chans) * QMP_NUM_CHANS,
+ GFP_KERNEL);
+ if (!chans)
+ return -ENOMEM;
+
+ mbox->dev = &pdev->dev;
+ mbox->ops = &qmp_mbox_ops;
+ mbox->chans = chans;
+ mbox->chans[0].con_priv = mdev;
+ mbox->num_chans = QMP_NUM_CHANS;
+ mbox->txdone_irq = true;
+ mbox->txdone_poll = false;
+ mbox->of_xlate = qmp_mbox_of_xlate;
+
+ mdev->dev = &pdev->dev;
+ mdev->mbox = mbox;
+ spin_lock_init(&mdev->tx_lock);
+ mutex_init(&mdev->state_lock);
+ mdev->local_state = LINK_DISCONNECTED;
+ kthread_init_work(&mdev->kwork, rx_worker);
+ kthread_init_worker(&mdev->kworker);
+ mdev->task = kthread_run(kthread_worker_fn, &mdev->kworker, "qmp_%s",
+ mdev->name);
+ init_completion(&mdev->link_complete);
+ init_completion(&mdev->ch_complete);
+ mdev->tx_sent = false;
+ mdev->ch_in_use = false;
+ INIT_DELAYED_WORK(&mdev->dwork, qmp_notify_timeout);
+
+ ret = mbox_controller_register(mbox);
+ if (ret) {
+ cleanup_workqueue(mdev);
+ pr_err("%s: failed to register mbox controller %d\n", __func__,
+ ret);
+ return ret;
+ }
+
+ ret = devm_request_irq(&pdev->dev, mdev->rx_irq_line, qmp_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND | IRQF_SHARED,
+ node->name, mdev);
+ if (ret < 0) {
+ cleanup_workqueue(mdev);
+ mbox_controller_unregister(mdev->mbox);
+ pr_err("%s: request irq on %d failed: %d\n", __func__,
+ mdev->rx_irq_line, ret);
+ return ret;
+ }
+ ret = enable_irq_wake(mdev->rx_irq_line);
+ if (ret < 0)
+ pr_err("%s: enable_irq_wake on %d failed: %d\n", __func__,
+ mdev->rx_irq_line, ret);
+
+ qmp_irq_handler(0, mdev);
+ return 0;
+}
+
+static int qmp_mbox_remove(struct platform_device *pdev)
+{
+ struct qmp_device *mdev = platform_get_drvdata(pdev);
+
+ cleanup_workqueue(mdev);
+ mbox_controller_unregister(mdev->mbox);
+ return 0;
+}
+
+static struct platform_driver qmp_mbox_driver = {
+ .probe = qmp_mbox_probe,
+ .remove = qmp_mbox_remove,
+ .driver = {
+ .name = "qmp_mbox",
+ .owner = THIS_MODULE,
+ .of_match_table = qmp_mbox_match_table,
+ },
+};
+
+static int __init qmp_init(void)
+{
+ int rc = 0;
+
+ rc = platform_driver_register(&qmp_mbox_driver);
+ if (rc)
+ pr_err("%s: qmp_mbox_driver reg failed %d\n", __func__, rc);
+ return rc;
+}
+arch_initcall(qmp_init);
+
+MODULE_DESCRIPTION("MSM QTI Mailbox Protocol");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index 5b114cb..31119ea 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -121,6 +121,7 @@
/* One per MBOX controller */
struct tcs_drv {
+ const char *name;
void *base; /* start address of the RSC's registers */
void *reg_base; /* start address for DRV specific register */
int drv_id;
@@ -385,7 +386,8 @@
mbox_chan_received_data(resp->chan, resp->msg);
}
- trace_rpmh_notify_irq(m, resp->msg->payload[0].addr, resp->err);
+ trace_rpmh_notify_irq(drv->name, m, resp->msg->payload[0].addr,
+ resp->err);
/* Notify the client that this request is completed. */
send_tcs_response(resp);
@@ -401,7 +403,9 @@
static inline void mbox_notify_tx_done(struct mbox_chan *chan,
struct tcs_mbox_msg *msg, int m, int err)
{
- trace_rpmh_notify(m, msg->payload[0].addr, err);
+ struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
+
+ trace_rpmh_notify(drv->name, m, msg->payload[0].addr, err);
mbox_chan_txdone(chan, err);
}
@@ -467,7 +471,7 @@
mbox_notify_tx_done(chan, msg, -1, err);
}
-static void __tcs_buffer_write(void __iomem *base, int d, int m, int n,
+static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n,
struct tcs_mbox_msg *msg, bool trigger)
{
u32 cmd_msgid = 0;
@@ -476,6 +480,7 @@
u32 enable = TCS_AMC_MODE_ENABLE;
struct tcs_cmd *cmd;
int i;
+ void __iomem *base = drv->reg_base;
/* We have homologous command set i.e pure read or write, not a mix */
cmd_msgid = CMD_MSGID_LEN;
@@ -492,8 +497,8 @@
write_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n + i, cmd_msgid);
write_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n + i, cmd->addr);
write_tcs_reg(base, TCS_DRV_CMD_DATA, m, n + i, cmd->data);
- trace_rpmh_send_msg(base, m, n + i,
- cmd_msgid, cmd->addr, cmd->data, cmd->complete);
+ trace_rpmh_send_msg(drv->name, m, n + i, cmd_msgid, cmd->addr,
+ cmd->data, cmd->complete, trigger);
}
/* Write the send-after-prev completion bits for the batch */
@@ -716,7 +721,7 @@
}
/* Write to the TCS or AMC */
- __tcs_buffer_write(drv->reg_base, d, m, n, msg, trigger);
+ __tcs_buffer_write(drv, d, m, n, msg, trigger);
/* Schedule a timeout response, incase there is no actual response */
if (trigger)
@@ -826,15 +831,16 @@
return 0;
}
-static void __tcs_write_hidden(void *base, int d, struct tcs_mbox_msg *msg)
+static void __tcs_write_hidden(struct tcs_drv *drv, int d,
+ struct tcs_mbox_msg *msg)
{
int i;
- void __iomem *addr = base + TCS_HIDDEN_CMD0_DRV_DATA;
+ void __iomem *addr = drv->base + TCS_HIDDEN_CMD0_DRV_DATA;
for (i = 0; i < msg->num_payload; i++) {
/* Only data is write capable */
writel_relaxed(cpu_to_le32(msg->payload[i].data), addr);
- trace_rpmh_control_msg(addr, msg->payload[i].data);
+ trace_rpmh_control_msg(drv->name, msg->payload[i].data);
addr += TCS_HIDDEN_CMD_SHIFT;
}
}
@@ -855,7 +861,7 @@
}
spin_lock(&tcs->tcs_lock);
- __tcs_write_hidden(tcs->drv->base, drv->drv_id, msg);
+ __tcs_write_hidden(tcs->drv, drv->drv_id, msg);
spin_unlock(&tcs->tcs_lock);
return 0;
@@ -1073,6 +1079,10 @@
drv->num_tcs = st;
drv->pdev = pdev;
+ drv->name = of_get_property(pdev->dev.of_node, "label", NULL);
+ if (!drv->name)
+ drv->name = dev_name(&pdev->dev);
+
ret = tcs_response_pool_init(drv);
if (ret)
return ret;
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index faba819..db01353 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -2,4 +2,4 @@
obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/
-
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/
diff --git a/drivers/media/platform/msm/camera/cam_core/Makefile b/drivers/media/platform/msm/camera/cam_core/Makefile
new file mode 100644
index 0000000..417de13
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_node.o cam_subdev.o
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c
new file mode 100644
index 0000000..56b34f5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 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/uaccess.h>
+#include "cam_context.h"
+
+static int cam_context_handle_hw_event(void *context, uint32_t evt_id,
+ void *evt_data)
+{
+ int rc = 0;
+ struct cam_context *ctx = (struct cam_context *)context;
+
+ if (!ctx || !ctx->state_machine) {
+ pr_err("%s: Context is not ready.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ctx->state_machine[ctx->state].irq_ops)
+ rc = ctx->state_machine[ctx->state].irq_ops(ctx, evt_id,
+ evt_data);
+ else
+ pr_debug("%s: No function to handle event %d in dev %d, state %d\n",
+ __func__, evt_id, ctx->dev_hdl, ctx->state);
+ return rc;
+}
+
+int cam_context_handle_get_dev_info(struct cam_context *ctx,
+ struct cam_req_mgr_device_info *info)
+{
+ int rc;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: Context is not ready.\n'", __func__);
+ return -EINVAL;
+ }
+
+ if (!info) {
+ pr_err("%s: Invalid get device info payload.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].crm_ops.get_dev_info) {
+ rc = ctx->state_machine[ctx->state].crm_ops.get_dev_info(
+ ctx, info);
+ } else {
+ pr_err("%s: No get device info in dev %d, state %d\n",
+ __func__, ctx->dev_hdl, ctx->state);
+ rc = -EPROTO;
+ }
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+int cam_context_handle_link(struct cam_context *ctx,
+ struct cam_req_mgr_core_dev_link_setup *link)
+{
+ int rc;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: Context is not ready.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!link) {
+ pr_err("%s: Invalid link payload.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].crm_ops.link) {
+ rc = ctx->state_machine[ctx->state].crm_ops.link(ctx, link);
+ } else {
+ pr_err("%s: No crm link in dev %d, state %d\n", __func__,
+ ctx->dev_hdl, ctx->state);
+ rc = -EPROTO;
+ }
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+int cam_context_handle_unlink(struct cam_context *ctx,
+ struct cam_req_mgr_core_dev_link_setup *unlink)
+{
+ int rc;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: Context is not ready!\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!unlink) {
+ pr_err("%s: Invalid unlink payload.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].crm_ops.unlink) {
+ rc = ctx->state_machine[ctx->state].crm_ops.unlink(
+ ctx, unlink);
+ } else {
+ pr_err("%s: No crm unlink in dev %d, state %d\n",
+ __func__, ctx->dev_hdl, ctx->state);
+ rc = -EPROTO;
+ }
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+int cam_context_handle_apply_req(struct cam_context *ctx,
+ struct cam_req_mgr_apply_request *apply)
+{
+ int rc;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: Context is not ready.\n'", __func__);
+ return -EINVAL;
+ }
+
+ if (!apply) {
+ pr_err("%s: Invalid apply request payload.\n'", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].crm_ops.apply_req) {
+ rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx,
+ apply);
+ } else {
+ pr_err("%s: No crm apply req in dev %d, state %d\n",
+ __func__, ctx->dev_hdl, ctx->state);
+ rc = -EPROTO;
+ }
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+
+int cam_context_handle_acquire_dev(struct cam_context *ctx,
+ struct cam_acquire_dev_cmd *cmd)
+{
+ int rc;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: Context is not ready.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!cmd) {
+ pr_err("%s: Invalid acquire device command payload.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].ioctl_ops.acquire_dev) {
+ rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_dev(
+ ctx, cmd);
+ } else {
+ pr_err("%s: No acquire device in dev %d, state %d\n",
+ __func__, cmd->dev_handle, ctx->state);
+ rc = -EPROTO;
+ }
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+int cam_context_handle_release_dev(struct cam_context *ctx,
+ struct cam_release_dev_cmd *cmd)
+{
+ int rc;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: Context is not ready.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!cmd) {
+ pr_err("%s: Invalid release device command payload.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].ioctl_ops.release_dev) {
+ rc = ctx->state_machine[ctx->state].ioctl_ops.release_dev(
+ ctx, cmd);
+ } else {
+ pr_err("%s: No release device in dev %d, state %d\n",
+ __func__, ctx->dev_hdl, ctx->state);
+ rc = -EPROTO;
+ }
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+int cam_context_handle_config_dev(struct cam_context *ctx,
+ struct cam_config_dev_cmd *cmd)
+{
+ int rc;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: context is not ready\n'", __func__);
+ return -EINVAL;
+ }
+
+ if (!cmd) {
+ pr_err("%s: Invalid config device command payload.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].ioctl_ops.config_dev) {
+ rc = ctx->state_machine[ctx->state].ioctl_ops.config_dev(
+ ctx, cmd);
+ } else {
+ pr_err("%s: No config device in dev %d, state %d\n",
+ __func__, ctx->dev_hdl, ctx->state);
+ rc = -EPROTO;
+ }
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+int cam_context_handle_start_dev(struct cam_context *ctx,
+ struct cam_start_stop_dev_cmd *cmd)
+{
+ int rc = 0;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: Context is not ready.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!cmd) {
+ pr_err("%s: Invalid start device command payload.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].ioctl_ops.start_dev)
+ rc = ctx->state_machine[ctx->state].ioctl_ops.start_dev(
+ ctx, cmd);
+ else
+ /* start device can be optional for some driver */
+ pr_debug("%s: No start device in dev %d, state %d\n",
+ __func__, ctx->dev_hdl, ctx->state);
+
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+int cam_context_handle_stop_dev(struct cam_context *ctx,
+ struct cam_start_stop_dev_cmd *cmd)
+{
+ int rc = 0;
+
+ if (!ctx->state_machine) {
+ pr_err("%s: Context is not ready.\n'", __func__);
+ return -EINVAL;
+ }
+
+ if (!cmd) {
+ pr_err("%s: Invalid stop device command payload.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev)
+ rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev(
+ ctx, cmd);
+ else
+ /* stop device can be optional for some driver */
+ pr_warn("%s: No stop device in dev %d, state %d\n",
+ __func__, ctx->dev_hdl, ctx->state);
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
+int cam_context_init(struct cam_context *ctx,
+ struct cam_req_mgr_kmd_ops *crm_node_intf,
+ struct cam_hw_mgr_intf *hw_mgr_intf,
+ struct cam_ctx_request *req_list,
+ uint32_t req_size)
+{
+ int i;
+
+ /* crm_node_intf is optinal */
+ if (!ctx || !hw_mgr_intf || !req_list) {
+ pr_err("%s: Invalid input parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ INIT_LIST_HEAD(&ctx->list);
+ mutex_init(&ctx->ctx_mutex);
+ spin_lock_init(&ctx->lock);
+
+ ctx->ctx_crm_intf = NULL;
+ ctx->crm_ctx_intf = crm_node_intf;
+ ctx->hw_mgr_intf = hw_mgr_intf;
+ ctx->irq_cb_intf = cam_context_handle_hw_event;
+
+ INIT_LIST_HEAD(&ctx->active_req_list);
+ INIT_LIST_HEAD(&ctx->wait_req_list);
+ INIT_LIST_HEAD(&ctx->pending_req_list);
+ INIT_LIST_HEAD(&ctx->free_req_list);
+ ctx->req_list = req_list;
+ ctx->req_size = req_size;
+ for (i = 0; i < req_size; i++) {
+ INIT_LIST_HEAD(&ctx->req_list[i].list);
+ list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list);
+ }
+ ctx->state = CAM_CTX_AVAILABLE;
+ ctx->state_machine = NULL;
+ ctx->ctx_priv = NULL;
+
+ return 0;
+}
+
+int cam_context_deinit(struct cam_context *ctx)
+{
+ if (!ctx)
+ return -EINVAL;
+
+ /**
+ * This is called from platform device remove.
+ * Everyting should be released at this moment.
+ * so we just free the memory for the context
+ */
+ if (ctx->state != CAM_CTX_AVAILABLE)
+ pr_err("%s: Device did not shutdown cleanly.\n", __func__);
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h
new file mode 100644
index 0000000..c7329cf
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -0,0 +1,302 @@
+/* Copyright (c) 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 _CAM_CONTEXT_H_
+#define _CAM_CONTEXT_H_
+
+#include <linux/spinlock.h>
+#include "cam_req_mgr_interface.h"
+#include "cam_hw_mgr_intf.h"
+
+/* Forward declarations */
+struct cam_context;
+
+/* max request number */
+#define CAM_CTX_REQ_MAX 20
+
+/**
+ * enum cam_ctx_state - context top level states
+ *
+ */
+enum cam_context_state {
+ CAM_CTX_UNINIT = 0,
+ CAM_CTX_AVAILABLE = 1,
+ CAM_CTX_ACQUIRED = 2,
+ CAM_CTX_READY = 3,
+ CAM_CTX_ACTIVATED = 4,
+ CAM_CTX_STATE_MAX = 5,
+};
+
+/**
+ * struct cam_ctx_request - Common request structure for the context
+ *
+ * @list: Link list entry
+ * @status: Request status
+ * @request_id: Request id
+ * @req_priv: Derived request object
+ *
+ */
+struct cam_ctx_request {
+ struct list_head list;
+ uint32_t status;
+ uint64_t request_id;
+ void *req_priv;
+};
+
+/**
+ * struct cam_ctx_ioctl_ops - Function table for handling IOCTL calls
+ *
+ * @acquire_dev: Function pointer for acquire device
+ * @release_dev: Function pointer for release device
+ * @config_dev: Function pointer for config device
+ * @start_dev: Function pointer for start device
+ * @stop_dev: Function pointer for stop device
+ *
+ */
+struct cam_ctx_ioctl_ops {
+ int (*acquire_dev)(struct cam_context *ctx,
+ struct cam_acquire_dev_cmd *cmd);
+ int (*release_dev)(struct cam_context *ctx,
+ struct cam_release_dev_cmd *cmd);
+ int (*config_dev)(struct cam_context *ctx,
+ struct cam_config_dev_cmd *cmd);
+ int (*start_dev)(struct cam_context *ctx,
+ struct cam_start_stop_dev_cmd *cmd);
+ int (*stop_dev)(struct cam_context *ctx,
+ struct cam_start_stop_dev_cmd *cmd);
+};
+
+/**
+ * struct cam_ctx_crm_ops - Function table for handling CRM to context calls
+ *
+ * @get_dev_info: Get device informaiton
+ * @link: Link the context
+ * @unlink: Unlink the context
+ * @apply_req: Apply setting for the context
+ *
+ */
+struct cam_ctx_crm_ops {
+ int (*get_dev_info)(struct cam_context *ctx,
+ struct cam_req_mgr_device_info *);
+ int (*link)(struct cam_context *ctx,
+ struct cam_req_mgr_core_dev_link_setup *link);
+ int (*unlink)(struct cam_context *ctx,
+ struct cam_req_mgr_core_dev_link_setup *unlink);
+ int (*apply_req)(struct cam_context *ctx,
+ struct cam_req_mgr_apply_request *apply);
+};
+
+
+/**
+ * struct cam_ctx_ops - Collection of the interface funciton tables
+ *
+ * @ioctl_ops: Ioctl funciton table
+ * @crm_ops: CRM to context interface function table
+ * @irq_ops: Hardware event handle function
+ *
+ */
+struct cam_ctx_ops {
+ struct cam_ctx_ioctl_ops ioctl_ops;
+ struct cam_ctx_crm_ops crm_ops;
+ cam_hw_event_cb_func irq_ops;
+};
+
+/**
+ * struct cam_context - camera context object for the subdevice node
+ *
+ * @list: Link list entry
+ * @sessoin_hdl: Session handle
+ * @dev_hdl: Device handle
+ * @link_hdl: Link handle
+ * @ctx_mutex: Mutex for ioctl calls
+ * @lock: Spin lock
+ * @active_req_list: Requests pending for done event
+ * @pending_req_list: Requests pending for reg upd event
+ * @wait_req_list: Requests waiting for apply
+ * @free_req_list: Requests that are free
+ * @req_list: Reference to the request storage
+ * @req_size: Size of the request storage
+ * @hw_mgr_intf: Context to HW interface
+ * @ctx_crm_intf: Context to CRM interface
+ * @crm_ctx_intf: CRM to context interface
+ * @irq_cb_intf: HW to context callback interface
+ * @state: Current state for top level state machine
+ * @state_machine: Top level state machine
+ * @ctx_priv: Private context pointer
+ *
+ */
+struct cam_context {
+ struct list_head list;
+ int32_t session_hdl;
+ int32_t dev_hdl;
+ int32_t link_hdl;
+
+ struct mutex ctx_mutex;
+ spinlock_t lock;
+
+ struct list_head active_req_list;
+ struct list_head pending_req_list;
+ struct list_head wait_req_list;
+ struct list_head free_req_list;
+ struct cam_ctx_request *req_list;
+ uint32_t req_size;
+
+ struct cam_hw_mgr_intf *hw_mgr_intf;
+ struct cam_req_mgr_crm_cb *ctx_crm_intf;
+ struct cam_req_mgr_kmd_ops *crm_ctx_intf;
+ cam_hw_event_cb_func irq_cb_intf;
+
+ enum cam_context_state state;
+ struct cam_ctx_ops *state_machine;
+
+ void *ctx_priv;
+};
+
+/**
+ * cam_context_handle_get_dev_info()
+ *
+ * @brief: Handle get device information command
+ *
+ * @ctx: Object pointer for cam_context
+ * @info: Device information returned
+ *
+ */
+int cam_context_handle_get_dev_info(struct cam_context *ctx,
+ struct cam_req_mgr_device_info *info);
+
+/**
+ * cam_context_handle_link()
+ *
+ * @brief: Handle link command
+ *
+ * @ctx: Object pointer for cam_context
+ * @link: Link command payload
+ *
+ */
+int cam_context_handle_link(struct cam_context *ctx,
+ struct cam_req_mgr_core_dev_link_setup *link);
+
+/**
+ * cam_context_handle_unlink()
+ *
+ * @brief: Handle unlink command
+ *
+ * @ctx: Object pointer for cam_context
+ * @unlink: Unlink command payload
+ *
+ */
+int cam_context_handle_unlink(struct cam_context *ctx,
+ struct cam_req_mgr_core_dev_link_setup *unlink);
+
+/**
+ * cam_context_handle_apply_req()
+ *
+ * @brief: Handle apply request command
+ *
+ * @ctx: Object pointer for cam_context
+ * @apply: Apply request command payload
+ *
+ */
+int cam_context_handle_apply_req(struct cam_context *ctx,
+ struct cam_req_mgr_apply_request *apply);
+
+
+/**
+ * cam_context_handle_acquire_dev()
+ *
+ * @brief: Handle acquire device command
+ *
+ * @ctx: Object pointer for cam_context
+ * @cmd: Acquire device command payload
+ *
+ */
+int cam_context_handle_acquire_dev(struct cam_context *ctx,
+ struct cam_acquire_dev_cmd *cmd);
+
+/**
+ * cam_context_handle_release_dev()
+ *
+ * @brief: Handle release device command
+ *
+ * @ctx: Object pointer for cam_context
+ * @cmd: Release device command payload
+ *
+ */
+int cam_context_handle_release_dev(struct cam_context *ctx,
+ struct cam_release_dev_cmd *cmd);
+
+/**
+ * cam_context_handle_config_dev()
+ *
+ * @brief: Handle config device command
+ *
+ * @ctx: Object pointer for cam_context
+ * @cmd: Config device command payload
+ *
+ */
+int cam_context_handle_config_dev(struct cam_context *ctx,
+ struct cam_config_dev_cmd *cmd);
+
+/**
+ * cam_context_handle_start_dev()
+ *
+ * @brief: Handle start device command
+ *
+ * @ctx: Object pointer for cam_context
+ * @cmd: Start device command payload
+ *
+ */
+int cam_context_handle_start_dev(struct cam_context *ctx,
+ struct cam_start_stop_dev_cmd *cmd);
+
+/**
+ * cam_context_handle_stop_dev()
+ *
+ * @brief: Handle stop device command
+ *
+ * @ctx: Object pointer for cam_context
+ * @cmd: Stop device command payload
+ *
+ */
+int cam_context_handle_stop_dev(struct cam_context *ctx,
+ struct cam_start_stop_dev_cmd *cmd);
+
+/**
+ * cam_context_deinit()
+ *
+ * @brief: Camera context deinitialize function
+ *
+ * @ctx: Object pointer for cam_context
+ *
+ */
+int cam_context_deinit(struct cam_context *ctx);
+
+/**
+ * cam_context_init()
+ *
+ * @brief: Camera context initialize function
+ *
+ * @ctx: Object pointer for cam_context
+ * @crm_node_intf: Function table for crm to context interface
+ * @hw_mgr_intf: Function table for context to hw interface
+ * @req_list: Requests storage
+ * @req_size: Size of the request storage
+ *
+ */
+int cam_context_init(struct cam_context *ctx,
+ struct cam_req_mgr_kmd_ops *crm_node_intf,
+ struct cam_hw_mgr_intf *hw_mgr_intf,
+ struct cam_ctx_request *req_list,
+ uint32_t req_size);
+
+
+#endif /* _CAM_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw.h b/drivers/media/platform/msm/camera/cam_core/cam_hw.h
new file mode 100644
index 0000000..d01a84a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 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 _CAM_HW_H_
+#define _CAM_HW_H_
+
+#include "cam_soc_util.h"
+
+/*
+ * This file declares Enums, Structures and APIs to be used as template
+ * when writing any HW driver in the camera subsystem.
+ */
+
+/* Hardware state enum */
+enum cam_hw_state {
+ CAM_HW_STATE_POWER_DOWN,
+ CAM_HW_STATE_POWER_UP,
+};
+
+/**
+ * struct cam_hw_info - Common hardware information
+ *
+ * @hw_mutex: Hardware mutex
+ * @hw_lock: Hardware spinlock
+ * @hw_complete: Hardware Completion
+ * @open_count: Count to track the HW enable from the client
+ * @hw_state: Hardware state
+ * @soc_info: Platform SOC properties for hardware
+ * @node_info: Private HW data related to nodes
+ * @core_info: Private HW data related to core logic
+ *
+ */
+struct cam_hw_info {
+ struct mutex hw_mutex;
+ spinlock_t hw_lock;
+ struct completion hw_complete;
+ uint32_t open_count;
+ enum cam_hw_state hw_state;
+ struct cam_hw_soc_info soc_info;
+ void *node_info;
+ void *core_info;
+};
+
+#endif /* _CAM_HW_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_intf.h
new file mode 100644
index 0000000..3a997ae
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_intf.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 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 _CAM_HW_INTF_H_
+#define _CAM_HW_INTF_H_
+
+#include <linux/types.h>
+
+/*
+ * This file declares Constants, Enums, Structures and APIs to be used as
+ * Interface between HW driver and HW Manager.
+ */
+
+/**
+ * struct cam_hw_ops - Hardware layer interface functions
+ *
+ * @get_hw_caps: Function pointer for get hw caps
+ * @init: Function poniter for initialize hardware
+ * @deinit: Function pointer for deinitialize hardware
+ * @reset: Function pointer for reset hardware
+ * @reserve: Function pointer for reserve hardware
+ * @release: Function pointer for release hardware
+ * @start: Function pointer for start hardware
+ * @stop: Function pointer for stop hardware
+ * @read: Function pointer for read hardware registers
+ * @write: Function pointer for Write hardware registers
+ * @process_cmd: Function pointer for additional hardware controls
+ *
+ */
+struct cam_hw_ops {
+ int (*get_hw_caps)(void *hw_priv,
+ void *get_hw_cap_args, uint32_t arg_size);
+ int (*init)(void *hw_priv,
+ void *init_hw_args, uint32_t arg_size);
+ int (*deinit)(void *hw_priv,
+ void *init_hw_args, uint32_t arg_size);
+ int (*reset)(void *hw_priv,
+ void *reset_core_args, uint32_t arg_size);
+ int (*reserve)(void *hw_priv,
+ void *reserve_args, uint32_t arg_size);
+ int (*release)(void *hw_priv,
+ void *release_args, uint32_t arg_size);
+ int (*start)(void *hw_priv,
+ void *start_args, uint32_t arg_size);
+ int (*stop)(void *hw_priv,
+ void *stop_args, uint32_t arg_size);
+ int (*read)(void *hw_priv,
+ void *read_args, uint32_t arg_size);
+ int (*write)(void *hw_priv,
+ void *write_args, uint32_t arg_size);
+ int (*process_cmd)(void *hw_priv,
+ uint32_t cmd_type, void *cmd_args, uint32_t arg_size);
+};
+
+/**
+ * struct cam_hw_intf - Common hardware node
+ *
+ * @hw_type: Hardware type
+ * @hw_idx: Hardware ID
+ * @hw_ops: Hardware interface function table
+ * @hw_priv: Private hardware node pointer
+ *
+ */
+struct cam_hw_intf {
+ uint32_t hw_type;
+ uint32_t hw_idx;
+ struct cam_hw_ops hw_ops;
+ void *hw_priv;
+};
+
+#endif /* _CAM_HW_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
new file mode 100644
index 0000000..db605e7
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
@@ -0,0 +1,209 @@
+/* Copyright (c) 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 _CAM_HW_MGR_INTF_H_
+#define _CAM_HW_MGR_INTF_H_
+
+/*
+ * This file declares Constants, Enums, Structures and APIs to be used as
+ * Interface between HW Manager and Context.
+ */
+
+
+/* maximum context numbers */
+#define CAM_CTX_MAX 8
+
+/* maximum buf done irqs */
+#define CAM_NUM_OUT_PER_COMP_IRQ_MAX 12
+
+/* hardware event callback function type */
+typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id,
+ void *evt_data);
+
+/**
+ * struct cam_hw_update_entry - Entry for hardware config
+ *
+ * @handle: Memory handle for the configuration
+ * @offset: Memory offset
+ * @len: Size of the configuration
+ * @flags: Flags for the config entry(eg. DMI)
+ *
+ */
+struct cam_hw_update_entry {
+ int handle;
+ uint32_t offset;
+ uint32_t len;
+ uint32_t flags;
+};
+
+/**
+ * struct cam_hw_fence_map_entry - Entry for the resource to sync id map
+ *
+ * @resrouce_handle: Resource port id for the buffer
+ * @sync_id: Synce id
+ *
+ */
+struct cam_hw_fence_map_entry {
+ uint32_t resource_handle;
+ int32_t sync_id;
+};
+
+/**
+ * struct cam_hw_done_event_data - Payload for hw done event
+ *
+ * @num_handles: number of handles in the event
+ * @resrouce_handle: list of the resource handle
+ * @timestamp: time stamp
+ *
+ */
+struct cam_hw_done_event_data {
+ uint32_t num_handles;
+ uint32_t resource_handle[CAM_NUM_OUT_PER_COMP_IRQ_MAX];
+ struct timeval timestamp;
+};
+
+/**
+ * struct cam_hw_acquire_args - Payload for acquire command
+ *
+ * @context_data: Context data pointer for the callback function
+ * @event_cb: Callback function array
+ * @num_acq: Total number of acquire in the payload
+ * @acquire_info: Acquired resource array pointer
+ * @ctxt_to_hw_map: HW context (returned)
+ *
+ */
+struct cam_hw_acquire_args {
+ void *context_data;
+ cam_hw_event_cb_func event_cb;
+ uint32_t num_acq;
+ uint64_t acquire_info;
+ void *ctxt_to_hw_map;
+};
+
+/**
+ * struct cam_hw_release_args - Payload for release command
+ *
+ * @ctxt_to_hw_map: HW context from the acquire
+ *
+ */
+struct cam_hw_release_args {
+ void *ctxt_to_hw_map;
+};
+
+/**
+ * struct cam_hw_start_args - Payload for start command
+ *
+ * @ctxt_to_hw_map: HW context from the acquire
+ * @num_hw_update_entries: Number of Hardware configuration
+ * @hw_update_entries: Hardware configuration list
+ *
+ */
+struct cam_hw_start_args {
+ void *ctxt_to_hw_map;
+ uint32_t num_hw_update_entries;
+ struct cam_hw_update_entry *hw_update_entries;
+};
+
+/**
+ * struct cam_hw_stop_args - Payload for stop command
+ *
+ * @ctxt_to_hw_map: HW context from the acquire
+ *
+ */
+struct cam_hw_stop_args {
+ void *ctxt_to_hw_map;
+};
+
+/**
+ * struct cam_hw_prepare_update_args - Payload for prepare command
+ *
+ * @packet: CSL packet from user mode driver
+ * @ctxt_to_hw_map: HW context from the acquire
+ * @max_hw_update_entries: Maximum hardware update entries supported
+ * @hw_update_entries: Actual hardware update configuration (returned)
+ * @num_hw_update_entries: Number of actual hardware update entries (returned)
+ * @max_out_map_entries: Maximum output fence mapping supported
+ * @out_map_entries: Actual output fence mapping list (returned)
+ * @num_out_map_entries: Number of actual output fence mapping (returned)
+ * @max_in_map_entries: Maximum input fence mapping supported
+ * @in_map_entries: Actual input fence mapping list (returned)
+ * @num_in_map_entries: Number of acutal input fence mapping (returned)
+ *
+ */
+struct cam_hw_prepare_update_args {
+ struct cam_packet *packet;
+ void *ctxt_to_hw_map;
+ uint32_t max_hw_update_entries;
+ struct cam_hw_update_entry *hw_update_entries;
+ uint32_t num_hw_update_entries;
+ uint32_t max_out_map_entries;
+ struct cam_hw_fence_map_entry *out_map_entries;
+ uint32_t num_out_map_entries;
+ uint32_t max_in_map_entries;
+ struct cam_hw_fence_map_entry *in_map_entries;
+ uint32_t num_in_map_entries;
+};
+
+/**
+ * struct cam_hw_config_args - Payload for config command
+ *
+ * @ctxt_to_hw_map: HW context from the acquire
+ * @num_hw_update_entries: Number of hardware update entries
+ * @hw_update_entries: Hardware update list
+ *
+ */
+struct cam_hw_config_args {
+ void *ctxt_to_hw_map;
+ uint32_t num_hw_update_entries;
+ struct cam_hw_update_entry *hw_update_entries;
+};
+
+/**
+ * cam_hw_mgr_intf - HW manager interface
+ *
+ * @hw_mgr_priv: HW manager object
+ * @hw_get_caps: Function pointer for get hw caps
+ * args = cam_query_cap_cmd
+ * @hw_acquire: Function poniter for acquire hw resources
+ * args = cam_hw_acquire_args
+ * @hw_release: Function pointer for release hw device resource
+ * args = cam_hw_release_args
+ * @hw_start: Function pointer for start hw devices
+ * args = cam_hw_start_args
+ * @hw_stop: Function pointer for stop hw devices
+ * args = cam_hw_stop_args
+ * @hw_prepare_update: Function pointer for prepare hw update for hw devices
+ * args = cam_hw_prepare_update_args
+ * @hw_config: Function pointer for configure hw devices
+ * args = cam_hw_config_args
+ * @hw_read: Function pointer for read hardware registers
+ * @hw_write: Function pointer for Write hardware registers
+ * @hw_cmd: Function pointer for any customized commands for the
+ * hardware manager
+ *
+ */
+struct cam_hw_mgr_intf {
+ void *hw_mgr_priv;
+
+ int (*hw_get_caps)(void *hw_priv, void *hw_caps_args);
+ int (*hw_acquire)(void *hw_priv, void *hw_acquire_args);
+ int (*hw_release)(void *hw_priv, void *hw_release_args);
+ int (*hw_start)(void *hw_priv, void *hw_start_args);
+ int (*hw_stop)(void *hw_priv, void *hw_stop_args);
+ int (*hw_prepare_update)(void *hw_priv, void *hw_prepare_update_args);
+ int (*hw_config)(void *hw_priv, void *hw_config_args);
+ int (*hw_read)(void *hw_priv, void *read_args);
+ int (*hw_write)(void *hw_priv, void *write_args);
+ int (*hw_cmd)(void *hw_priv, void *write_args);
+};
+
+#endif /* _CAM_HW_MGR_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
new file mode 100644
index 0000000..ef60822
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -0,0 +1,413 @@
+/* Copyright (c) 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/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+
+#include "cam_node.h"
+
+static int __cam_node_handle_query_cap(struct cam_node *node,
+ struct cam_query_cap_cmd *query)
+{
+ int rc = -EFAULT;
+
+ if (!query)
+ return -EINVAL;
+
+ if (node->hw_mgr_intf.hw_get_caps) {
+ rc = node->hw_mgr_intf.hw_get_caps(
+ node->hw_mgr_intf.hw_mgr_priv, query);
+ }
+ return rc;
+}
+
+static int __cam_node_handle_acquire_dev(struct cam_node *node,
+ struct cam_acquire_dev_cmd *acquire)
+{
+ int rc = 0;
+ struct cam_context *ctx = NULL;
+
+ if (!acquire)
+ return -EINVAL;
+
+ mutex_lock(&node->list_mutex);
+ if (!list_empty(&node->free_ctx_list)) {
+ ctx = list_first_entry(&node->free_ctx_list,
+ struct cam_context, list);
+ list_del_init(&ctx->list);
+ }
+ mutex_unlock(&node->list_mutex);
+
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = cam_context_handle_acquire_dev(ctx, acquire);
+ if (rc) {
+ pr_err("%s: Acquire device failed\n", __func__);
+ goto free_ctx;
+ }
+
+ return 0;
+free_ctx:
+ mutex_lock(&node->list_mutex);
+ list_add_tail(&ctx->list, &node->free_ctx_list);
+ mutex_unlock(&node->list_mutex);
+err:
+ return rc;
+}
+
+static int __cam_node_handle_start_dev(struct cam_node *node,
+ struct cam_start_stop_dev_cmd *start)
+{
+ struct cam_context *ctx = NULL;
+
+ if (!start)
+ return -EINVAL;
+
+ if (start->dev_handle <= 0) {
+ pr_err("Invalid device handle for context\n");
+ return -EINVAL;
+ }
+
+ if (start->session_handle <= 0) {
+ pr_err("Invalid session handle for context\n");
+ return -EINVAL;
+ }
+
+ ctx = (struct cam_context *)cam_get_device_priv(start->dev_handle);
+ if (!ctx) {
+ pr_err("%s: Can not get context for handle %d\n",
+ __func__, start->dev_handle);
+ return -EINVAL;
+ }
+
+ return cam_context_handle_start_dev(ctx, start);
+}
+
+static int __cam_node_handle_stop_dev(struct cam_node *node,
+ struct cam_start_stop_dev_cmd *stop)
+{
+ struct cam_context *ctx = NULL;
+
+ if (!stop)
+ return -EINVAL;
+
+ if (stop->dev_handle <= 0) {
+ pr_err("Invalid device handle for context\n");
+ return -EINVAL;
+ }
+
+ if (stop->session_handle <= 0) {
+ pr_err("Invalid session handle for context\n");
+ return -EINVAL;
+ }
+
+ ctx = (struct cam_context *)cam_get_device_priv(stop->dev_handle);
+ if (!ctx) {
+ pr_err("%s: Can not get context for handle %d\n",
+ __func__, stop->dev_handle);
+ return -EINVAL;
+ }
+
+ return cam_context_handle_stop_dev(ctx, stop);
+}
+
+static int __cam_node_handle_config_dev(struct cam_node *node,
+ struct cam_config_dev_cmd *config)
+{
+ struct cam_context *ctx = NULL;
+
+ if (!config)
+ return -EINVAL;
+
+ if (config->dev_handle <= 0) {
+ pr_err("Invalid device handle for context\n");
+ return -EINVAL;
+ }
+
+ if (config->session_handle <= 0) {
+ pr_err("Invalid session handle for context\n");
+ return -EINVAL;
+ }
+
+ ctx = (struct cam_context *)cam_get_device_priv(config->dev_handle);
+ if (!ctx) {
+ pr_err("%s: Can not get context for handle %d\n",
+ __func__, config->dev_handle);
+ return -EINVAL;
+ }
+
+ return cam_context_handle_config_dev(ctx, config);
+}
+
+static int __cam_node_handle_release_dev(struct cam_node *node,
+ struct cam_release_dev_cmd *release)
+{
+ int rc = 0;
+ struct cam_context *ctx = NULL;
+
+ if (!release)
+ return -EINVAL;
+
+ if (release->dev_handle <= 0) {
+ pr_err("Invalid device handle for context\n");
+ return -EINVAL;
+ }
+
+ if (release->session_handle <= 0) {
+ pr_err("Invalid session handle for context\n");
+ return -EINVAL;
+ }
+
+ ctx = (struct cam_context *)cam_get_device_priv(release->dev_handle);
+ if (!ctx) {
+ pr_err("%s: Can not get context for handle %d\n",
+ __func__, release->dev_handle);
+ return -EINVAL;
+ }
+
+ rc = cam_context_handle_release_dev(ctx, release);
+ if (rc)
+ pr_err("%s: context release failed\n", __func__);
+
+ rc = cam_destroy_device_hdl(release->dev_handle);
+ if (rc)
+ pr_err("%s: destroy device handle is failed\n", __func__);
+
+ mutex_lock(&node->list_mutex);
+ list_add_tail(&ctx->list, &node->free_ctx_list);
+ mutex_unlock(&node->list_mutex);
+ return rc;
+}
+
+static int __cam_node_get_dev_info(struct cam_req_mgr_device_info *info)
+{
+ struct cam_context *ctx = NULL;
+
+ if (!info)
+ return -EINVAL;
+
+ ctx = (struct cam_context *) cam_get_device_priv(info->dev_hdl);
+ if (!ctx) {
+ pr_err("%s: Can not get context for handle %d\n",
+ __func__, info->dev_hdl);
+ return -EINVAL;
+ }
+ return cam_context_handle_get_dev_info(ctx, info);
+}
+
+static int __cam_node_link_setup(struct cam_req_mgr_core_dev_link_setup *setup)
+{
+ int rc;
+ struct cam_context *ctx = NULL;
+
+ if (!setup)
+ return -EINVAL;
+
+ ctx = (struct cam_context *) cam_get_device_priv(setup->dev_hdl);
+ if (!ctx) {
+ pr_err("%s: Can not get context for handle %d\n",
+ __func__, setup->dev_hdl);
+ return -EINVAL;
+ }
+
+ if (setup->link_enable)
+ rc = cam_context_handle_link(ctx, setup);
+ else
+ rc = cam_context_handle_unlink(ctx, setup);
+
+ return rc;
+}
+
+static int __cam_node_apply_req(struct cam_req_mgr_apply_request *apply)
+{
+ struct cam_context *ctx = NULL;
+
+ if (!apply)
+ return -EINVAL;
+
+ ctx = (struct cam_context *) cam_get_device_priv(apply->dev_hdl);
+ if (!ctx) {
+ pr_err("%s: Can not get context for handle %d\n",
+ __func__, apply->dev_hdl);
+ return -EINVAL;
+ }
+
+ return cam_context_handle_apply_req(ctx, apply);
+}
+
+int cam_node_deinit(struct cam_node *node)
+{
+ if (node)
+ memset(node, 0, sizeof(*node));
+
+ pr_debug("%s: deinit complete!\n", __func__);
+ return 0;
+
+}
+
+int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
+ struct cam_context *ctx_list, uint32_t ctx_size, char *name)
+{
+ int rc = 0;
+ int i;
+
+ if (!node || !hw_mgr_intf ||
+ sizeof(node->hw_mgr_intf) != sizeof(*hw_mgr_intf)) {
+ return -EINVAL;
+ }
+
+ memset(node, 0, sizeof(*node));
+
+ strlcpy(node->name, name, sizeof(node->name));
+
+ memcpy(&node->hw_mgr_intf, hw_mgr_intf, sizeof(node->hw_mgr_intf));
+
+ node->crm_node_intf.apply_req = __cam_node_apply_req;
+ node->crm_node_intf.get_dev_info = __cam_node_get_dev_info;
+ node->crm_node_intf.link_setup = __cam_node_link_setup;
+
+ mutex_init(&node->list_mutex);
+ INIT_LIST_HEAD(&node->free_ctx_list);
+ node->ctx_list = ctx_list;
+ node->ctx_size = ctx_size;
+ for (i = 0; i < ctx_size; i++) {
+ if (!ctx_list[i].state_machine) {
+ pr_err("%s: camera context %d is not initialized!",
+ __func__, i);
+ rc = -1;
+ goto err;
+ }
+ INIT_LIST_HEAD(&ctx_list[i].list);
+ list_add_tail(&ctx_list[i].list, &node->free_ctx_list);
+ }
+
+ node->state = CAM_NODE_STATE_INIT;
+err:
+ pr_debug("%s: Exit. (rc = %d)\n", __func__, rc);
+ return rc;
+}
+
+int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd)
+{
+ int rc = 0;
+
+ if (!cmd)
+ return -EINVAL;
+
+ pr_debug("%s: handle cmd %d\n", __func__, cmd->op_code);
+
+ switch (cmd->op_code) {
+ case CAM_QUERY_CAP: {
+ struct cam_query_cap_cmd query;
+
+ if (copy_from_user(&query, (void __user *)cmd->handle,
+ sizeof(query))) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = __cam_node_handle_query_cap(node, &query);
+ if (rc) {
+ pr_err("%s: querycap is failed(rc = %d)\n",
+ __func__, rc);
+ break;
+ }
+ if (copy_to_user((void __user *)cmd->handle, &query,
+ sizeof(query)))
+ rc = -EFAULT;
+ break;
+ }
+ case CAM_ACQUIRE_DEV: {
+ struct cam_acquire_dev_cmd acquire;
+
+ if (copy_from_user(&acquire, (void __user *)cmd->handle,
+ sizeof(acquire))) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = __cam_node_handle_acquire_dev(node, &acquire);
+ if (rc) {
+ pr_err("%s: acquire device failed(rc = %d)\n",
+ __func__, rc);
+ break;
+ }
+ if (copy_to_user((void __user *)cmd->handle, &acquire,
+ sizeof(acquire)))
+ rc = -EFAULT;
+ break;
+ }
+ case CAM_START_DEV: {
+ struct cam_start_stop_dev_cmd start;
+
+ if (copy_from_user(&start, (void __user *)cmd->handle,
+ sizeof(start)))
+ rc = -EFAULT;
+ else {
+ rc = __cam_node_handle_start_dev(node, &start);
+ if (rc)
+ pr_err("%s: start device failed(rc = %d)\n",
+ __func__, rc);
+ }
+ break;
+ }
+ case CAM_STOP_DEV: {
+ struct cam_start_stop_dev_cmd stop;
+
+ if (copy_from_user(&stop, (void __user *)cmd->handle,
+ sizeof(stop)))
+ rc = -EFAULT;
+ else {
+ rc = __cam_node_handle_stop_dev(node, &stop);
+ if (rc)
+ pr_err("%s: stop device failed(rc = %d)\n",
+ __func__, rc);
+ }
+ break;
+ }
+ case CAM_CONFIG_DEV: {
+ struct cam_config_dev_cmd config;
+
+ if (copy_from_user(&config, (void __user *)cmd->handle,
+ sizeof(config)))
+ rc = -EFAULT;
+ else {
+ rc = __cam_node_handle_config_dev(node, &config);
+ if (rc)
+ pr_err("%s: config device failed(rc = %d)\n",
+ __func__, rc);
+ }
+ break;
+ }
+ case CAM_RELEASE_DEV: {
+ struct cam_release_dev_cmd release;
+
+ if (copy_from_user(&release, (void __user *)cmd->handle,
+ sizeof(release)))
+ rc = -EFAULT;
+ else {
+ rc = __cam_node_handle_release_dev(node, &release);
+ if (rc)
+ pr_err("%s: release device failed(rc = %d)\n",
+ __func__, rc);
+ }
+ break;
+ }
+ default:
+ pr_err("Unknown op code %d\n", cmd->op_code);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.h b/drivers/media/platform/msm/camera/cam_core/cam_node.h
new file mode 100644
index 0000000..6e4a641
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 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 _CAM_NODE_H_
+#define _CAM_NODE_H_
+
+#include "cam_context.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_req_mgr_interface.h"
+
+#define CAM_NODE_NAME_LENGTH_MAX 256
+
+#define CAM_NODE_STATE_UNINIT 0
+#define CAM_NODE_STATE_INIT 1
+
+/**
+ * struct cam_node - Singleton Node for camera HW devices
+ *
+ * @name: Name for struct cam_node
+ * @state: Node state:
+ * 0 = uninitialized, 1 = initialized
+ * @list_mutex: Mutex for the context pool
+ * @free_ctx_list: Free context pool list
+ * @ctx_list: Context list
+ * @ctx_size: Context list size
+ * @hw_mgr_intf: Interface for cam_node to HW
+ * @crm_node_intf: Interface for the CRM to cam_node
+ *
+ */
+struct cam_node {
+ char name[CAM_NODE_NAME_LENGTH_MAX];
+ uint32_t state;
+
+ /* context pool */
+ struct mutex list_mutex;
+ struct list_head free_ctx_list;
+ struct cam_context *ctx_list;
+ uint32_t ctx_size;
+
+ /* interfaces */
+ struct cam_hw_mgr_intf hw_mgr_intf;
+ struct cam_req_mgr_kmd_ops crm_node_intf;
+};
+
+/**
+ * cam_node_handle_ioctl()
+ *
+ * @brief: Handle ioctl commands
+ *
+ * @node: Node handle
+ * @cmd: IOCTL command
+ *
+ */
+int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd);
+
+/**
+ * cam_node_deinit()
+ *
+ * @brief: Deinitialization function for the Node interface
+ *
+ * @node: Node handle
+ *
+ */
+int cam_node_deinit(struct cam_node *node);
+
+/**
+ * cam_node_init()
+ *
+ * @brief: Initialization function for the Node interface.
+ *
+ * @node: Cam_node pointer
+ * @hw_mgr_intf: HW manager interface blob
+ * @ctx_list: List of cam_contexts to be added
+ * @ctx_size: Size of the cam_context
+ * @name: Name for the node
+ *
+ */
+int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
+ struct cam_context *ctx_list, uint32_t ctx_size, char *name);
+
+#endif /* _CAM_NODE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_subdev.c b/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
new file mode 100644
index 0000000..03b18cf
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
@@ -0,0 +1,143 @@
+/* Copyright (c) 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 "cam_subdev.h"
+#include "cam_node.h"
+
+/**
+ * cam_subdev_subscribe_event()
+ *
+ * @brief: function to subscribe to v4l2 events
+ *
+ * @sd: Pointer to struct v4l2_subdev.
+ * @fh: Pointer to struct v4l2_fh.
+ * @sub: Pointer to struct v4l2_event_subscription.
+ */
+static int cam_subdev_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_subscribe(fh, sub, CAM_SUBDEVICE_EVENT_MAX, NULL);
+}
+
+/**
+ * cam_subdev_unsubscribe_event()
+ *
+ * @brief: function to unsubscribe from v4l2 events
+ *
+ * @sd: Pointer to struct v4l2_subdev.
+ * @fh: Pointer to struct v4l2_fh.
+ * @sub: Pointer to struct v4l2_event_subscription.
+ */
+static int cam_subdev_unsubscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
+static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd,
+ void *arg)
+{
+ long rc;
+ struct cam_node *node =
+ (struct cam_node *) v4l2_get_subdevdata(sd);
+
+ if (!node || node->state == CAM_NODE_STATE_UNINIT) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ switch (cmd) {
+ case VIDIOC_CAM_CONTROL:
+ rc = cam_node_handle_ioctl(node,
+ (struct cam_control *) arg);
+ break;
+ default:
+ pr_err("Invalid command %d for %s!\n", cmd,
+ node->name);
+ rc = -EINVAL;
+ }
+end:
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_subdev_compat_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, unsigned long arg)
+{
+ return cam_subdev_ioctl(sd, cmd, compat_ptr(arg));
+}
+#endif
+
+const struct v4l2_subdev_core_ops cam_subdev_core_ops = {
+ .ioctl = cam_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = cam_subdev_compat_ioctl,
+#endif
+ .subscribe_event = cam_subdev_subscribe_event,
+ .unsubscribe_event = cam_subdev_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops cam_subdev_ops = {
+ .core = &cam_subdev_core_ops,
+};
+
+int cam_subdev_remove(struct cam_subdev *sd)
+{
+ if (!sd)
+ return -EINVAL;
+
+ cam_unregister_subdev(sd);
+ cam_node_deinit((struct cam_node *)sd->token);
+ kfree(sd->token);
+
+ return 0;
+}
+
+int cam_subdev_probe(struct cam_subdev *sd, struct platform_device *pdev,
+ char *name, uint32_t dev_type)
+{
+ int rc;
+ struct cam_node *node = NULL;
+
+ if (!sd || !pdev || !name) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ /* Setup camera v4l2 subdevice */
+ sd->pdev = pdev;
+ sd->name = name;
+ sd->ops = &cam_subdev_ops;
+ sd->token = node;
+ sd->sd_flags =
+ V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ sd->ent_function = dev_type;
+ rc = cam_register_subdev(sd);
+ if (rc) {
+ pr_err("%s: cam_register_subdev() failed for dev: %s!\n",
+ __func__, sd->name);
+ goto err;
+ }
+ platform_set_drvdata(sd->pdev, sd);
+ return rc;
+err:
+ kfree(node);
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_dev_mgr_util.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_dev_mgr_util.h
deleted file mode 100644
index 69970b5..0000000
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_dev_mgr_util.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (c) 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 _CAM_DEV_MGR_UTIL_H_
-#define _CAM_DEV_MGR_UTIL_H_
-
-#define CAM_SUBDEVICE_EVENT_MAX 30
-
-#include <linux/types.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-
-/**
- * struct cam_subdev - describes a camera sub-device
- *
- * @sd: struct v4l2_subdev
- * @ops: struct v4l2_subdev_ops
- * @internal_ops: struct v4l2_subdev_internal_ops
- * @name: Name of the sub-device. Please notice that the name must be unique.
- * @sd_flags: subdev flags. Can be:
- * %V4L2_SUBDEV_FL_HAS_DEVNODE - Set this flag if this subdev needs a
- * device node;
- * %V4L2_SUBDEV_FL_HAS_EVENTS - Set this flag if this subdev generates
- * events.
- * @token: pointer to cookie of the client driver
- * @ent_function: media entity function type. Can be:
- * %CAM_IFE_DEVICE_TYPE - identifies as IFE device;
- * %CAM_ICP_DEVICE_TYPE - identifies as ICP device.
- * Each instance of a subdev driver should create this struct, either
- * stand-alone or embedded in a larger struct.
- *
- * This structure should be initialized/registered by cam_register_subdev
- */
-struct cam_subdev {
- struct v4l2_subdev sd;
- const struct v4l2_subdev_ops *ops;
- const struct v4l2_subdev_internal_ops *internal_ops;
- char *name;
- u32 sd_flags;
- void *token;
- u32 ent_function;
-};
-
-/**
- * cam_register_subdev()
- *
- * @brief: Registration function for camera subdevice
- *
- * @sd: pointer to struct cam_subdev.
- */
-int cam_register_subdev(struct cam_subdev *sd);
-
-/**
- * cam_unregister_subdev()
- *
- * @brief: Unregistration function for camera subdevice
- *
- * @sd: pointer to struct cam_subdev.
- */
-int cam_unregister_subdev(struct cam_subdev *sd);
-
-/**
- * cam_send_event()
- *
- * @brief: Inline function to sent event to user space
- *
- * @csd: pointer to struct cam_subdev.
- * @ev: pointer to struct v4l2_event.
- */
-static inline int cam_send_event(struct cam_subdev *csd,
- const struct v4l2_event *ev)
-{
- if (!csd || !ev)
- return -EINVAL;
-
- v4l2_event_queue(csd->sd.devnode, ev);
-
- return 0;
-}
-
-/**
- * cam_get_subdev_data()
- *
- * @brief: Inline function to retrieve the private data
- *
- * @csd: pointer to struct cam_subdev.
- */
-static inline void *cam_get_subdev_data(struct cam_subdev *csd)
-{
- if (!csd)
- return ERR_PTR(-EINVAL);
-
- return v4l2_get_subdevdata(&csd->sd);
-}
-
-/**
- * cam_sd_subscribe_event()
- *
- * @brief: Inline function to subscribe to v4l2 events
- *
- * @sd: pointer to struct v4l2_subdev.
- * @fh: pointer to struct v4l2_fh.
- * @sub: pointer to struct v4l2_event_subscription.
- */
-static inline int cam_sd_subscribe_event(struct v4l2_subdev *sd,
- struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
-{
- return v4l2_event_subscribe(fh, sub, CAM_SUBDEVICE_EVENT_MAX, NULL);
-}
-
-/**
- * cam_sd_unsubscribe_event()
- *
- * @brief: Inline function to unsubscribe from v4l2 events
- *
- * @sd: pointer to struct v4l2_subdev.
- * @fh: pointer to struct v4l2_fh.
- * @sub: pointer to struct v4l2_event_subscription.
- */
-static inline int cam_sd_unsubscribe_event(struct v4l2_subdev *sd,
- struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
-{
- return v4l2_event_unsubscribe(fh, sub);
-}
-#endif /* _CAM_DEV_MGR_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index 2dba2c8..f3af1bd 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -23,7 +23,7 @@
#include "cam_req_mgr_dev.h"
#include "cam_req_mgr_util.h"
#include "cam_req_mgr_core.h"
-#include "cam_dev_mgr_util.h"
+#include "cam_subdev.h"
#define CAM_REQ_MGR_EVENT_MAX 30
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h
new file mode 100644
index 0000000..78f2223
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h
@@ -0,0 +1,106 @@
+/* Copyright (c) 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 _CAM_SUBDEV_H_
+#define _CAM_SUBDEV_H_
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#define CAM_SUBDEVICE_EVENT_MAX 30
+
+/**
+ * struct cam_subdev - describes a camera sub-device
+ *
+ * @pdev: Pointer to the platform device
+ * @sd: V4l2 subdevice
+ * @ops: V4l2 subdecie operations
+ * @internal_ops: V4l2 subdevice internal operations
+ * @name: Name of the sub-device. Please notice that the name
+ * must be unique.
+ * @sd_flags: Subdev flags. Can be:
+ * %V4L2_SUBDEV_FL_HAS_DEVNODE - Set this flag if
+ * this subdev needs a device node.
+ * %V4L2_SUBDEV_FL_HAS_EVENTS - Set this flag if
+ * this subdev generates events.
+ * @token: Pointer to cookie of the client driver
+ * @ent_function: Media entity function type. Can be:
+ * %CAM_IFE_DEVICE_TYPE - identifies as IFE device.
+ * %CAM_ICP_DEVICE_TYPE - identifies as ICP device.
+ *
+ * Each instance of a subdev driver should create this struct, either
+ * stand-alone or embedded in a larger struct. This structure should be
+ * initialized/registered by cam_register_subdev
+ *
+ */
+struct cam_subdev {
+ struct platform_device *pdev;
+ struct v4l2_subdev sd;
+ const struct v4l2_subdev_ops *ops;
+ const struct v4l2_subdev_internal_ops *internal_ops;
+ char *name;
+ u32 sd_flags;
+ void *token;
+ u32 ent_function;
+};
+
+/**
+ * cam_subdev_probe()
+ *
+ * @brief: Camera Subdevice node probe function for v4l2 setup
+ *
+ * @sd: Camera subdevice object
+ * @name: Name of the subdevice node
+ * @dev_type: Subdevice node type
+ *
+ */
+int cam_subdev_probe(struct cam_subdev *sd, struct platform_device *pdev,
+ char *name, uint32_t dev_type);
+
+/**
+ * cam_subdev_remove()
+ *
+ * @brief: Called when subdevice node is unloaded
+ *
+ * @sd: Camera subdevice node object
+ *
+ */
+int cam_subdev_remove(struct cam_subdev *sd);
+
+/**
+ * cam_register_subdev()
+ *
+ * @brief: This is the common utility function to be called by each camera
+ * subdevice node when it tries to register itself to the camera
+ * request manager
+ *
+ * @sd: Pointer to struct cam_subdev.
+ */
+int cam_register_subdev(struct cam_subdev *sd);
+
+/**
+ * cam_unregister_subdev()
+ *
+ * @brief: This is the common utility function to be called by each camera
+ * subdevice node when it tries to unregister itself from the
+ * camera request manger
+ *
+ * @sd: Pointer to struct cam_subdev.
+ */
+int cam_unregister_subdev(struct cam_subdev *sd);
+
+#endif /* _CAM_SUBDEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index d396d4f..683386c 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
@@ -59,7 +59,7 @@
int rc = 0;
long clk_rate_round;
- if (!clk || !clk_name || !clk_rate)
+ if (!clk || !clk_name)
return -EINVAL;
CDBG("enable %s, clk %pK rate %d\n",
@@ -231,8 +231,8 @@
return rc;
}
- rc = of_property_read_string_index(of_node, "src-clock-name",
- i, &src_clk_str);
+ rc = of_property_read_string_index(of_node, "src-clock-name", 0,
+ &src_clk_str);
if (rc) {
CDBG("No src_clk_str found\n");
soc_info->src_clk_idx = -1;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 643e8a0..27156fc 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -112,7 +112,10 @@
return -EINVAL;
}
- if (bus->bus_hdl < 1) {
+ if (!bus->bus_hdl) {
+ SDEROT_DBG("bus scaling not enabled\n");
+ return 0;
+ } else if (bus->bus_hdl < 0) {
SDEROT_ERR("invalid bus handle %d\n", bus->bus_hdl);
return -EINVAL;
}
@@ -2501,8 +2504,7 @@
mgr->data_bus.bus_scale_pdata = msm_bus_cl_get_pdata(dev);
if (IS_ERR_OR_NULL(mgr->data_bus.bus_scale_pdata)) {
ret = PTR_ERR(mgr->data_bus.bus_scale_pdata);
- if (!ret) {
- ret = -EINVAL;
+ if (ret) {
SDEROT_ERR("msm_bus_cl_get_pdata failed. ret=%d\n",
ret);
mgr->data_bus.bus_scale_pdata = NULL;
@@ -2638,8 +2640,8 @@
static int sde_rotator_bus_scale_register(struct sde_rot_mgr *mgr)
{
if (!mgr->data_bus.bus_scale_pdata) {
- SDEROT_ERR("Scale table is NULL\n");
- return -EINVAL;
+ SDEROT_DBG("Bus scaling is not enabled\n");
+ return 0;
}
mgr->data_bus.bus_hdl =
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 27e2d28..2c9c75e 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -48,7 +48,7 @@
#define XIN_WRITEBACK 1
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
-#define KOFF_TIMEOUT (42 * 32)
+#define KOFF_TIMEOUT (84)
/* default stream buffer headroom in lines */
#define DEFAULT_SBUF_HEADROOM 20
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 64937aa..0a6a1ce 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1715,6 +1715,7 @@
enable.enable = 0;
break;
case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+ enable.enable = 1;
default:
rc = -ENOTSUPP;
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 74e68e4..bc86ef4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2434,55 +2434,6 @@
put_inst(inst);
}
-static void handle_seq_hdr_done(enum hal_command_response cmd, void *data)
-{
- struct msm_vidc_cb_data_done *response = data;
- struct msm_vidc_inst *inst;
- struct vb2_buffer *vb;
- struct vidc_hal_fbd *fill_buf_done;
- struct vb2_v4l2_buffer *vbuf;
-
- if (!response) {
- dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
- return;
- }
-
- inst = get_inst(get_vidc_core(response->device_id),
- response->session_id);
- if (!inst) {
- dprintk(VIDC_WARN, "Got a response for an inactive session\n");
- return;
- }
-
- fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
- vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
- fill_buf_done->packet_buffer1);
- if (!vb) {
- dprintk(VIDC_ERR,
- "Failed to find video buffer for seq_hdr_done: %pa\n",
- &fill_buf_done->packet_buffer1);
- goto err_seq_hdr_done;
- }
- vbuf = to_vb2_v4l2_buffer(vb);
- vb->timestamp = 0;
-
- vb->planes[0].bytesused = fill_buf_done->filled_len1;
- vb->planes[0].data_offset = fill_buf_done->offset1;
-
- vbuf->flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
-
- dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
- vb->planes[0].bytesused,
- vb->planes[0].data_offset,
- vbuf->flags);
- mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
- mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
-
-err_seq_hdr_done:
- put_inst(inst);
-}
-
void handle_cmd_response(enum hal_command_response cmd, void *data)
{
dprintk(VIDC_DBG, "Command response = %d\n", cmd);
@@ -2527,9 +2478,6 @@
case HAL_SESSION_FLUSH_DONE:
handle_session_flush(cmd, data);
break;
- case HAL_SESSION_GET_SEQ_HDR_DONE:
- handle_seq_hdr_done(cmd, data);
- break;
case HAL_SYS_WATCHDOG_TIMEOUT:
case HAL_SYS_ERROR:
handle_sys_error(cmd, data);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 74e360e..58954f6 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -3176,14 +3176,12 @@
case HAL_SESSION_RESUME_DONE:
case HAL_SESSION_SET_PROP_DONE:
case HAL_SESSION_GET_PROP_DONE:
- case HAL_SESSION_PARSE_SEQ_HDR_DONE:
case HAL_SESSION_RELEASE_BUFFER_DONE:
case HAL_SESSION_RELEASE_RESOURCE_DONE:
case HAL_SESSION_PROPERTY_INFO:
session_id = &info->response.cmd.session_id;
break;
case HAL_SESSION_ERROR:
- case HAL_SESSION_GET_SEQ_HDR_DONE:
case HAL_SESSION_ETB_DONE:
case HAL_SESSION_FTB_DONE:
session_id = &info->response.data.session_id;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index d60a0d1..75d7aea 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1227,8 +1227,6 @@
HAL_SESSION_RESUME_DONE,
HAL_SESSION_SET_PROP_DONE,
HAL_SESSION_GET_PROP_DONE,
- HAL_SESSION_PARSE_SEQ_HDR_DONE,
- HAL_SESSION_GET_SEQ_HDR_DONE,
HAL_SESSION_RELEASE_BUFFER_DONE,
HAL_SESSION_RELEASE_RESOURCE_DONE,
HAL_SESSION_PROPERTY_INFO,
diff --git a/drivers/mfd/msm-cdc-pinctrl.c b/drivers/mfd/msm-cdc-pinctrl.c
index 3ffd202..9622256 100644
--- a/drivers/mfd/msm-cdc-pinctrl.c
+++ b/drivers/mfd/msm-cdc-pinctrl.c
@@ -180,13 +180,15 @@
ret = PTR_ERR(gpio_data->pinctrl_sleep);
goto err_lookup_state;
}
-
- /* Set pinctrl state to aud_sleep by default */
- ret = pinctrl_select_state(gpio_data->pinctrl,
- gpio_data->pinctrl_sleep);
- if (ret)
- dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
- __func__, ret);
+ /* skip setting to sleep state for LPI_TLMM GPIOs */
+ if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
+ /* Set pinctrl state to aud_sleep by default */
+ ret = pinctrl_select_state(gpio_data->pinctrl,
+ gpio_data->pinctrl_sleep);
+ if (ret)
+ dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
+ __func__, ret);
+ }
gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,cdc-rst-n-gpio", 0);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index f0126dd..d143536 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -505,6 +505,7 @@
mutex_init(&wcd9xxx->io_lock);
mutex_init(&wcd9xxx->xfer_lock);
+ mutex_init(&wcd9xxx->reset_lock);
ret = wcd9xxx_bringup(wcd9xxx->dev);
if (ret) {
@@ -583,6 +584,7 @@
err_bring_up:
mutex_destroy(&wcd9xxx->io_lock);
mutex_destroy(&wcd9xxx->xfer_lock);
+ mutex_destroy(&wcd9xxx->reset_lock);
return ret;
}
@@ -595,6 +597,7 @@
wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
mutex_destroy(&wcd9xxx->io_lock);
mutex_destroy(&wcd9xxx->xfer_lock);
+ mutex_destroy(&wcd9xxx->reset_lock);
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
slim_remove_device(wcd9xxx->slim_slave);
}
@@ -1215,11 +1218,19 @@
{
struct wcd9xxx *wcd9xxx;
struct wcd9xxx_pdata *pdata;
+ const struct slim_device_id *device_id;
int ret = 0;
int intf_type;
intf_type = wcd9xxx_get_intf_type();
+ wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx),
+ GFP_KERNEL);
+ if (!wcd9xxx) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
if (!slim) {
ret = -EINVAL;
goto err;
@@ -1228,7 +1239,8 @@
if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n",
__func__);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
if (slim->dev.of_node) {
dev_info(&slim->dev, "Platform data from device tree\n");
@@ -1262,21 +1274,22 @@
goto err;
}
- wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx),
- GFP_KERNEL);
- if (!wcd9xxx) {
- ret = -ENOMEM;
- goto err;
- }
if (!slim->ctrl) {
dev_err(&slim->dev, "%s: Error, no SLIMBUS control data\n",
__func__);
ret = -EINVAL;
goto err_codec;
}
- wcd9xxx->type = slim_get_device_id(slim)->driver_data;
+ device_id = slim_get_device_id(slim);
+ if (!device_id) {
+ dev_err(&slim->dev, "%s: Error, no device id\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ wcd9xxx->type = device_id->driver_data;
dev_info(&slim->dev, "%s: probing for wcd type: %d, name: %s\n",
- __func__, wcd9xxx->type, slim_get_device_id(slim)->name);
+ __func__, wcd9xxx->type, device_id->name);
/* wcd9xxx members init */
wcd9xxx->multi_reg_write = wcd9xxx_slim_multi_reg_write;
@@ -1417,6 +1430,7 @@
err_codec:
slim_set_clientdata(slim, NULL);
err:
+ devm_kfree(&slim->dev, wcd9xxx);
return ret;
}
static int wcd9xxx_slim_remove(struct slim_device *pdev)
@@ -1470,9 +1484,11 @@
if (wcd9xxx->dev_up)
return 0;
+ mutex_lock(&wcd9xxx->reset_lock);
ret = wcd9xxx_reset(wcd9xxx->dev);
if (ret)
dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__);
+ mutex_unlock(&wcd9xxx->reset_lock);
return ret;
}
@@ -1480,6 +1496,7 @@
static int wcd9xxx_slim_device_up(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+ int ret = 0;
if (!wcd9xxx) {
pr_err("%s: wcd9xxx is NULL\n", __func__);
@@ -1491,7 +1508,12 @@
return 0;
wcd9xxx->dev_up = true;
- return wcd9xxx_device_up(wcd9xxx);
+
+ mutex_lock(&wcd9xxx->reset_lock);
+ ret = wcd9xxx_device_up(wcd9xxx);
+ mutex_unlock(&wcd9xxx->reset_lock);
+
+ return ret;
}
static int wcd9xxx_slim_device_down(struct slim_device *sldev)
@@ -1509,10 +1531,14 @@
return 0;
wcd9xxx->dev_up = false;
- wcd9xxx_irq_exit(&wcd9xxx->core_res);
+
+ mutex_lock(&wcd9xxx->reset_lock);
if (wcd9xxx->dev_down)
wcd9xxx->dev_down(wcd9xxx);
+ wcd9xxx_irq_exit(&wcd9xxx->core_res);
wcd9xxx_reset_low(wcd9xxx->dev);
+ mutex_unlock(&wcd9xxx->reset_lock);
+
return 0;
}
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index d747408..30ad689e 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -307,6 +307,7 @@
goto err_disable_irq;
}
+ memset(status, 0, sizeof(status));
ret = regmap_bulk_read(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_STATUS_BASE],
status, num_irq_regs);
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index d3a926c..8bf1404 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -62,6 +62,10 @@
goto err;
}
+ if (!rx_num || rx_num > wcd9xxx->num_rx_port) {
+ pr_err("%s: invalid rx num %d\n", __func__, rx_num);
+ return -EINVAL;
+ }
if (wcd9xxx->rx_chs) {
wcd9xxx->num_rx_port = rx_num;
for (i = 0; i < rx_num; i++) {
@@ -84,6 +88,10 @@
wcd9xxx->num_rx_port);
}
+ if (!tx_num || tx_num > wcd9xxx->num_tx_port) {
+ pr_err("%s: invalid tx num %d\n", __func__, tx_num);
+ return -EINVAL;
+ }
if (wcd9xxx->tx_chs) {
wcd9xxx->num_tx_port = tx_num;
for (i = 0; i < tx_num; i++) {
diff --git a/drivers/mfd/wcd9xxx-utils.c b/drivers/mfd/wcd9xxx-utils.c
index 007b99d..8d3d4ad 100644
--- a/drivers/mfd/wcd9xxx-utils.c
+++ b/drivers/mfd/wcd9xxx-utils.c
@@ -669,7 +669,7 @@
return -EINVAL;
}
- value = msm_cdc_get_gpio_state(wcd9xxx->wcd_rst_np);
+ value = msm_cdc_pinctrl_get_state(wcd9xxx->wcd_rst_np);
if (value > 0) {
wcd9xxx->avoid_cdc_rstlow = 1;
return 0;
diff --git a/drivers/misc/qcom/qdsp6v2/aac_in.c b/drivers/misc/qcom/qdsp6v2/aac_in.c
index b74aa59..c0828dc 100644
--- a/drivers/misc/qcom/qdsp6v2/aac_in.c
+++ b/drivers/misc/qcom/qdsp6v2/aac_in.c
@@ -34,6 +34,8 @@
#define AAC_FORMAT_ADTS 65535
+#define MAX_SAMPLE_RATE_384K 384000
+
static long aac_in_ioctl_shared(struct file *file, unsigned int cmd, void *arg)
{
struct q6audio_in *audio = file->private_data;
@@ -233,6 +235,13 @@
break;
}
+ if (cfg->sample_rate > MAX_SAMPLE_RATE_384K) {
+ pr_err("%s: ERROR: invalid sample rate = %u",
+ __func__, cfg->sample_rate);
+ 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
diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
index c1d792b..b97a584 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
@@ -29,6 +29,8 @@
struct audio_client *ac;
struct msm_hwacc_effects_config config;
+ struct mutex lock;
+
atomic_t in_count;
atomic_t out_count;
@@ -231,8 +233,11 @@
uint32_t idx = 0;
uint32_t size = 0;
+ mutex_lock(&effects->lock);
+
if (!effects->started) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
@@ -242,11 +247,13 @@
if (!rc) {
pr_err("%s: write wait_event_timeout\n", __func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if (!atomic_read(&effects->out_count)) {
pr_err("%s: pcm stopped out_count 0\n", __func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
@@ -256,6 +263,7 @@
copy_from_user(bufptr, (void *)arg,
effects->config.buf_cfg.output_len)) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
rc = q6asm_write(effects->ac,
@@ -263,6 +271,7 @@
0, 0, NO_TIMESTAMP);
if (rc < 0) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
atomic_dec(&effects->out_count);
@@ -270,6 +279,7 @@
pr_err("%s: AUDIO_EFFECTS_WRITE: Buffer dropped\n",
__func__);
}
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_READ: {
@@ -469,6 +479,7 @@
break;
}
case AUDIO_EFFECTS_SET_BUF_LEN: {
+ mutex_lock(&effects->lock);
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",
@@ -478,6 +489,7 @@
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);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_GET_BUF_AVAIL: {
@@ -725,6 +737,7 @@
}
q6asm_audio_client_free(effects->ac);
+ mutex_destroy(&effects->lock);
kfree(effects);
pr_debug("%s: close session success\n", __func__);
@@ -752,6 +765,7 @@
init_waitqueue_head(&effects->read_wait);
init_waitqueue_head(&effects->write_wait);
+ mutex_init(&effects->lock);
effects->opened = 0;
effects->started = 0;
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index 73746ee..06e0dc3 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -122,7 +122,10 @@
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) {
+ addr + len <= region_elt->vaddr + region_elt->len &&
+ addr + len > addr) {
+ /* to avoid integer addition overflow */
+
/* offset since we could pass vaddr inside a registered
* ion buffer
*/
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index daad32f..36d9d69 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -37,3 +37,13 @@
about re-trying SD init requests. This can be a useful
work-around for buggy controllers and hardware. Enable
if you are experiencing issues with SD detection.
+
+config MMC_CLKGATE
+ bool "MMC host clock gating"
+ help
+ This will attempt to aggressively gate the clock to the MMC card.
+ This is done to save power due to gating off the logic and bus
+ noise when the MMC card is not in use. Your host driver has to
+ support handling this in order for it to be of any use.
+
+ If unsure, say N.
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 40ddc3e..e7af954 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -226,6 +226,8 @@
if (mrq->done)
mrq->done(mrq);
+
+ mmc_host_clk_release(host);
}
}
@@ -340,6 +342,7 @@
mrq->stop->mrq = mrq;
}
}
+ mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
__mmc_start_request(host, mrq);
@@ -634,8 +637,11 @@
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
bool is_first_req)
{
- if (host->ops->pre_req)
+ if (host->ops->pre_req) {
+ mmc_host_clk_hold(host);
host->ops->pre_req(host, mrq, is_first_req);
+ mmc_host_clk_release(host);
+ }
}
/**
@@ -650,8 +656,11 @@
static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
int err)
{
- if (host->ops->post_req)
+ if (host->ops->post_req) {
+ mmc_host_clk_hold(host);
host->ops->post_req(host, mrq, err);
+ mmc_host_clk_release(host);
+ }
}
/**
@@ -949,9 +958,9 @@
unsigned int timeout_us, limit_us;
timeout_us = data->timeout_ns / 1000;
- if (card->host->ios.clock)
+ if (mmc_host_clk_rate(card->host))
timeout_us += data->timeout_clks * 1000 /
- (card->host->ios.clock / 1000);
+ (mmc_host_clk_rate(card->host) / 1000);
if (data->flags & MMC_DATA_WRITE)
/*
@@ -1149,6 +1158,8 @@
ios->power_mode, ios->chip_select, ios->vdd,
1 << ios->bus_width, ios->timing);
+ if (ios->clock > 0)
+ mmc_set_ungated(host);
host->ops->set_ios(host, ios);
}
@@ -1157,15 +1168,17 @@
*/
void mmc_set_chip_select(struct mmc_host *host, int mode)
{
+ mmc_host_clk_hold(host);
host->ios.chip_select = mode;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
* Sets the host clock to the highest possible frequency that
* is below "hz".
*/
-void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
WARN_ON(hz && hz < host->f_min);
@@ -1176,6 +1189,68 @@
mmc_set_ios(host);
}
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+{
+ mmc_host_clk_hold(host);
+ __mmc_set_clock(host, hz);
+ mmc_host_clk_release(host);
+}
+
+#ifdef CONFIG_MMC_CLKGATE
+/*
+ * This gates the clock by setting it to 0 Hz.
+ */
+void mmc_gate_clock(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clk_old = host->ios.clock;
+ host->ios.clock = 0;
+ host->clk_gated = true;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mmc_set_ios(host);
+}
+
+/*
+ * This restores the clock from gating by using the cached
+ * clock value.
+ */
+void mmc_ungate_clock(struct mmc_host *host)
+{
+ /*
+ * We should previously have gated the clock, so the clock shall
+ * be 0 here! The clock may however be 0 during initialization,
+ * when some request operations are performed before setting
+ * the frequency. When ungate is requested in that situation
+ * we just ignore the call.
+ */
+ if (host->clk_old) {
+ BUG_ON(host->ios.clock);
+ /* This call will also set host->clk_gated to false */
+ __mmc_set_clock(host, host->clk_old);
+ }
+}
+
+void mmc_set_ungated(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ /*
+ * We've been given a new frequency while the clock is gated,
+ * so make sure we regard this as ungating it.
+ */
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clk_gated = false;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+}
+
+#else
+void mmc_set_ungated(struct mmc_host *host)
+{
+}
+#endif
+
int mmc_execute_tuning(struct mmc_card *card)
{
struct mmc_host *host = card->host;
@@ -1190,7 +1265,9 @@
else
opcode = MMC_SEND_TUNING_BLOCK;
+ mmc_host_clk_hold(host);
err = host->ops->execute_tuning(host, opcode);
+ mmc_host_clk_release(host);
if (err)
pr_err("%s: tuning execution failed: %d\n",
@@ -1206,8 +1283,10 @@
*/
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
{
+ mmc_host_clk_hold(host);
host->ios.bus_mode = mode;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -1215,8 +1294,10 @@
*/
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
+ mmc_host_clk_hold(host);
host->ios.bus_width = width;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -1671,8 +1752,11 @@
int old_signal_voltage = host->ios.signal_voltage;
host->ios.signal_voltage = signal_voltage;
- if (host->ops->start_signal_voltage_switch)
+ if (host->ops->start_signal_voltage_switch) {
+ mmc_host_clk_hold(host);
err = host->ops->start_signal_voltage_switch(host, &host->ios);
+ mmc_host_clk_release(host);
+ }
if (err)
host->ios.signal_voltage = old_signal_voltage;
@@ -1706,17 +1790,20 @@
pr_warn("%s: cannot verify signal voltage switch\n",
mmc_hostname(host));
+ mmc_host_clk_hold(host);
+
cmd.opcode = SD_SWITCH_VOLTAGE;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
- return err;
+ goto err_command;
- if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
- return -EIO;
-
+ if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
+ err = -EIO;
+ goto err_command;
+ }
/*
* The card should drive cmd and dat[0:3] low immediately
* after the response of cmd11, but wait 1 ms to be sure
@@ -1765,6 +1852,9 @@
mmc_power_cycle(host, ocr);
}
+err_command:
+ mmc_host_clk_release(host);
+
return err;
}
@@ -1773,8 +1863,10 @@
*/
void mmc_set_timing(struct mmc_host *host, unsigned int timing)
{
+ mmc_host_clk_hold(host);
host->ios.timing = timing;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -1782,8 +1874,10 @@
*/
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
{
+ mmc_host_clk_hold(host);
host->ios.drv_type = drv_type;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
@@ -1791,6 +1885,7 @@
{
struct mmc_host *host = card->host;
int host_drv_type = SD_DRIVER_TYPE_B;
+ int drive_strength;
*drv_type = 0;
@@ -1813,10 +1908,14 @@
* information and let the hardware specific code
* return what is possible given the options
*/
- return host->ops->select_drive_strength(card, max_dtr,
- host_drv_type,
- card_drv_type,
- drv_type);
+ mmc_host_clk_hold(host);
+ drive_strength = host->ops->select_drive_strength(card, max_dtr,
+ host_drv_type,
+ card_drv_type,
+ drv_type);
+ mmc_host_clk_release(host);
+
+ return drive_strength;
}
/*
@@ -1835,6 +1934,8 @@
if (host->ios.power_mode == MMC_POWER_ON)
return;
+ mmc_host_clk_hold(host);
+
mmc_pwrseq_pre_power_on(host);
host->ios.vdd = fls(ocr) - 1;
@@ -1868,6 +1969,8 @@
* time required to reach a stable voltage.
*/
mmc_delay(10);
+
+ mmc_host_clk_release(host);
}
void mmc_power_off(struct mmc_host *host)
@@ -1875,6 +1978,8 @@
if (host->ios.power_mode == MMC_POWER_OFF)
return;
+ mmc_host_clk_hold(host);
+
mmc_pwrseq_power_off(host);
host->ios.clock = 0;
@@ -1890,6 +1995,8 @@
* can be successfully turned on again.
*/
mmc_delay(1);
+
+ mmc_host_clk_release(host);
}
void mmc_power_cycle(struct mmc_host *host, u32 ocr)
@@ -2103,7 +2210,7 @@
*/
timeout_clks <<= 1;
timeout_us += (timeout_clks * 1000) /
- (card->host->ios.clock / 1000);
+ (mmc_host_clk_rate(card->host) / 1000);
erase_timeout = timeout_us / 1000;
@@ -2626,7 +2733,9 @@
{
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
return;
+ mmc_host_clk_hold(host);
host->ops->hw_reset(host);
+ mmc_host_clk_release(host);
}
int mmc_hw_reset(struct mmc_host *host)
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 0fa86a2..c975c7a 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -40,6 +40,9 @@
void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+void mmc_gate_clock(struct mmc_host *host);
+void mmc_ungate_clock(struct mmc_host *host);
+void mmc_set_ungated(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index c8451ce..bf0f6ce 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -256,6 +256,11 @@
&mmc_clock_fops))
goto err_node;
+#ifdef CONFIG_MMC_CLKGATE
+ if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
+ root, &host->clk_delay))
+ goto err_node;
+#endif
#ifdef CONFIG_FAIL_MMC_REQUEST
if (fail_request)
setup_fault_attr(&fail_default_attr, fail_request);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 348b58b..f18105f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -58,6 +58,246 @@
class_unregister(&mmc_host_class);
}
+#ifdef CONFIG_MMC_CLKGATE
+static ssize_t clkgate_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
+}
+
+static ssize_t clkgate_delay_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ unsigned long flags, value;
+
+ if (kstrtoul(buf, 0, &value))
+ return -EINVAL;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clkgate_delay = value;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ return count;
+}
+
+/*
+ * Enabling clock gating will make the core call out to the host
+ * once up and once down when it performs a request or card operation
+ * intermingled in any fashion. The driver will see this through
+ * set_ios() operations with ios.clock field set to 0 to gate (disable)
+ * the block clock, and to the old frequency to enable it again.
+ */
+static void mmc_host_clk_gate_delayed(struct mmc_host *host)
+{
+ unsigned long tick_ns;
+ unsigned long freq = host->ios.clock;
+ unsigned long flags;
+
+ if (!freq) {
+ pr_debug("%s: frequency set to 0 in disable function, "
+ "this means the clock is already disabled.\n",
+ mmc_hostname(host));
+ return;
+ }
+ /*
+ * New requests may have appeared while we were scheduling,
+ * then there is no reason to delay the check before
+ * clk_disable().
+ */
+ spin_lock_irqsave(&host->clk_lock, flags);
+
+ /*
+ * Delay n bus cycles (at least 8 from MMC spec) before attempting
+ * to disable the MCI block clock. The reference count may have
+ * gone up again after this delay due to rescheduling!
+ */
+ if (!host->clk_requests) {
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ tick_ns = DIV_ROUND_UP(1000000000, freq);
+ ndelay(host->clk_delay * tick_ns);
+ } else {
+ /* New users appeared while waiting for this work */
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ return;
+ }
+ mutex_lock(&host->clk_gate_mutex);
+ spin_lock_irqsave(&host->clk_lock, flags);
+ if (!host->clk_requests) {
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ /* This will set host->ios.clock to 0 */
+ mmc_gate_clock(host);
+ spin_lock_irqsave(&host->clk_lock, flags);
+ pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
+ }
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mutex_unlock(&host->clk_gate_mutex);
+}
+
+/*
+ * Internal work. Work to disable the clock at some later point.
+ */
+static void mmc_host_clk_gate_work(struct work_struct *work)
+{
+ struct mmc_host *host = container_of(work, struct mmc_host,
+ clk_gate_work.work);
+
+ mmc_host_clk_gate_delayed(host);
+}
+
+/**
+ * mmc_host_clk_hold - ungate hardware MCI clocks
+ * @host: host to ungate.
+ *
+ * Makes sure the host ios.clock is restored to a non-zero value
+ * past this call. Increase clock reference count and ungate clock
+ * if we're the first user.
+ */
+void mmc_host_clk_hold(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ /* cancel any clock gating work scheduled by mmc_host_clk_release() */
+ cancel_delayed_work_sync(&host->clk_gate_work);
+ mutex_lock(&host->clk_gate_mutex);
+ spin_lock_irqsave(&host->clk_lock, flags);
+ if (host->clk_gated) {
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mmc_ungate_clock(host);
+ spin_lock_irqsave(&host->clk_lock, flags);
+ pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
+ }
+ host->clk_requests++;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mutex_unlock(&host->clk_gate_mutex);
+}
+
+/**
+ * mmc_host_may_gate_card - check if this card may be gated
+ * @card: card to check.
+ */
+static bool mmc_host_may_gate_card(struct mmc_card *card)
+{
+ /* If there is no card we may gate it */
+ if (!card)
+ return true;
+ /*
+ * Don't gate SDIO cards! These need to be clocked at all times
+ * since they may be independent systems generating interrupts
+ * and other events. The clock requests counter from the core will
+ * go down to zero since the core does not need it, but we will not
+ * gate the clock, because there is somebody out there that may still
+ * be using it.
+ */
+ return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
+}
+
+/**
+ * mmc_host_clk_release - gate off hardware MCI clocks
+ * @host: host to gate.
+ *
+ * Calls the host driver with ios.clock set to zero as often as possible
+ * in order to gate off hardware MCI clocks. Decrease clock reference
+ * count and schedule disabling of clock.
+ */
+void mmc_host_clk_release(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clk_requests--;
+ if (mmc_host_may_gate_card(host->card) &&
+ !host->clk_requests)
+ schedule_delayed_work(&host->clk_gate_work,
+ msecs_to_jiffies(host->clkgate_delay));
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+}
+
+/**
+ * mmc_host_clk_rate - get current clock frequency setting
+ * @host: host to get the clock frequency for.
+ *
+ * Returns current clock frequency regardless of gating.
+ */
+unsigned int mmc_host_clk_rate(struct mmc_host *host)
+{
+ unsigned long freq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ if (host->clk_gated)
+ freq = host->clk_old;
+ else
+ freq = host->ios.clock;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ return freq;
+}
+
+/**
+ * mmc_host_clk_init - set up clock gating code
+ * @host: host with potential clock to control
+ */
+static inline void mmc_host_clk_init(struct mmc_host *host)
+{
+ host->clk_requests = 0;
+ /* Hold MCI clock for 8 cycles by default */
+ host->clk_delay = 8;
+ /*
+ * Default clock gating delay is 0ms to avoid wasting power.
+ * This value can be tuned by writing into sysfs entry.
+ */
+ host->clkgate_delay = 0;
+ host->clk_gated = false;
+ INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
+ spin_lock_init(&host->clk_lock);
+ mutex_init(&host->clk_gate_mutex);
+}
+
+/**
+ * mmc_host_clk_exit - shut down clock gating code
+ * @host: host with potential clock to control
+ */
+static inline void mmc_host_clk_exit(struct mmc_host *host)
+{
+ /*
+ * Wait for any outstanding gate and then make sure we're
+ * ungated before exiting.
+ */
+ if (cancel_delayed_work_sync(&host->clk_gate_work))
+ mmc_host_clk_gate_delayed(host);
+ if (host->clk_gated)
+ mmc_host_clk_hold(host);
+ /* There should be only one user now */
+ WARN_ON(host->clk_requests > 1);
+}
+
+static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+{
+ host->clkgate_delay_attr.show = clkgate_delay_show;
+ host->clkgate_delay_attr.store = clkgate_delay_store;
+ sysfs_attr_init(&host->clkgate_delay_attr.attr);
+ host->clkgate_delay_attr.attr.name = "clkgate_delay";
+ host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
+ if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
+ pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
+ mmc_hostname(host));
+}
+#else
+
+static inline void mmc_host_clk_init(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_exit(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+{
+}
+
+#endif
+
void mmc_retune_enable(struct mmc_host *host)
{
host->can_retune = 1;
@@ -382,6 +622,8 @@
return NULL;
}
+ mmc_host_clk_init(host);
+
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
@@ -427,6 +669,7 @@
#ifdef CONFIG_DEBUG_FS
mmc_add_host_debugfs(host);
#endif
+ mmc_host_clk_sysfs_init(host);
#ifdef CONFIG_BLOCK
mmc_latency_hist_sysfs_init(host);
@@ -466,6 +709,8 @@
device_del(&host->class_dev);
led_trigger_unregister_simple(host->led);
+
+ mmc_host_clk_exit(host);
}
EXPORT_SYMBOL(mmc_remove_host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 5aa3f09..56e6355 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2096,11 +2096,13 @@
if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
mmc_can_reset(card)) {
+ mmc_host_clk_hold(host);
/* If the card accept RST_n signal, send it. */
mmc_set_clock(host, host->f_init);
host->ops->hw_reset(host);
/* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host);
+ mmc_host_clk_release(host);
} else {
/* Do a brute force power cycle */
mmc_power_cycle(host, card->ocr);
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index ca9cade..4e65ea5 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -35,7 +35,25 @@
#define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128
#endif
+/*
+ * This hook just adds a quirk for all sdio devices
+ */
+static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
+{
+ if (mmc_card_sdio(card))
+ card->quirks |= data;
+}
+
static const struct mmc_fixup mmc_fixup_methods[] = {
+ /* by default sdio devices are considered CLK_GATING broken */
+ /* good cards will be whitelisted as they are tested */
+ SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
+ add_quirk_for_sdio_devices,
+ MMC_QUIRK_BROKEN_CLK_GATING),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index a0aa64e..60542b2 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -838,7 +838,9 @@
if (!host->ops->get_ro)
return -1;
+ mmc_host_clk_hold(host);
ro = host->ops->get_ro(host);
+ mmc_host_clk_release(host);
return ro;
}
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index b5ec3c8..8e10bdc 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -976,10 +976,13 @@
}
if (!err && host->sdio_irqs) {
- if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
+ if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
wake_up_process(host->sdio_irq_thread);
- else if (host->caps & MMC_CAP_SDIO_IRQ)
+ } else if (host->caps & MMC_CAP_SDIO_IRQ) {
+ mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1);
+ mmc_host_clk_release(host);
+ }
}
mmc_release_host(host);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 91bbbfb..09cc67d 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -168,15 +168,21 @@
}
set_current_state(TASK_INTERRUPTIBLE);
- if (host->caps & MMC_CAP_SDIO_IRQ)
+ if (host->caps & MMC_CAP_SDIO_IRQ) {
+ mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1);
+ mmc_host_clk_release(host);
+ }
if (!kthread_should_stop())
schedule_timeout(period);
set_current_state(TASK_RUNNING);
} while (!kthread_should_stop());
- if (host->caps & MMC_CAP_SDIO_IRQ)
+ if (host->caps & MMC_CAP_SDIO_IRQ) {
+ mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 0);
+ mmc_host_clk_release(host);
+ }
pr_debug("%s: IRQ thread exiting with code %d\n",
mmc_hostname(host), ret);
@@ -202,7 +208,9 @@
return err;
}
} else if (host->caps & MMC_CAP_SDIO_IRQ) {
+ mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1);
+ mmc_host_clk_release(host);
}
}
@@ -221,7 +229,9 @@
atomic_set(&host->sdio_irq_thread_abort, 1);
kthread_stop(host->sdio_irq_thread);
} else if (host->caps & MMC_CAP_SDIO_IRQ) {
+ mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 0);
+ mmc_host_clk_release(host);
}
}
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 410a55b..1cfd7f9 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -28,13 +28,9 @@
#include "sdhci-pltfm.h"
#include <linux/of.h>
-#define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c
#define SDHCI_ARASAN_VENDOR_REGISTER 0x78
#define VENDOR_ENHANCED_STROBE BIT(0)
-#define CLK_CTRL_TIMEOUT_SHIFT 16
-#define CLK_CTRL_TIMEOUT_MASK (0xf << CLK_CTRL_TIMEOUT_SHIFT)
-#define CLK_CTRL_TIMEOUT_MIN_EXP 13
#define PHY_CLK_TOO_SLOW_HZ 400000
@@ -163,15 +159,15 @@
static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
{
- u32 div;
unsigned long freq;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- div = readl(host->ioaddr + SDHCI_ARASAN_CLK_CTRL_OFFSET);
- div = (div & CLK_CTRL_TIMEOUT_MASK) >> CLK_CTRL_TIMEOUT_SHIFT;
+ /* SDHCI timeout clock is in kHz */
+ freq = DIV_ROUND_UP(clk_get_rate(pltfm_host->clk), 1000);
- freq = clk_get_rate(pltfm_host->clk);
- freq /= 1 << (CLK_CTRL_TIMEOUT_MIN_EXP + div);
+ /* or in MHz */
+ if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
+ freq = DIV_ROUND_UP(freq, 1000);
return freq;
}
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index a9b7fc0..387ae1c 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -85,11 +85,30 @@
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
+/*
+ * In this specific implementation of the SDHCI controller, the power register
+ * needs to have a valid voltage set even when the power supply is managed by
+ * an external regulator.
+ */
+static void sdhci_at91_set_power(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd)
+{
+ if (!IS_ERR(host->mmc->supply.vmmc)) {
+ struct mmc_host *mmc = host->mmc;
+
+ spin_unlock_irq(&host->lock);
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+ spin_lock_irq(&host->lock);
+ }
+ sdhci_set_power_noreg(host, mode, vdd);
+}
+
static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
.set_clock = sdhci_at91_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
+ .set_power = sdhci_at91_set_power,
};
static const struct sdhci_pltfm_data soc_data_sama5d2 = {
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 1d9e00a..b0b9ceb 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -412,6 +412,8 @@
if (mode == MMC_POWER_OFF)
return;
+ spin_unlock_irq(&host->lock);
+
/*
* Bus power might not enable after D3 -> D0 transition due to the
* present state not yet having propagated. Retry for up to 2ms.
@@ -424,6 +426,8 @@
reg |= SDHCI_POWER_ON;
sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
}
+
+ spin_lock_irq(&host->lock);
}
static const struct sdhci_ops sdhci_intel_byt_ops = {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ba637ff..a983ba0 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1371,7 +1371,9 @@
return;
}
timeout--;
- mdelay(1);
+ spin_unlock_irq(&host->lock);
+ usleep_range(900, 1100);
+ spin_lock_irq(&host->lock);
}
clk |= SDHCI_CLOCK_CARD_EN;
diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c
index d2c386f..1d84335 100644
--- a/drivers/mmc/host/ushc.c
+++ b/drivers/mmc/host/ushc.c
@@ -426,6 +426,9 @@
struct ushc_data *ushc;
int ret;
+ if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
if (mmc == NULL)
return -ENOMEM;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index bbef959..1592e1c 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -917,8 +917,8 @@
#define RX_PACKET_ATTRIBUTES_CSUM_DONE_WIDTH 1
#define RX_PACKET_ATTRIBUTES_VLAN_CTAG_INDEX 1
#define RX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH 1
-#define RX_PACKET_ATTRIBUTES_INCOMPLETE_INDEX 2
-#define RX_PACKET_ATTRIBUTES_INCOMPLETE_WIDTH 1
+#define RX_PACKET_ATTRIBUTES_LAST_INDEX 2
+#define RX_PACKET_ATTRIBUTES_LAST_WIDTH 1
#define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_INDEX 3
#define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_WIDTH 1
#define RX_PACKET_ATTRIBUTES_CONTEXT_INDEX 4
@@ -927,6 +927,8 @@
#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_WIDTH 1
#define RX_PACKET_ATTRIBUTES_RSS_HASH_INDEX 6
#define RX_PACKET_ATTRIBUTES_RSS_HASH_WIDTH 1
+#define RX_PACKET_ATTRIBUTES_FIRST_INDEX 7
+#define RX_PACKET_ATTRIBUTES_FIRST_WIDTH 1
#define RX_NORMAL_DESC0_OVT_INDEX 0
#define RX_NORMAL_DESC0_OVT_WIDTH 16
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 1babcc1..ca106d4 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1721,10 +1721,15 @@
/* Get the header length */
if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD)) {
+ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+ FIRST, 1);
rdata->rx.hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
RX_NORMAL_DESC2, HL);
if (rdata->rx.hdr_len)
pdata->ext_stats.rx_split_header_packets++;
+ } else {
+ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+ FIRST, 0);
}
/* Get the RSS hash */
@@ -1747,19 +1752,16 @@
}
}
- /* Get the packet length */
- rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
-
- if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD)) {
- /* Not all the data has been transferred for this packet */
- XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
- INCOMPLETE, 1);
+ /* Not all the data has been transferred for this packet */
+ if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD))
return 0;
- }
/* This is the last of the data for this packet */
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
- INCOMPLETE, 0);
+ LAST, 1);
+
+ /* Get the packet length */
+ rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
/* Set checksum done indicator as appropriate */
if (netdev->features & NETIF_F_RXCSUM)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 7f9216d..0f0f3014 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1752,13 +1752,12 @@
{
struct sk_buff *skb;
u8 *packet;
- unsigned int copy_len;
skb = napi_alloc_skb(napi, rdata->rx.hdr.dma_len);
if (!skb)
return NULL;
- /* Start with the header buffer which may contain just the header
+ /* Pull in the header buffer which may contain just the header
* or the header plus data
*/
dma_sync_single_range_for_cpu(pdata->dev, rdata->rx.hdr.dma_base,
@@ -1767,30 +1766,49 @@
packet = page_address(rdata->rx.hdr.pa.pages) +
rdata->rx.hdr.pa.pages_offset;
- copy_len = (rdata->rx.hdr_len) ? rdata->rx.hdr_len : len;
- copy_len = min(rdata->rx.hdr.dma_len, copy_len);
- skb_copy_to_linear_data(skb, packet, copy_len);
- skb_put(skb, copy_len);
-
- len -= copy_len;
- if (len) {
- /* Add the remaining data as a frag */
- dma_sync_single_range_for_cpu(pdata->dev,
- rdata->rx.buf.dma_base,
- rdata->rx.buf.dma_off,
- rdata->rx.buf.dma_len,
- DMA_FROM_DEVICE);
-
- skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
- rdata->rx.buf.pa.pages,
- rdata->rx.buf.pa.pages_offset,
- len, rdata->rx.buf.dma_len);
- rdata->rx.buf.pa.pages = NULL;
- }
+ skb_copy_to_linear_data(skb, packet, len);
+ skb_put(skb, len);
return skb;
}
+static unsigned int xgbe_rx_buf1_len(struct xgbe_ring_data *rdata,
+ struct xgbe_packet_data *packet)
+{
+ /* Always zero if not the first descriptor */
+ if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, FIRST))
+ return 0;
+
+ /* First descriptor with split header, return header length */
+ if (rdata->rx.hdr_len)
+ return rdata->rx.hdr_len;
+
+ /* First descriptor but not the last descriptor and no split header,
+ * so the full buffer was used
+ */
+ if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, LAST))
+ return rdata->rx.hdr.dma_len;
+
+ /* First descriptor and last descriptor and no split header, so
+ * calculate how much of the buffer was used
+ */
+ return min_t(unsigned int, rdata->rx.hdr.dma_len, rdata->rx.len);
+}
+
+static unsigned int xgbe_rx_buf2_len(struct xgbe_ring_data *rdata,
+ struct xgbe_packet_data *packet,
+ unsigned int len)
+{
+ /* Always the full buffer if not the last descriptor */
+ if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, LAST))
+ return rdata->rx.buf.dma_len;
+
+ /* Last descriptor so calculate how much of the buffer was used
+ * for the last bit of data
+ */
+ return rdata->rx.len - len;
+}
+
static int xgbe_tx_poll(struct xgbe_channel *channel)
{
struct xgbe_prv_data *pdata = channel->pdata;
@@ -1873,8 +1891,8 @@
struct napi_struct *napi;
struct sk_buff *skb;
struct skb_shared_hwtstamps *hwtstamps;
- unsigned int incomplete, error, context_next, context;
- unsigned int len, rdesc_len, max_len;
+ unsigned int last, error, context_next, context;
+ unsigned int len, buf1_len, buf2_len, max_len;
unsigned int received = 0;
int packet_count = 0;
@@ -1884,7 +1902,7 @@
if (!ring)
return 0;
- incomplete = 0;
+ last = 0;
context_next = 0;
napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi;
@@ -1918,9 +1936,8 @@
received++;
ring->cur++;
- incomplete = XGMAC_GET_BITS(packet->attributes,
- RX_PACKET_ATTRIBUTES,
- INCOMPLETE);
+ last = XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+ LAST);
context_next = XGMAC_GET_BITS(packet->attributes,
RX_PACKET_ATTRIBUTES,
CONTEXT_NEXT);
@@ -1929,7 +1946,7 @@
CONTEXT);
/* Earlier error, just drain the remaining data */
- if ((incomplete || context_next) && error)
+ if ((!last || context_next) && error)
goto read_again;
if (error || packet->errors) {
@@ -1941,16 +1958,22 @@
}
if (!context) {
- /* Length is cumulative, get this descriptor's length */
- rdesc_len = rdata->rx.len - len;
- len += rdesc_len;
+ /* Get the data length in the descriptor buffers */
+ buf1_len = xgbe_rx_buf1_len(rdata, packet);
+ len += buf1_len;
+ buf2_len = xgbe_rx_buf2_len(rdata, packet, len);
+ len += buf2_len;
- if (rdesc_len && !skb) {
+ if (!skb) {
skb = xgbe_create_skb(pdata, napi, rdata,
- rdesc_len);
- if (!skb)
+ buf1_len);
+ if (!skb) {
error = 1;
- } else if (rdesc_len) {
+ goto skip_data;
+ }
+ }
+
+ if (buf2_len) {
dma_sync_single_range_for_cpu(pdata->dev,
rdata->rx.buf.dma_base,
rdata->rx.buf.dma_off,
@@ -1960,13 +1983,14 @@
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
rdata->rx.buf.pa.pages,
rdata->rx.buf.pa.pages_offset,
- rdesc_len,
+ buf2_len,
rdata->rx.buf.dma_len);
rdata->rx.buf.pa.pages = NULL;
}
}
- if (incomplete || context_next)
+skip_data:
+ if (!last || context_next)
goto read_again;
if (!skb)
@@ -2024,7 +2048,7 @@
}
/* Check if we need to save state before leaving */
- if (received && (incomplete || context_next)) {
+ if (received && (!last || context_next)) {
rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
rdata->state_saved = 1;
rdata->state.skb = skb;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index a4e60e5..0975af2 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3402,7 +3402,8 @@
bcmgenet_netif_stop(dev);
- phy_suspend(priv->phydev);
+ if (!device_may_wakeup(d))
+ phy_suspend(priv->phydev);
netif_device_detach(dev);
@@ -3499,7 +3500,8 @@
netif_device_attach(dev);
- phy_resume(priv->phydev);
+ if (!device_may_wakeup(d))
+ phy_resume(priv->phydev);
if (priv->eee.eee_enabled)
bcmgenet_eee_enable_set(dev, true);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index e876076..2f92819 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -220,20 +220,6 @@
udelay(60);
}
-static void bcmgenet_internal_phy_setup(struct net_device *dev)
-{
- struct bcmgenet_priv *priv = netdev_priv(dev);
- u32 reg;
-
- /* Power up PHY */
- bcmgenet_phy_power_set(dev, true);
- /* enable APD */
- reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
- reg |= EXT_PWR_DN_EN_LD;
- bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
- bcmgenet_mii_reset(dev);
-}
-
static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
{
u32 reg;
@@ -281,7 +267,6 @@
if (priv->internal_phy) {
phy_name = "internal PHY";
- bcmgenet_internal_phy_setup(dev);
} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
phy_name = "MoCA";
bcmgenet_moca_phy_setup(priv);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index bfe410e..3f51a44 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -367,6 +367,8 @@
case MLX5_CMD_OP_QUERY_VPORT_COUNTER:
case MLX5_CMD_OP_ALLOC_Q_COUNTER:
case MLX5_CMD_OP_QUERY_Q_COUNTER:
+ case MLX5_CMD_OP_SET_RATE_LIMIT:
+ case MLX5_CMD_OP_QUERY_RATE_LIMIT:
case MLX5_CMD_OP_ALLOC_PD:
case MLX5_CMD_OP_ALLOC_UAR:
case MLX5_CMD_OP_CONFIG_INT_MODERATION:
@@ -500,6 +502,8 @@
MLX5_COMMAND_STR_CASE(ALLOC_Q_COUNTER);
MLX5_COMMAND_STR_CASE(DEALLOC_Q_COUNTER);
MLX5_COMMAND_STR_CASE(QUERY_Q_COUNTER);
+ MLX5_COMMAND_STR_CASE(SET_RATE_LIMIT);
+ MLX5_COMMAND_STR_CASE(QUERY_RATE_LIMIT);
MLX5_COMMAND_STR_CASE(ALLOC_PD);
MLX5_COMMAND_STR_CASE(DEALLOC_PD);
MLX5_COMMAND_STR_CASE(ALLOC_UAR);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 796bdf0..7309ae3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -602,6 +602,10 @@
if (lro_num_seg > 1) {
mlx5e_lro_update_hdr(skb, cqe, cqe_bcnt);
skb_shinfo(skb)->gso_size = DIV_ROUND_UP(cqe_bcnt, lro_num_seg);
+ /* Subtract one since we already counted this as one
+ * "regular" packet in mlx5e_complete_rx_cqe()
+ */
+ rq->stats.packets += lro_num_seg - 1;
rq->stats.lro_packets++;
rq->stats.lro_bytes += cqe_bcnt;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index a543ea6..3fd471a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -427,14 +427,16 @@
}
if (is_tcf_vlan(a)) {
- if (tcf_vlan_action(a) == VLAN_F_POP) {
+ if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) {
attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
- } else if (tcf_vlan_action(a) == VLAN_F_PUSH) {
+ } else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) {
if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q))
return -EOPNOTSUPP;
attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
attr->vlan = tcf_vlan_push_vid(a);
+ } else { /* action is TCA_VLAN_ACT_MODIFY */
+ return -EOPNOTSUPP;
}
continue;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index cfb6837..5743110 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -272,15 +272,18 @@
sq->stats.tso_bytes += skb->len - ihs;
}
+ sq->stats.packets += skb_shinfo(skb)->gso_segs;
num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs;
} else {
bf = sq->bf_budget &&
!skb->xmit_more &&
!skb_shinfo(skb)->nr_frags;
ihs = mlx5e_get_inline_hdr_size(sq, skb, bf);
+ sq->stats.packets++;
num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
}
+ sq->stats.bytes += num_bytes;
wi->num_bytes = num_bytes;
if (skb_vlan_tag_present(skb)) {
@@ -377,8 +380,6 @@
if (bf)
sq->bf_budget--;
- sq->stats.packets++;
- sq->stats.bytes += num_bytes;
return NETDEV_TX_OK;
dma_unmap_wqe_err:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 0c9ef87..7a196a0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -87,7 +87,7 @@
[2] = {
.mask = MLX5_PROF_MASK_QP_SIZE |
MLX5_PROF_MASK_MR_CACHE,
- .log_max_qp = 17,
+ .log_max_qp = 18,
.mr_cache[0] = {
.size = 500,
.limit = 250
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 24d5272..0d519a9 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -924,6 +924,8 @@
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
+ {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */
+ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */
{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
{QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
{QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index bc744ac..a2afb8e 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -467,8 +467,10 @@
}
if (rt6_local) {
- if (rt6_local->rt6i_idev)
+ if (rt6_local->rt6i_idev) {
in6_dev_put(rt6_local->rt6i_idev);
+ rt6_local->rt6i_idev = NULL;
+ }
dst = &rt6_local->dst;
dev_put(dst->dev);
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 3c3c4f1..7a310c4 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2700,6 +2700,21 @@
schedule_work(&pcie_work);
}
+static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+ if (reg->sleep_cookie)
+ mwifiex_pcie_delete_sleep_cookie_buf(adapter);
+
+ mwifiex_pcie_delete_cmdrsp_buf(adapter);
+ mwifiex_pcie_delete_evtbd_ring(adapter);
+ mwifiex_pcie_delete_rxbd_ring(adapter);
+ mwifiex_pcie_delete_txbd_ring(adapter);
+ card->cmdrsp_buf = NULL;
+}
+
/*
* This function initializes the PCI-E host memory space, WCB rings, etc.
*
@@ -2812,13 +2827,6 @@
/*
* This function cleans up the allocated card buffers.
- *
- * The following are freed by this function -
- * - TXBD ring buffers
- * - RXBD ring buffers
- * - Event BD ring buffers
- * - Command response ring buffer
- * - Sleep cookie buffer
*/
static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
{
@@ -2834,6 +2842,8 @@
"Failed to write driver not-ready signature\n");
}
+ mwifiex_pcie_free_buffers(adapter);
+
if (pdev) {
pci_iounmap(pdev, card->pci_mmap);
pci_iounmap(pdev, card->pci_mmap1);
@@ -3080,10 +3090,7 @@
pci_iounmap(pdev, card->pci_mmap1);
}
-/* This function cleans up the PCI-E host memory space.
- * Some code is extracted from mwifiex_unregister_dev()
- *
- */
+/* This function cleans up the PCI-E host memory space. */
static void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
@@ -3095,16 +3102,8 @@
adapter->seq_num = 0;
adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
- if (card) {
- if (reg->sleep_cookie)
- mwifiex_pcie_delete_sleep_cookie_buf(adapter);
-
- mwifiex_pcie_delete_cmdrsp_buf(adapter);
- mwifiex_pcie_delete_evtbd_ring(adapter);
- mwifiex_pcie_delete_rxbd_ring(adapter);
- mwifiex_pcie_delete_txbd_ring(adapter);
- card->cmdrsp_buf = NULL;
- }
+ if (card)
+ mwifiex_pcie_free_buffers(adapter);
return;
}
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 3308427..4399de34 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -939,8 +939,10 @@
* pardevice fields. -arca
*/
port->ops->init_state(par_dev, par_dev->state);
- port->proc_device = par_dev;
- parport_device_proc_register(par_dev);
+ if (!test_and_set_bit(PARPORT_DEVPROC_REGISTERED, &port->devflags)) {
+ port->proc_device = par_dev;
+ parport_device_proc_register(par_dev);
+ }
return par_dev;
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 522c724..ba6d5ce 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -146,4 +146,11 @@
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
WCD gpio controller block.
+config PINCTRL_LPI
+ tristate "Qualcomm Technologies, Inc LPI pin controller driver"
+ depends on GPIOLIB && OF
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ LPI gpio controller block.
+
endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 7c74288..5e05e897 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -18,3 +18,4 @@
obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_SDM830) += pinctrl-sdm830.o
obj-$(CONFIG_PINCTRL_WCD) += pinctrl-wcd.o
+obj-$(CONFIG_PINCTRL_LPI) += pinctrl-lpi.o
diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c
new file mode 100644
index 0000000..009e27bf
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-lpi.c
@@ -0,0 +1,638 @@
+/*
+ * 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/gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define LPI_ADDRESS_SIZE 0xC000
+
+#define LPI_GPIO_REG_VAL_CTL 0x00
+#define LPI_GPIO_REG_DIR_CTL 0x04
+
+#define LPI_GPIO_REG_PULL_SHIFT 0x0
+#define LPI_GPIO_REG_PULL_MASK 0x3
+
+#define LPI_GPIO_REG_FUNCTION_SHIFT 0x2
+#define LPI_GPIO_REG_FUNCTION_MASK 0x3C
+
+#define LPI_GPIO_REG_OUT_STRENGTH_SHIFT 0x6
+#define LPI_GPIO_REG_OUT_STRENGTH_MASK 0x1C0
+
+#define LPI_GPIO_REG_OE_SHIFT 0x9
+#define LPI_GPIO_REG_OE_MASK 0x200
+
+#define LPI_GPIO_REG_DIR_SHIFT 0x1
+#define LPI_GPIO_REG_DIR_MASK 0x2
+
+#define LPI_GPIO_BIAS_DISABLE 0x0
+#define LPI_GPIO_PULL_DOWN 0x1
+#define LPI_GPIO_KEEPER 0x2
+#define LPI_GPIO_PULL_UP 0x3
+
+#define LPI_GPIO_FUNC_GPIO "gpio"
+#define LPI_GPIO_FUNC_FUNC1 "func1"
+#define LPI_GPIO_FUNC_FUNC2 "func2"
+#define LPI_GPIO_FUNC_FUNC3 "func3"
+#define LPI_GPIO_FUNC_FUNC4 "func4"
+#define LPI_GPIO_FUNC_FUNC5 "func5"
+
+static bool lpi_dev_up;
+
+/* The index of each function in lpi_gpio_functions[] array */
+enum lpi_gpio_func_index {
+ LPI_GPIO_FUNC_INDEX_GPIO = 0x00,
+ LPI_GPIO_FUNC_INDEX_FUNC1 = 0x01,
+ LPI_GPIO_FUNC_INDEX_FUNC2 = 0x02,
+ LPI_GPIO_FUNC_INDEX_FUNC3 = 0x03,
+ LPI_GPIO_FUNC_INDEX_FUNC4 = 0x04,
+ LPI_GPIO_FUNC_INDEX_FUNC5 = 0x05,
+};
+
+/**
+ * struct lpi_gpio_pad - keep current GPIO settings
+ * @offset: Nth GPIO in supported GPIOs.
+ * @output_enabled: Set to true if GPIO output logic is enabled.
+ * @value: value of a pin
+ * @base: Address base of LPI GPIO PAD.
+ * @pullup: Constant current which flow through GPIO output buffer.
+ * @strength: No, Low, Medium, High
+ * @function: See lpi_gpio_functions[]
+ */
+struct lpi_gpio_pad {
+ u16 offset;
+ bool output_enabled;
+ bool value;
+ char __iomem *base;
+ unsigned int pullup;
+ unsigned int strength;
+ unsigned int function;
+};
+
+struct lpi_gpio_state {
+ struct device *dev;
+ struct pinctrl_dev *ctrl;
+ struct gpio_chip chip;
+ char __iomem *base;
+};
+
+static const char *const lpi_gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31",
+};
+
+static const u32 lpi_offset[] = {
+ 0x00000000,
+ 0x00001000,
+ 0x00002000,
+ 0x00002010,
+ 0x00003000,
+ 0x00003010,
+ 0x00004000,
+ 0x00004010,
+ 0x00005000,
+ 0x00005010,
+ 0x00005020,
+ 0x00005030,
+ 0x00005040,
+ 0x00005050,
+ 0x00006000,
+ 0x00006010,
+ 0x00007000,
+ 0x00007010,
+ 0x00008000,
+ 0x00008010,
+ 0x00008020,
+ 0x00008030,
+ 0x00008040,
+ 0x00008050,
+ 0x00008060,
+ 0x00008070,
+ 0x00009000,
+ 0x00009010,
+ 0x0000A000,
+ 0x0000A010,
+ 0x0000B000,
+ 0x0000B010,
+};
+
+static const char *const lpi_gpio_functions[] = {
+ [LPI_GPIO_FUNC_INDEX_GPIO] = LPI_GPIO_FUNC_GPIO,
+ [LPI_GPIO_FUNC_INDEX_FUNC1] = LPI_GPIO_FUNC_FUNC1,
+ [LPI_GPIO_FUNC_INDEX_FUNC2] = LPI_GPIO_FUNC_FUNC2,
+ [LPI_GPIO_FUNC_INDEX_FUNC3] = LPI_GPIO_FUNC_FUNC3,
+ [LPI_GPIO_FUNC_INDEX_FUNC4] = LPI_GPIO_FUNC_FUNC4,
+ [LPI_GPIO_FUNC_INDEX_FUNC5] = LPI_GPIO_FUNC_FUNC5,
+};
+
+static int lpi_gpio_read(struct lpi_gpio_pad *pad, unsigned int addr)
+{
+ int ret;
+
+ if (!lpi_dev_up) {
+ pr_err_ratelimited("%s: ADSP is down due to SSR, return\n",
+ __func__);
+ return 0;
+ }
+
+ ret = ioread32(pad->base + pad->offset + addr);
+ if (ret < 0)
+ pr_err("%s: read 0x%x failed\n", __func__, addr);
+
+ return ret;
+}
+
+static int lpi_gpio_write(struct lpi_gpio_pad *pad, unsigned int addr,
+ unsigned int val)
+{
+ if (!lpi_dev_up) {
+ pr_err_ratelimited("%s: ADSP is down due to SSR, return\n",
+ __func__);
+ return 0;
+ }
+
+ iowrite32(val, pad->base + pad->offset + addr);
+ return 0;
+}
+
+static int lpi_gpio_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ /* Every PIN is a group */
+ return pctldev->desc->npins;
+}
+
+static const char *lpi_gpio_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int pin)
+{
+ return pctldev->desc->pins[pin].name;
+}
+
+static int lpi_gpio_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ *pins = &pctldev->desc->pins[pin].number;
+ *num_pins = 1;
+ return 0;
+}
+
+static const struct pinctrl_ops lpi_gpio_pinctrl_ops = {
+ .get_groups_count = lpi_gpio_get_groups_count,
+ .get_group_name = lpi_gpio_get_group_name,
+ .get_group_pins = lpi_gpio_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int lpi_gpio_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(lpi_gpio_functions);
+}
+
+static const char *lpi_gpio_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int function)
+{
+ return lpi_gpio_functions[function];
+}
+
+static int lpi_gpio_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned int function,
+ const char *const **groups,
+ unsigned *const num_qgroups)
+{
+ *groups = lpi_gpio_groups;
+ *num_qgroups = pctldev->desc->npins;
+ return 0;
+}
+
+static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
+ unsigned int pin)
+{
+ struct lpi_gpio_pad *pad;
+ unsigned int val;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ pad->function = function;
+
+ val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
+ val &= ~(LPI_GPIO_REG_FUNCTION_MASK);
+ val |= pad->function << LPI_GPIO_REG_FUNCTION_SHIFT;
+ lpi_gpio_write(pad, LPI_GPIO_REG_VAL_CTL, val);
+ return 0;
+}
+
+static const struct pinmux_ops lpi_gpio_pinmux_ops = {
+ .get_functions_count = lpi_gpio_get_functions_count,
+ .get_function_name = lpi_gpio_get_function_name,
+ .get_function_groups = lpi_gpio_get_function_groups,
+ .set_mux = lpi_gpio_set_mux,
+};
+
+static int lpi_config_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ unsigned int param = pinconf_to_config_param(*config);
+ struct lpi_gpio_pad *pad;
+ unsigned int arg;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ arg = pad->pullup = LPI_GPIO_BIAS_DISABLE;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ arg = pad->pullup == LPI_GPIO_PULL_DOWN;
+ break;
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ arg = pad->pullup = LPI_GPIO_KEEPER;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ arg = pad->pullup == LPI_GPIO_PULL_UP;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ case PIN_CONFIG_OUTPUT:
+ arg = pad->output_enabled;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return 0;
+}
+
+static unsigned int lpi_drive_to_regval(u32 arg)
+{
+ return (arg/2 - 1);
+}
+
+static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int nconfs)
+{
+ struct lpi_gpio_pad *pad;
+ unsigned int param, arg;
+ int i, ret = 0, val;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ for (i = 0; i < nconfs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ dev_dbg(pctldev->dev, "%s: param: %d arg: %d pin: %d\n",
+ __func__, param, arg, pin);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ pad->pullup = LPI_GPIO_BIAS_DISABLE;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ pad->pullup = LPI_GPIO_PULL_DOWN;
+ break;
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ pad->pullup = LPI_GPIO_KEEPER;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ pad->pullup = LPI_GPIO_PULL_UP;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ pad->output_enabled = false;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ pad->output_enabled = true;
+ pad->value = arg;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ pad->strength = arg;
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
+ val &= ~(LPI_GPIO_REG_PULL_MASK | LPI_GPIO_REG_OUT_STRENGTH_MASK |
+ LPI_GPIO_REG_OE_MASK);
+ val |= pad->pullup << LPI_GPIO_REG_PULL_SHIFT;
+ val |= lpi_drive_to_regval(pad->strength) <<
+ LPI_GPIO_REG_OUT_STRENGTH_SHIFT;
+ if (pad->output_enabled)
+ val |= pad->value << LPI_GPIO_REG_OE_SHIFT;
+
+ lpi_gpio_write(pad, LPI_GPIO_REG_VAL_CTL, val);
+ lpi_gpio_write(pad, LPI_GPIO_REG_DIR_CTL,
+ pad->output_enabled << LPI_GPIO_REG_DIR_SHIFT);
+done:
+ return ret;
+}
+
+static const struct pinconf_ops lpi_gpio_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_group_get = lpi_config_get,
+ .pin_config_group_set = lpi_config_set,
+};
+
+static int lpi_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
+{
+ struct lpi_gpio_state *state = gpiochip_get_data(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
+
+ return lpi_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int lpi_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int pin, int val)
+{
+ struct lpi_gpio_state *state = gpiochip_get_data(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
+
+ return lpi_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int lpi_gpio_get(struct gpio_chip *chip, unsigned int pin)
+{
+ struct lpi_gpio_state *state = gpiochip_get_data(chip);
+ struct lpi_gpio_pad *pad;
+ int value;
+
+ pad = state->ctrl->desc->pins[pin].drv_data;
+
+ value = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
+ return value;
+}
+
+static void lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
+{
+ struct lpi_gpio_state *state = gpiochip_get_data(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
+
+ lpi_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int lpi_notifier_service_cb(struct notifier_block *this,
+ unsigned long opcode, void *ptr)
+{
+ pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
+
+ switch (opcode) {
+ case AUDIO_NOTIFIER_SERVICE_DOWN:
+ lpi_dev_up = false;
+ break;
+ case AUDIO_NOTIFIER_SERVICE_UP:
+ lpi_dev_up = true;
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block service_nb = {
+ .notifier_call = lpi_notifier_service_cb,
+ .priority = -INT_MAX,
+};
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static unsigned int lpi_regval_to_drive(u32 val)
+{
+ return (val + 1) * 2;
+}
+
+static void lpi_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev,
+ struct gpio_chip *chip,
+ unsigned int offset,
+ unsigned int gpio)
+{
+ struct pinctrl_pin_desc pindesc;
+ struct lpi_gpio_pad *pad;
+ unsigned int func;
+ int is_out;
+ int drive;
+ int pull;
+ u32 ctl_reg;
+
+ static const char * const pulls[] = {
+ "no pull",
+ "pull down",
+ "keeper",
+ "pull up"
+ };
+
+ pindesc = pctldev->desc->pins[offset];
+ pad = pctldev->desc->pins[offset].drv_data;
+ ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_DIR_CTL);
+ is_out = (ctl_reg & LPI_GPIO_REG_DIR_MASK) >> LPI_GPIO_REG_DIR_SHIFT;
+ ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
+
+ func = (ctl_reg & LPI_GPIO_REG_FUNCTION_MASK) >>
+ LPI_GPIO_REG_FUNCTION_SHIFT;
+ drive = (ctl_reg & LPI_GPIO_REG_OUT_STRENGTH_MASK) >>
+ LPI_GPIO_REG_OUT_STRENGTH_SHIFT;
+ pull = (ctl_reg & LPI_GPIO_REG_PULL_MASK) >> LPI_GPIO_REG_PULL_SHIFT;
+
+ seq_printf(s, " %-8s: %-3s %d",
+ pindesc.name, is_out ? "out" : "in", func);
+ seq_printf(s, " %dmA", lpi_regval_to_drive(drive));
+ seq_printf(s, " %s", pulls[pull]);
+}
+
+static void lpi_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ unsigned int gpio = chip->base;
+ unsigned int i;
+
+ for (i = 0; i < chip->ngpio; i++, gpio++) {
+ lpi_gpio_dbg_show_one(s, NULL, chip, i, gpio);
+ seq_puts(s, "\n");
+ }
+}
+
+#else
+#define lpi_gpio_dbg_show NULL
+#endif
+
+static const struct gpio_chip lpi_gpio_template = {
+ .direction_input = lpi_gpio_direction_input,
+ .direction_output = lpi_gpio_direction_output,
+ .get = lpi_gpio_get,
+ .set = lpi_gpio_set,
+ .request = gpiochip_generic_request,
+ .free = gpiochip_generic_free,
+ .dbg_show = lpi_gpio_dbg_show,
+};
+
+static int lpi_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pinctrl_pin_desc *pindesc;
+ struct pinctrl_desc *pctrldesc;
+ struct lpi_gpio_pad *pad, *pads;
+ struct lpi_gpio_state *state;
+ int ret, npins, i;
+ char __iomem *lpi_base;
+ u32 reg;
+
+ ret = of_property_read_u32(dev->of_node, "reg", ®);
+ if (ret < 0) {
+ dev_err(dev, "missing base address\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "qcom,num-gpios", &npins);
+ if (ret < 0)
+ return ret;
+
+ WARN_ON(npins > ARRAY_SIZE(lpi_gpio_groups));
+
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, state);
+
+ state->dev = &pdev->dev;
+
+ pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
+ if (!pindesc)
+ return -ENOMEM;
+
+ pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
+ if (!pads)
+ return -ENOMEM;
+
+ pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
+ if (!pctrldesc)
+ return -ENOMEM;
+
+ pctrldesc->pctlops = &lpi_gpio_pinctrl_ops;
+ pctrldesc->pmxops = &lpi_gpio_pinmux_ops;
+ pctrldesc->confops = &lpi_gpio_pinconf_ops;
+ pctrldesc->owner = THIS_MODULE;
+ pctrldesc->name = dev_name(dev);
+ pctrldesc->pins = pindesc;
+ pctrldesc->npins = npins;
+
+ lpi_base = devm_ioremap(dev, reg, LPI_ADDRESS_SIZE);
+ if (lpi_base == NULL) {
+ dev_err(dev, "%s devm_ioremap failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ state->base = lpi_base;
+
+ for (i = 0; i < npins; i++, pindesc++) {
+ pad = &pads[i];
+ pindesc->drv_data = pad;
+ pindesc->number = i;
+ pindesc->name = lpi_gpio_groups[i];
+
+ pad->base = lpi_base;
+ pad->offset = lpi_offset[i];
+ }
+
+ state->chip = lpi_gpio_template;
+ state->chip.parent = dev;
+ state->chip.base = -1;
+ state->chip.ngpio = npins;
+ state->chip.label = dev_name(dev);
+ state->chip.of_gpio_n_cells = 2;
+ state->chip.can_sleep = false;
+
+ state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
+ if (IS_ERR(state->ctrl))
+ return PTR_ERR(state->ctrl);
+
+ ret = gpiochip_add_data(&state->chip, state);
+ if (ret) {
+ dev_err(state->dev, "can't add gpio chip\n");
+ goto err_chip;
+ }
+
+ ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
+ if (ret) {
+ dev_err(dev, "failed to add pin range\n");
+ goto err_range;
+ }
+
+ lpi_dev_up = true;
+ ret = audio_notifier_register("lpi_tlmm", AUDIO_NOTIFIER_ADSP_DOMAIN,
+ &service_nb);
+ if (ret < 0) {
+ pr_err("%s: Audio notifier register failed ret = %d\n",
+ __func__, ret);
+ goto err_range;
+ }
+
+ return 0;
+
+err_range:
+ gpiochip_remove(&state->chip);
+err_chip:
+ return ret;
+}
+
+static int lpi_pinctrl_remove(struct platform_device *pdev)
+{
+ struct lpi_gpio_state *state = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&state->chip);
+ return 0;
+}
+
+static const struct of_device_id lpi_pinctrl_of_match[] = {
+ { .compatible = "qcom,lpi-pinctrl" }, /* Generic */
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match);
+
+static struct platform_driver lpi_pinctrl_driver = {
+ .driver = {
+ .name = "qcom-lpi-pinctrl",
+ .of_match_table = lpi_pinctrl_of_match,
+ },
+ .probe = lpi_pinctrl_probe,
+ .remove = lpi_pinctrl_remove,
+};
+
+module_platform_driver(lpi_pinctrl_driver);
+
+MODULE_DESCRIPTION("QTI LPI GPIO pin control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index f9d483b..2a1367e 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -597,10 +597,6 @@
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_status_reg);
- val &= ~BIT(g->intr_status_bit);
- writel(val, pctrl->regs + g->intr_status_reg);
-
val = readl(pctrl->regs + g->intr_cfg_reg);
val |= BIT(g->intr_enable_bit);
writel(val, pctrl->regs + g->intr_cfg_reg);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 757541b..6cfe25d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -335,12 +335,13 @@
[IPA_3_0][IPA_CLIENT_APPS_LAN_PROD] = {
14, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
- QMB_MASTER_SELECT_DDR},
+ QMB_MASTER_SELECT_DDR,
+ { 14, 11, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_APPS_WAN_PROD] = {
3, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
- { 14, 11, 8, 16, IPA_EE_AP } },
+ { 3, 5, 16, 32, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_APPS_CMD_PROD] = {
22, IPA_v3_0_GROUP_IMM_CMD, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
@@ -568,8 +569,8 @@
[IPA_3_5][IPA_CLIENT_A2_EMBEDDED_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_A2_TETHERED_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_APPS_LAN_PROD] = {
- 8, IPA_v3_5_GROUP_UL_DL, true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ 8, IPA_v3_5_GROUP_UL_DL, false,
+ IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 8, 9, 8, 16, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_APPS_WAN_PROD] = {
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 40a539e..7179fe0 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -17,7 +17,6 @@
#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>
@@ -33,16 +32,10 @@
#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;
@@ -51,7 +44,6 @@
};
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] = {
{
@@ -67,43 +59,36 @@
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)
+static struct apr_tx_buf *apr_alloc_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);
+ return kzalloc(sizeof(struct apr_tx_buf), GFP_ATOMIC);
+}
+
+static void apr_free_buf(const void *ptr)
+{
+
+ struct apr_pkt_priv *apr_pkt_priv = (struct apr_pkt_priv *)ptr;
+ struct apr_tx_buf *tx_buf;
+
+ if (!apr_pkt_priv) {
+ pr_err("%s: Invalid apr_pkt_priv\n", __func__);
+ return;
}
- 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;
+ if (apr_pkt_priv->pkt_owner == APR_PKT_OWNER_DRIVER) {
+ tx_buf = container_of((void *)apr_pkt_priv,
+ struct apr_tx_buf, pkt_priv);
+ pr_debug("%s: Freeing buffer %pK", __func__, tx_buf);
+ kfree(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)
@@ -129,14 +114,14 @@
{
int rc = 0, retries = 0;
void *pkt_data = NULL;
- struct apr_tx_buf *tx_buf;
+ struct apr_tx_buf *tx_buf = NULL;
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);
+ tx_buf = apr_alloc_buf(len);
if (IS_ERR_OR_NULL(tx_buf)) {
rc = -EINVAL;
goto exit;
@@ -159,7 +144,7 @@
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);
+ kfree(tx_buf);
}
exit:
return rc;
@@ -188,39 +173,17 @@
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);
- }
+ pr_debug("%s: tx_abort received for pkt_priv:%pK\n",
+ __func__, pkt_priv);
+ apr_free_buf(pkt_priv);
}
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);
+ pr_debug("%s: tx_done received for pkt_priv:%pK\n",
+ __func__, pkt_priv);
+ apr_free_buf(pkt_priv);
}
bool apr_tal_notify_rx_intent_req(void *handle, const void *priv,
@@ -456,8 +419,6 @@
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++) {
@@ -473,21 +434,6 @@
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);
@@ -501,13 +447,5 @@
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/service-locator.c b/drivers/soc/qcom/service-locator.c
index 8e9ad9b..b40d678 100644
--- a/drivers/soc/qcom/service-locator.c
+++ b/drivers/soc/qcom/service-locator.c
@@ -378,6 +378,7 @@
if (!pqw) {
rc = -ENOMEM;
pr_err("Allocation failed\n");
+ kfree(pqcd);
goto err;
}
pqw->notifier = locator_nb;
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
index 758f627..034ddd3 100644
--- a/drivers/soc/qcom/wcd-dsp-glink.c
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -25,8 +25,10 @@
#include "sound/wcd-dsp-glink.h"
#define WDSP_GLINK_DRIVER_NAME "wcd-dsp-glink"
-#define WDSP_MAX_WRITE_SIZE (512 * 1024)
+#define WDSP_MAX_WRITE_SIZE (256 * 1024)
#define WDSP_MAX_READ_SIZE (4 * 1024)
+#define WDSP_MAX_NO_OF_INTENTS (20)
+#define WDSP_MAX_NO_OF_CHANNELS (10)
#define MINOR_NUMBER_COUNT 1
#define WDSP_EDGE "wdsp"
@@ -532,15 +534,30 @@
payload = (u8 *)pkt->payload;
no_of_channels = pkt->no_of_channels;
+ if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
+ dev_info(wpriv->dev, "%s: no_of_channels = %d are limited to %d\n",
+ __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
+ no_of_channels = WDSP_MAX_NO_OF_CHANNELS;
+ }
ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *),
GFP_KERNEL);
if (!ch) {
ret = -ENOMEM;
goto done;
}
+ wpriv->ch = ch;
+ wpriv->no_of_channels = no_of_channels;
for (i = 0; i < no_of_channels; i++) {
ch_cfg = (struct wdsp_glink_ch_cfg *)payload;
+
+ if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
+ dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
+ __func__, ch_cfg->no_of_intents);
+ ret = -EINVAL;
+ goto err_ch_mem;
+ }
+
ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) +
(sizeof(u32) * ch_cfg->no_of_intents);
ch_size = sizeof(struct wdsp_glink_ch) +
@@ -564,8 +581,6 @@
INIT_WORK(&ch[i]->lcl_ch_cls_wrk, wdsp_glink_lcl_ch_cls_wrk);
init_waitqueue_head(&ch[i]->ch_connect_wait);
}
- wpriv->ch = ch;
- wpriv->no_of_channels = no_of_channels;
INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk);
@@ -746,15 +761,17 @@
goto done;
}
- dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count);
-
- if (count > WDSP_MAX_WRITE_SIZE) {
- dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_WRITE_SIZE\n",
+ if ((count < sizeof(struct wdsp_write_pkt)) ||
+ (count > WDSP_MAX_WRITE_SIZE)) {
+ dev_err(wpriv->dev, "%s: Invalid count = %zd\n",
__func__, count);
- count = WDSP_MAX_WRITE_SIZE;
+ ret = -EINVAL;
+ goto done;
}
- tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf);
+ dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count);
+
+ tx_buf_size = WDSP_MAX_WRITE_SIZE + sizeof(struct wdsp_glink_tx_buf);
tx_buf = kzalloc(tx_buf_size, GFP_KERNEL);
if (!tx_buf) {
ret = -ENOMEM;
@@ -772,6 +789,13 @@
wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
switch (wpkt->pkt_type) {
case WDSP_REG_PKT:
+ if (count <= (sizeof(struct wdsp_write_pkt) +
+ sizeof(struct wdsp_reg_pkt))) {
+ dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
+ __func__, count);
+ ret = -EINVAL;
+ goto free_buf;
+ }
ret = wdsp_glink_ch_info_init(wpriv,
(struct wdsp_reg_pkt *)wpkt->payload);
if (ret < 0)
@@ -794,6 +818,13 @@
kfree(tx_buf);
break;
case WDSP_CMD_PKT:
+ if (count <= (sizeof(struct wdsp_write_pkt) +
+ sizeof(struct wdsp_cmd_pkt))) {
+ dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
+ __func__, count);
+ ret = -EINVAL;
+ goto free_buf;
+ }
mutex_lock(&wpriv->glink_mutex);
if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
mutex_unlock(&wpriv->glink_mutex);
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index ea886c7..7e33e8b 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -64,6 +64,8 @@
{6, 10, 7800}, /* UC15: 2*(Spkr + SB + VI) */
{2, 3, 3600}, /* UC16: Spkr + VI */
{4, 6, 7200}, /* UC17: 2*(Spkr + VI) */
+ {3, 7, 4200}, /* UC18: Spkr + Comp + VI */
+ {6, 14, 8400}, /* UC19: 2*(Spkr + Comp + VI) */
};
#define MAX_USECASE ARRAY_SIZE(uc)
@@ -178,6 +180,21 @@
{7, 6, 0},
{15, 10, 0},
},
+ /* UC 18 */
+ {
+ {7, 1, 0},
+ {31, 2, 0},
+ {15, 7, 0},
+ },
+ /* UC 19 */
+ {
+ {7, 1, 0},
+ {31, 2, 0},
+ {15, 7, 0},
+ {7, 6, 0},
+ {31, 18, 0},
+ {15, 10, 0},
+ },
};
enum {
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2fda339..2a4000d 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -454,6 +454,16 @@
the sensor. Also able to set threshold temperature for both hot and cold
and update when a threshold is reached.
+config THERMAL_TSENS
+ tristate "Qualcomm Technologies Inc. TSENS Temperature driver"
+ depends on THERMAL
+ help
+ This enables the thermal sysfs driver for the TSENS device. It shows
+ up in Sysfs as a thermal zone with multiple trip points. Also able
+ to set threshold temperature for both warm and cool and update
+ thermal userspace client when a threshold is reached. Warm/Cool
+ temperature thresholds can be set independently for each sensor.
+
menu "Qualcomm thermal drivers"
depends on (ARCH_QCOM && OF) || COMPILE_TEST
source "drivers/thermal/qcom/Kconfig"
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index d9489a7..e12c199 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -57,3 +57,4 @@
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
obj-$(CONFIG_THERMAL_QPNP_ADC_TM) += qpnp-adc-tm.o
+obj-$(CONFIG_THERMAL_TSENS) += msm-tsens.o tsens2xxx.o tsens-dbg.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 9ce0e9e..5556b5b 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -30,6 +30,8 @@
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/cpu_cooling.h>
+#include <linux/sched.h>
+#include <linux/of_device.h>
#include <trace/events/thermal.h>
@@ -45,6 +47,7 @@
* level 0 --> 1st Max Freq
* level 1 --> 2nd Max Freq
* ...
+ * leven n --> core isolated
*/
/**
@@ -70,8 +73,8 @@
* cooling devices.
* @clipped_freq: integer value representing the absolute value of the clipped
* frequency.
- * @max_level: maximum cooling level. One less than total number of valid
- * cpufreq frequencies.
+ * @max_level: maximum cooling level. [0..max_level-1: <freq>
+ * max_level: Core unavailable]
* @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
* @node: list_head to link all cpufreq_cooling_device together.
* @last_load: load measured by the latest call to cpufreq_get_requested_power()
@@ -103,6 +106,7 @@
int dyn_power_table_entries;
struct device *cpu_dev;
get_static_t plat_get_static_power;
+ struct cpu_cooling_ops *plat_ops;
};
static DEFINE_IDR(cpufreq_idr);
static DEFINE_MUTEX(cooling_cpufreq_lock);
@@ -162,7 +166,7 @@
{
unsigned long level;
- for (level = 0; level <= cpufreq_dev->max_level; level++) {
+ for (level = 0; level < cpufreq_dev->max_level; level++) {
if (freq == cpufreq_dev->freq_table[level])
return level;
@@ -535,11 +539,27 @@
if (cpufreq_device->cpufreq_state == state)
return 0;
+ /* If state is the last, isolate the CPU */
+ if (state == cpufreq_device->max_level)
+ return sched_isolate_cpu(cpu);
+ else if (state < cpufreq_device->max_level)
+ sched_unisolate_cpu(cpu);
+
clip_freq = cpufreq_device->freq_table[state];
cpufreq_device->cpufreq_state = state;
cpufreq_device->clipped_freq = clip_freq;
- cpufreq_update_policy(cpu);
+ /* Check if the device has a platform mitigation function that
+ * can handle the CPU freq mitigation, if not, notify cpufreq
+ * framework.
+ */
+ if (cpufreq_device->plat_ops) {
+ if (cpufreq_device->plat_ops->ceil_limit)
+ cpufreq_device->plat_ops->ceil_limit(cpu,
+ clip_freq);
+ } else {
+ cpufreq_update_policy(cpu);
+ }
return 0;
}
@@ -783,6 +803,9 @@
* @capacitance: dynamic power coefficient for these cpus
* @plat_static_func: function to calculate the static power consumed by these
* cpus (optional)
+ * @plat_mitig_func: function that does the mitigation by changing the
+ * frequencies (Optional). By default, cpufreq framweork will
+ * be notified of the new limits.
*
* This interface function registers the cpufreq cooling device with the name
* "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
@@ -795,7 +818,8 @@
static struct thermal_cooling_device *
__cpufreq_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus, u32 capacitance,
- get_static_t plat_static_func)
+ get_static_t plat_static_func,
+ struct cpu_cooling_ops *plat_ops)
{
struct cpufreq_policy *policy;
struct thermal_cooling_device *cool_dev;
@@ -848,7 +872,9 @@
cpufreq_for_each_valid_entry(pos, table)
cpufreq_dev->max_level++;
- cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) *
+ /* Last level will indicate the core will be isolated. */
+ cpufreq_dev->max_level++;
+ cpufreq_dev->freq_table = kzalloc(sizeof(*cpufreq_dev->freq_table) *
cpufreq_dev->max_level, GFP_KERNEL);
if (!cpufreq_dev->freq_table) {
cool_dev = ERR_PTR(-ENOMEM);
@@ -874,6 +900,8 @@
cooling_ops = &cpufreq_cooling_ops;
}
+ cpufreq_dev->plat_ops = plat_ops;
+
ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
if (ret) {
cool_dev = ERR_PTR(ret);
@@ -881,7 +909,7 @@
}
/* Fill freq-table in descending order of frequencies */
- for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
+ for (i = 0, freq = -1; i < cpufreq_dev->max_level; i++) {
freq = find_next_max(table, freq);
cpufreq_dev->freq_table[i] = freq;
@@ -949,7 +977,7 @@
struct thermal_cooling_device *
cpufreq_cooling_register(const struct cpumask *clip_cpus)
{
- return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL);
+ return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL, NULL);
}
EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
@@ -973,7 +1001,7 @@
if (!np)
return ERR_PTR(-EINVAL);
- return __cpufreq_cooling_register(np, clip_cpus, 0, NULL);
+ return __cpufreq_cooling_register(np, clip_cpus, 0, NULL, NULL);
}
EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
@@ -1003,11 +1031,34 @@
get_static_t plat_static_func)
{
return __cpufreq_cooling_register(NULL, clip_cpus, capacitance,
- plat_static_func);
+ plat_static_func, NULL);
}
EXPORT_SYMBOL(cpufreq_power_cooling_register);
/**
+ * cpufreq_platform_cooling_register() - create cpufreq cooling device with
+ * additional platform specific mitigation function.
+ *
+ * @clip_cpus: cpumask of cpus where the frequency constraints will happen
+ * @plat_ops: the platform mitigation functions that will be called insted of
+ * cpufreq, if provided.
+ *
+ * Return: a valid struct thermal_cooling_device pointer on success,
+ * on failure, it returns a corresponding ERR_PTR().
+ */
+struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+ struct cpu_cooling_ops *plat_ops)
+{
+ struct device_node *cpu_node;
+
+ cpu_node = of_cpu_device_node_get(cpumask_first(clip_cpus));
+ return __cpufreq_cooling_register(cpu_node, clip_cpus, 0, NULL,
+ plat_ops);
+}
+EXPORT_SYMBOL(cpufreq_platform_cooling_register);
+
+/**
* of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
* @np: a valid struct device_node to the cooling device device tree node
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
@@ -1040,7 +1091,7 @@
return ERR_PTR(-EINVAL);
return __cpufreq_cooling_register(np, clip_cpus, capacitance,
- plat_static_func);
+ plat_static_func, NULL);
}
EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
new file mode 100644
index 0000000..5b4bb7a
--- /dev/null
+++ b/drivers/thermal/msm-tsens.c
@@ -0,0 +1,288 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the term_tm 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/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+#include "tsens.h"
+
+LIST_HEAD(tsens_device_list);
+
+static int tsens_get_temp(struct tsens_sensor *s, int *temp)
+{
+ struct tsens_device *tmdev = s->tmdev;
+
+ return tmdev->ops->get_temp(s, temp);
+}
+
+static int tsens_set_trip_temp(struct tsens_sensor *s, int trip, int temp)
+{
+ struct tsens_device *tmdev = s->tmdev;
+
+ if (tmdev->ops->set_trip_temp)
+ return tmdev->ops->set_trip_temp(s, trip, temp);
+
+ return 0;
+}
+
+static int tsens_init(struct tsens_device *tmdev)
+{
+ if (tmdev->ops->hw_init)
+ return tmdev->ops->hw_init(tmdev);
+
+ return 0;
+}
+
+static int tsens_register_interrupts(struct tsens_device *tmdev)
+{
+ if (tmdev->ops->interrupts_reg)
+ return tmdev->ops->interrupts_reg(tmdev);
+
+ return 0;
+}
+
+static const struct of_device_id tsens_table[] = {
+ { .compatible = "qcom,msm8996-tsens",
+ .data = &data_tsens2xxx,
+ },
+ { .compatible = "qcom,msm8953-tsens",
+ .data = &data_tsens2xxx,
+ },
+ { .compatible = "qcom,msm8998-tsens",
+ .data = &data_tsens2xxx,
+ },
+ { .compatible = "qcom,msmhamster-tsens",
+ .data = &data_tsens2xxx,
+ },
+ { .compatible = "qcom,sdm660-tsens",
+ .data = &data_tsens23xx,
+ },
+ { .compatible = "qcom,sdm630-tsens",
+ .data = &data_tsens23xx,
+ },
+ { .compatible = "qcom,sdm845-tsens",
+ .data = &data_tsens24xx,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tsens_table);
+
+static struct thermal_zone_of_device_ops tsens_tm_thermal_zone_ops = {
+ .get_temp = tsens_get_temp,
+ .set_trip_temp = tsens_set_trip_temp,
+};
+
+static int get_device_tree_data(struct platform_device *pdev,
+ struct tsens_device *tmdev)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ u32 *hw_id, *client_id;
+ u32 rc = 0, i, tsens_num_sensors = 0;
+ int tsens_len;
+ const struct of_device_id *id;
+ const struct tsens_data *data;
+ struct resource *res_tsens_mem, *res_mem = NULL;
+
+ if (!of_match_node(tsens_table, of_node)) {
+ pr_err("Need to read SoC specific fuse map\n");
+ return -ENODEV;
+ }
+
+ id = of_match_node(tsens_table, of_node);
+ if (id == NULL) {
+ pr_err("can not find tsens_table of_node\n");
+ return -ENODEV;
+ }
+
+ data = id->data;
+ hw_id = devm_kzalloc(&pdev->dev,
+ tsens_num_sensors * sizeof(u32), GFP_KERNEL);
+ if (!hw_id)
+ return -ENOMEM;
+
+ client_id = devm_kzalloc(&pdev->dev,
+ tsens_num_sensors * sizeof(u32), GFP_KERNEL);
+ if (!client_id)
+ return -ENOMEM;
+
+ tmdev->ops = data->ops;
+ tmdev->ctrl_data = data;
+ tmdev->pdev = pdev;
+
+ if (!tmdev->ops || !tmdev->ops->hw_init || !tmdev->ops->get_temp) {
+ pr_err("Invalid ops\n");
+ return -EINVAL;
+ }
+
+ /* TSENS register region */
+ res_tsens_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "tsens_physical");
+ if (!res_tsens_mem) {
+ pr_err("Could not get tsens physical address resource\n");
+ return -EINVAL;
+ }
+
+ tsens_len = res_tsens_mem->end - res_tsens_mem->start + 1;
+
+ res_mem = request_mem_region(res_tsens_mem->start,
+ tsens_len, res_tsens_mem->name);
+ if (!res_mem) {
+ pr_err("Request tsens physical memory region failed\n");
+ return -EINVAL;
+ }
+
+ tmdev->tsens_addr = ioremap(res_mem->start, tsens_len);
+ if (!tmdev->tsens_addr) {
+ pr_err("Failed to IO map TSENS registers.\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,sensor-id", hw_id, tsens_num_sensors);
+ if (rc) {
+ pr_err("Default sensor id mapping\n");
+ for (i = 0; i < tsens_num_sensors; i++)
+ tmdev->sensor[i].hw_id = i;
+ } else {
+ pr_err("Use specified sensor id mapping\n");
+ for (i = 0; i < tsens_num_sensors; i++)
+ tmdev->sensor[i].hw_id = hw_id[i];
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,client-id", client_id, tsens_num_sensors);
+ if (rc) {
+ for (i = 0; i < tsens_num_sensors; i++)
+ tmdev->sensor[i].id = i;
+ pr_debug("Default client id mapping\n");
+ } else {
+ for (i = 0; i < tsens_num_sensors; i++)
+ tmdev->sensor[i].id = client_id[i];
+ pr_debug("Use specified client id mapping\n");
+ }
+
+ return 0;
+}
+
+static int tsens_thermal_zone_register(struct tsens_device *tmdev)
+{
+ int rc = 0, i = 0;
+
+ for (i = 0; i < tmdev->num_sensors; i++) {
+ tmdev->sensor[i].tmdev = tmdev;
+ tmdev->sensor[i].tzd = devm_thermal_zone_of_sensor_register(
+ &tmdev->pdev->dev, i, &tmdev->sensor[i],
+ &tsens_tm_thermal_zone_ops);
+ if (IS_ERR(tmdev->sensor[i].tzd)) {
+ pr_err("Error registering sensor:%d\n", i);
+ continue;
+ }
+ }
+
+ return rc;
+}
+
+static int tsens_tm_remove(struct platform_device *pdev)
+{
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+int tsens_tm_probe(struct platform_device *pdev)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ struct tsens_device *tmdev = NULL;
+ u32 tsens_num_sensors = 0;
+ int rc;
+
+ if (!(pdev->dev.of_node))
+ return -ENODEV;
+
+ rc = of_property_read_u32(of_node,
+ "qcom,sensors", &tsens_num_sensors);
+ if (rc || (!tsens_num_sensors)) {
+ dev_err(&pdev->dev, "missing sensors\n");
+ return -ENODEV;
+ }
+
+ tmdev = devm_kzalloc(&pdev->dev,
+ sizeof(struct tsens_device) +
+ tsens_num_sensors *
+ sizeof(struct tsens_sensor),
+ GFP_KERNEL);
+ if (tmdev == NULL) {
+ pr_err("%s: kzalloc() failed.\n", __func__);
+ return -ENOMEM;
+ }
+
+ tmdev->num_sensors = tsens_num_sensors;
+
+ rc = get_device_tree_data(pdev, tmdev);
+ if (rc) {
+ pr_err("Error reading TSENS DT\n");
+ return rc;
+ }
+
+ rc = tsens_init(tmdev);
+ if (rc)
+ return rc;
+
+ rc = tsens_thermal_zone_register(tmdev);
+ if (rc) {
+ pr_err("Error registering the thermal zone\n");
+ return rc;
+ }
+
+ rc = tsens_register_interrupts(tmdev);
+ if (rc < 0) {
+ pr_err("TSENS interrupt register failed:%d\n", rc);
+ return rc;
+ }
+
+ list_add_tail(&tmdev->list, &tsens_device_list);
+ platform_set_drvdata(pdev, tmdev);
+
+ return rc;
+}
+
+static struct platform_driver tsens_tm_driver = {
+ .probe = tsens_tm_probe,
+ .remove = tsens_tm_remove,
+ .driver = {
+ .name = "msm-tsens",
+ .owner = THIS_MODULE,
+ .of_match_table = tsens_table,
+ },
+};
+
+int __init tsens_tm_init_driver(void)
+{
+ return platform_driver_register(&tsens_tm_driver);
+}
+subsys_initcall(tsens_tm_init_driver);
+
+static void __exit tsens_tm_deinit(void)
+{
+ platform_driver_unregister(&tsens_tm_driver);
+}
+module_exit(tsens_tm_deinit);
+
+MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index d04ec3b..b337ad7 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -31,11 +31,16 @@
#include <linux/export.h>
#include <linux/string.h>
#include <linux/thermal.h>
+#include <linux/list.h>
#include "thermal_core.h"
-/*** Private data structures to represent thermal device tree data ***/
+#define for_each_tz_sibling(pos, head) \
+ for (pos = list_first_entry((head), struct __thermal_zone, list);\
+ &(pos->list) != (head); \
+ pos = list_next_entry(pos, list)) \
+/*** Private data structures to represent thermal device tree data ***/
/**
* struct __thermal_bind_param - a match between trip and cooling device
* @cooling_device: a pointer to identify the referred cooling device
@@ -54,18 +59,36 @@
};
/**
+ * struct __sensor_param - Holds individual sensor data
+ * @sensor_data: sensor driver private data passed as input argument
+ * @ops: sensor driver ops
+ * @trip_high: last trip high value programmed in the sensor driver
+ * @trip_low: last trip low value programmed in the sensor driver
+ * @lock: mutex lock acquired before updating the trip temperatures
+ * @first_tz: list head pointing the first thermal zone
+ */
+struct __sensor_param {
+ void *sensor_data;
+ const struct thermal_zone_of_device_ops *ops;
+ int trip_high, trip_low;
+ struct mutex lock;
+ struct list_head first_tz;
+};
+
+/**
* struct __thermal_zone - internal representation of a thermal zone
* @mode: current thermal zone device mode (enabled/disabled)
* @passive_delay: polling interval while passive cooling is activated
* @polling_delay: zone polling interval
* @slope: slope of the temperature adjustment curve
* @offset: offset of the temperature adjustment curve
+ * @tzd: thermal zone device pointer for this sensor
* @ntrips: number of trip points
* @trips: an array of trip points (0..ntrips - 1)
* @num_tbps: number of thermal bind params
* @tbps: an array of thermal bind params (0..num_tbps - 1)
- * @sensor_data: sensor private data used while reading temperature and trend
- * @ops: set of callbacks to handle the thermal zone based on DT
+ * @list: sibling thermal zone pointer
+ * @senps: sensor related parameters
*/
struct __thermal_zone {
@@ -74,6 +97,7 @@
int polling_delay;
int slope;
int offset;
+ struct thermal_zone_device *tzd;
/* trip data */
int ntrips;
@@ -83,11 +107,14 @@
int num_tbps;
struct __thermal_bind_params *tbps;
+ struct list_head list;
/* sensor interface */
- void *sensor_data;
- const struct thermal_zone_of_device_ops *ops;
+ struct __sensor_param *senps;
};
+static int of_thermal_aggregate_trip_types(struct thermal_zone_device *tz,
+ unsigned int trip_type_mask, int *low, int *high);
+
/*** DT thermal zone device callbacks ***/
static int of_thermal_get_temp(struct thermal_zone_device *tz,
@@ -95,21 +122,36 @@
{
struct __thermal_zone *data = tz->devdata;
- if (!data->ops->get_temp)
+ if (!data->senps || !data->senps->ops->get_temp)
return -EINVAL;
- return data->ops->get_temp(data->sensor_data, temp);
+ return data->senps->ops->get_temp(data->senps->sensor_data, temp);
}
static int of_thermal_set_trips(struct thermal_zone_device *tz,
- int low, int high)
+ int inp_low, int inp_high)
{
struct __thermal_zone *data = tz->devdata;
+ int high = INT_MAX, low = INT_MIN, ret = 0;
- if (!data->ops || !data->ops->set_trips)
+ if (!data->senps || !data->senps->ops->set_trips)
return -EINVAL;
- return data->ops->set_trips(data->sensor_data, low, high);
+ mutex_lock(&data->senps->lock);
+ of_thermal_aggregate_trip_types(tz, GENMASK(THERMAL_TRIP_CRITICAL, 0),
+ &low, &high);
+ if (low == data->senps->trip_low
+ && high == data->senps->trip_high)
+ goto set_trips_exit;
+
+ data->senps->trip_low = low;
+ data->senps->trip_high = high;
+ ret = data->senps->ops->set_trips(data->senps->sensor_data,
+ low, high);
+
+set_trips_exit:
+ mutex_unlock(&data->senps->lock);
+ return ret;
}
/**
@@ -192,7 +234,10 @@
{
struct __thermal_zone *data = tz->devdata;
- return data->ops->set_emul_temp(data->sensor_data, temp);
+ if (!data->senps || !data->senps->ops->set_emul_temp)
+ return -EINVAL;
+
+ return data->senps->ops->set_emul_temp(data->senps->sensor_data, temp);
}
static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
@@ -200,10 +245,11 @@
{
struct __thermal_zone *data = tz->devdata;
- if (!data->ops->get_trend)
+ if (!data->senps || !data->senps->ops->get_trend)
return -EINVAL;
- return data->ops->get_trend(data->sensor_data, trip, trend);
+ return data->senps->ops->get_trend(data->senps->sensor_data,
+ trip, trend);
}
static int of_thermal_bind(struct thermal_zone_device *thermal,
@@ -325,10 +371,11 @@
if (trip >= data->ntrips || trip < 0)
return -EDOM;
- if (data->ops->set_trip_temp) {
+ if (data->senps && data->senps->ops->set_trip_temp) {
int ret;
- ret = data->ops->set_trip_temp(data->sensor_data, trip, temp);
+ ret = data->senps->ops->set_trip_temp(data->senps->sensor_data,
+ trip, temp);
if (ret)
return ret;
}
@@ -381,6 +428,89 @@
return -EINVAL;
}
+static int of_thermal_aggregate_trip_types(struct thermal_zone_device *tz,
+ unsigned int trip_type_mask, int *low, int *high)
+{
+ int min = INT_MIN;
+ int max = INT_MAX;
+ int tt, th, trip;
+ int temp = tz->temperature;
+ struct thermal_zone_device *zone = NULL;
+ struct __thermal_zone *data = tz->devdata;
+ struct list_head *head;
+ enum thermal_trip_type type = 0;
+
+ head = &data->senps->first_tz;
+ for_each_tz_sibling(data, head) {
+ zone = data->tzd;
+ for (trip = 0; trip < data->ntrips; trip++) {
+ of_thermal_get_trip_type(zone, trip, &type);
+ if (!(BIT(type) & trip_type_mask))
+ continue;
+
+ if (!zone->tzp->tracks_low) {
+ tt = data->trips[trip].temperature;
+ if (tt > temp && tt < max)
+ max = tt;
+ th = tt - data->trips[trip].hysteresis;
+ if (th < temp && th > min)
+ min = th;
+ } else {
+ tt = data->trips[trip].temperature;
+ if (tt < temp && tt > min)
+ min = tt;
+ th = tt + data->trips[trip].hysteresis;
+ if (th > temp && th < max)
+ max = th;
+ }
+ }
+ }
+
+ *high = max;
+ *low = min;
+
+ return 0;
+}
+
+/*
+ * of_thermal_aggregate_trip - aggregate trip temperatures across sibling
+ * thermal zones.
+ * @tz: pointer to the primary thermal zone.
+ * @type: the thermal trip type to be aggregated upon
+ * @low: the low trip threshold which the most lesser than the @temp
+ * @high: the high trip threshold which is the least greater than the @temp
+ */
+int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type type,
+ int *low, int *high)
+{
+ if (type <= THERMAL_TRIP_CRITICAL)
+ return of_thermal_aggregate_trip_types(tz, BIT(type), low,
+ high);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(of_thermal_aggregate_trip);
+
+/*
+ * of_thermal_handle_trip - Handle thermal trip from sensors
+ *
+ * @tz: pointer to the primary thermal zone.
+ */
+void of_thermal_handle_trip(struct thermal_zone_device *tz)
+{
+ struct thermal_zone_device *zone;
+ struct __thermal_zone *data = tz->devdata;
+ struct list_head *head;
+
+ head = &data->senps->first_tz;
+ for_each_tz_sibling(data, head) {
+ zone = data->tzd;
+ thermal_zone_device_update(zone, THERMAL_EVENT_UNSPECIFIED);
+ }
+}
+EXPORT_SYMBOL(of_thermal_handle_trip);
+
static struct thermal_zone_device_ops of_thermal_ops = {
.get_mode = of_thermal_get_mode,
.set_mode = of_thermal_set_mode,
@@ -400,8 +530,8 @@
static struct thermal_zone_device *
thermal_zone_of_add_sensor(struct device_node *zone,
- struct device_node *sensor, void *data,
- const struct thermal_zone_of_device_ops *ops)
+ struct device_node *sensor,
+ struct __sensor_param *sens_param)
{
struct thermal_zone_device *tzd;
struct __thermal_zone *tz;
@@ -412,12 +542,11 @@
tz = tzd->devdata;
- if (!ops)
+ if (!sens_param->ops)
return ERR_PTR(-EINVAL);
mutex_lock(&tzd->lock);
- tz->ops = ops;
- tz->sensor_data = data;
+ tz->senps = sens_param;
tzd->ops->get_temp = of_thermal_get_temp;
tzd->ops->get_trend = of_thermal_get_trend;
@@ -426,12 +555,13 @@
* The thermal zone core will calculate the window if they have set the
* optional set_trips pointer.
*/
- if (ops->set_trips)
+ if (sens_param->ops->set_trips)
tzd->ops->set_trips = of_thermal_set_trips;
- if (ops->set_emul_temp)
+ if (sens_param->ops->set_emul_temp)
tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
+ list_add_tail(&tz->list, &sens_param->first_tz);
mutex_unlock(&tzd->lock);
return tzd;
@@ -462,11 +592,10 @@
* 01 - This function must enqueue the new sensor instead of using
* it as the only source of temperature values.
*
- * 02 - There must be a way to match the sensor with all thermal zones
- * that refer to it.
- *
* Return: On success returns a valid struct thermal_zone_device,
- * otherwise, it returns a corresponding ERR_PTR(). Caller must
+ * otherwise, it returns a corresponding ERR_PTR(). Incase there are multiple
+ * thermal zones referencing the same sensor, the return value will be
+ * thermal_zone_device pointer of the first thermal zone. Caller must
* check the return value with help of IS_ERR() helper.
*/
struct thermal_zone_device *
@@ -475,6 +604,8 @@
{
struct device_node *np, *child, *sensor_np;
struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
+ struct thermal_zone_device *first_tzd = NULL;
+ struct __sensor_param *sens_param = NULL;
np = of_find_node_by_name(NULL, "thermal-zones");
if (!np)
@@ -485,6 +616,17 @@
return ERR_PTR(-EINVAL);
}
+ sens_param = kzalloc(sizeof(*sens_param), GFP_KERNEL);
+ if (!sens_param) {
+ of_node_put(np);
+ return ERR_PTR(-ENOMEM);
+ }
+ sens_param->sensor_data = data;
+ sens_param->ops = ops;
+ INIT_LIST_HEAD(&sens_param->first_tz);
+ sens_param->trip_high = INT_MAX;
+ sens_param->trip_low = INT_MIN;
+ mutex_init(&sens_param->lock);
sensor_np = of_node_get(dev->of_node);
for_each_available_child_of_node(np, child) {
@@ -509,21 +651,23 @@
if (sensor_specs.np == sensor_np && id == sensor_id) {
tzd = thermal_zone_of_add_sensor(child, sensor_np,
- data, ops);
- if (!IS_ERR(tzd))
+ sens_param);
+ if (!IS_ERR(tzd)) {
+ if (!first_tzd)
+ first_tzd = tzd;
tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
-
- of_node_put(sensor_specs.np);
- of_node_put(child);
- goto exit;
+ }
}
of_node_put(sensor_specs.np);
}
-exit:
of_node_put(sensor_np);
of_node_put(np);
- return tzd;
+ if (!first_tzd) {
+ first_tzd = ERR_PTR(-ENODEV);
+ kfree(sens_param);
+ }
+ return first_tzd;
}
EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register);
@@ -546,6 +690,8 @@
struct thermal_zone_device *tzd)
{
struct __thermal_zone *tz;
+ struct thermal_zone_device *pos;
+ struct list_head *head;
if (!dev || !tzd || !tzd->devdata)
return;
@@ -556,14 +702,20 @@
if (!tz)
return;
- mutex_lock(&tzd->lock);
- tzd->ops->get_temp = NULL;
- tzd->ops->get_trend = NULL;
- tzd->ops->set_emul_temp = NULL;
+ head = &tz->senps->first_tz;
+ for_each_tz_sibling(tz, head) {
+ pos = tz->tzd;
+ mutex_lock(&pos->lock);
+ pos->ops->get_temp = NULL;
+ pos->ops->get_trend = NULL;
+ pos->ops->set_emul_temp = NULL;
- tz->ops = NULL;
- tz->sensor_data = NULL;
- mutex_unlock(&tzd->lock);
+ list_del(&tz->list);
+ if (list_empty(&tz->senps->first_tz))
+ kfree(tz->senps);
+ tz->senps = NULL;
+ mutex_unlock(&pos->lock);
+ }
}
EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
@@ -832,6 +984,7 @@
if (!tz)
return ERR_PTR(-ENOMEM);
+ INIT_LIST_HEAD(&tz->list);
ret = of_property_read_u32(np, "polling-delay-passive", &prop);
if (ret < 0) {
pr_err("missing polling-delay-passive property\n");
@@ -975,6 +1128,7 @@
struct thermal_zone_params *tzp;
int i, mask = 0;
u32 prop;
+ const char *governor_name;
tz = thermal_of_build_thermal_zone(child);
if (IS_ERR(tz)) {
@@ -997,6 +1151,11 @@
/* No hwmon because there might be hwmon drivers registering */
tzp->no_hwmon = true;
+ if (!of_property_read_string(child, "thermal-governor",
+ &governor_name))
+ strlcpy(tzp->governor_name, governor_name,
+ THERMAL_NAME_LENGTH);
+
if (!of_property_read_u32(child, "sustainable-power", &prop))
tzp->sustainable_power = prop;
@@ -1007,6 +1166,9 @@
tzp->slope = tz->slope;
tzp->offset = tz->offset;
+ if (of_property_read_bool(child, "tracks-low"))
+ tzp->tracks_low = true;
+
zone = thermal_zone_device_register(child->name, tz->ntrips,
mask, tz,
ops, tzp,
@@ -1019,7 +1181,9 @@
kfree(ops);
of_thermal_free_zone(tz);
/* attempting to build remaining zones still */
+ continue;
}
+ tz->tzd = zone;
}
of_node_put(np);
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index bcef2e7..4fa7f82 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -37,7 +37,7 @@
* for this trip point
* d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit
* for this trip point
- * If the temperature is lower than a trip point,
+ * If the temperature is lower than a hysteresis temperature,
* a. if the trend is THERMAL_TREND_RAISING, do nothing
* b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
* state for this trip point, if the cooling state already
@@ -126,7 +126,7 @@
static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
{
- int trip_temp;
+ int trip_temp, hyst_temp;
enum thermal_trip_type trip_type;
enum thermal_trend trend;
struct thermal_instance *instance;
@@ -134,22 +134,24 @@
int old_target;
if (trip == THERMAL_TRIPS_NONE) {
- trip_temp = tz->forced_passive;
+ hyst_temp = trip_temp = tz->forced_passive;
trip_type = THERMAL_TRIPS_NONE;
} else {
tz->ops->get_trip_temp(tz, trip, &trip_temp);
+ if (tz->ops->get_trip_hyst) {
+ tz->ops->get_trip_hyst(tz, trip, &hyst_temp);
+ hyst_temp = trip_temp - hyst_temp;
+ } else {
+ hyst_temp = trip_temp;
+ }
tz->ops->get_trip_type(tz, trip, &trip_type);
}
trend = get_tz_trend(tz, trip);
- if (tz->temperature >= trip_temp) {
- throttle = true;
- trace_thermal_zone_trip(tz, trip, trip_type);
- }
-
- dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
- trip, trip_type, trip_temp, trend, throttle);
+ dev_dbg(&tz->device,
+ "Trip%d[type=%d,temp=%d,hyst=%d]:trend=%d,throttle=%d\n",
+ trip, trip_type, trip_temp, hyst_temp, trend, throttle);
mutex_lock(&tz->lock);
@@ -158,6 +160,22 @@
continue;
old_target = instance->target;
+ /*
+ * Step wise has to lower the mitigation only if the
+ * temperature goes below the hysteresis temperature.
+ * Atleast, it has to hold on to mitigation device lower
+ * limit if the temperature is above the hysteresis
+ * temperature.
+ */
+ if (tz->temperature >= trip_temp ||
+ (tz->temperature >= hyst_temp &&
+ old_target != THERMAL_NO_TARGET)) {
+ throttle = true;
+ trace_thermal_zone_trip(tz, trip, trip_type);
+ } else {
+ throttle = false;
+ }
+
instance->target = get_target_state(instance, trend, throttle);
dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
old_target, (int)instance->target);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 5bb3862..5b627ea 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -457,7 +457,7 @@
}
}
-static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
@@ -520,7 +520,6 @@
if (!ret && *temp < crit_temp)
*temp = tz->emul_temperature;
}
-
mutex_unlock(&tz->lock);
exit:
return ret;
@@ -1201,6 +1200,25 @@
}
static ssize_t
+thermal_cooling_device_min_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct thermal_cooling_device *cdev = to_cooling_device(dev);
+ unsigned long state;
+ int ret;
+
+ if (cdev->ops->get_min_state)
+ ret = cdev->ops->get_min_state(cdev, &state);
+ else
+ ret = -EPERM;
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, PAGE_SIZE, "%lu\n", state);
+}
+
+static ssize_t
thermal_cooling_device_cur_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1220,8 +1238,7 @@
const char *buf, size_t count)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
- unsigned long state;
- int result;
+ long state;
if (!sscanf(buf, "%ld\n", &state))
return -EINVAL;
@@ -1229,9 +1246,35 @@
if ((long)state < 0)
return -EINVAL;
- result = cdev->ops->set_cur_state(cdev, state);
- if (result)
- return result;
+ cdev->sysfs_cur_state_req = state;
+
+ cdev->updated = false;
+ thermal_cdev_update(cdev);
+
+ return count;
+}
+
+static ssize_t
+thermal_cooling_device_min_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct thermal_cooling_device *cdev = to_cooling_device(dev);
+ long state;
+ int ret = 0;
+
+ ret = sscanf(buf, "%ld\n", &state);
+ if (ret <= 0)
+ return (ret < 0) ? ret : -EINVAL;
+
+ if ((long)state < 0)
+ return -EINVAL;
+
+ cdev->sysfs_min_state_req = state;
+
+ cdev->updated = false;
+ thermal_cdev_update(cdev);
+
return count;
}
@@ -1242,6 +1285,9 @@
static DEVICE_ATTR(cur_state, 0644,
thermal_cooling_device_cur_state_show,
thermal_cooling_device_cur_state_store);
+static DEVICE_ATTR(min_state, 0644,
+ thermal_cooling_device_min_state_show,
+ thermal_cooling_device_min_state_store);
static ssize_t
thermal_cooling_device_trip_point_show(struct device *dev,
@@ -1262,6 +1308,7 @@
&dev_attr_cdev_type.attr,
&dev_attr_max_state.attr,
&dev_attr_cur_state.attr,
+ &dev_attr_min_state.attr,
NULL,
};
@@ -1555,6 +1602,8 @@
cdev->device.class = &thermal_class;
cdev->device.groups = cooling_device_attr_groups;
cdev->devdata = devdata;
+ cdev->sysfs_cur_state_req = 0;
+ cdev->sysfs_min_state_req = ULONG_MAX;
dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
result = device_register(&cdev->device);
if (result) {
@@ -1689,7 +1738,7 @@
void thermal_cdev_update(struct thermal_cooling_device *cdev)
{
struct thermal_instance *instance;
- unsigned long target = 0;
+ unsigned long current_target = 0, min_target = ULONG_MAX;
mutex_lock(&cdev->lock);
/* cooling device is updated*/
@@ -1699,19 +1748,29 @@
}
/* Make sure cdev enters the deepest cooling state */
+ current_target = cdev->sysfs_cur_state_req;
+ min_target = cdev->sysfs_min_state_req;
list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
dev_dbg(&cdev->device, "zone%d->target=%lu\n",
instance->tz->id, instance->target);
if (instance->target == THERMAL_NO_TARGET)
continue;
- if (instance->target > target)
- target = instance->target;
+ if (instance->tz->governor->min_state_throttle) {
+ if (instance->target < min_target)
+ min_target = instance->target;
+ } else {
+ if (instance->target > current_target)
+ current_target = instance->target;
+ }
}
- cdev->ops->set_cur_state(cdev, target);
+ cdev->ops->set_cur_state(cdev, current_target);
+ if (cdev->ops->set_min_state)
+ cdev->ops->set_min_state(cdev, min_target);
cdev->updated = true;
mutex_unlock(&cdev->lock);
- trace_cdev_update(cdev, target);
- dev_dbg(&cdev->device, "set to state %lu\n", target);
+ trace_cdev_update(cdev, current_target);
+ dev_dbg(&cdev->device, "set to state %lu min state %lu\n",
+ current_target, min_target);
}
EXPORT_SYMBOL(thermal_cdev_update);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 749d41a..9408f3f 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -56,6 +56,7 @@
int thermal_register_governor(struct thermal_governor *);
void thermal_unregister_governor(struct thermal_governor *);
+void handle_thermal_trip(struct thermal_zone_device *tz, int trip);
#ifdef CONFIG_THERMAL_GOV_STEP_WISE
int thermal_gov_step_wise_register(void);
@@ -105,6 +106,10 @@
bool of_thermal_is_trip_valid(struct thermal_zone_device *, int);
const struct thermal_trip *
of_thermal_get_trip_points(struct thermal_zone_device *);
+int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type type,
+ int *low, int *high);
+void of_thermal_handle_trip(struct thermal_zone_device *tz);
#else
static inline int of_parse_thermal_zones(void) { return 0; }
static inline void of_thermal_destroy_zones(void) { }
@@ -122,6 +127,15 @@
{
return NULL;
}
+static inline int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type type,
+ int *low, int *high)
+{
+ return -ENODEV;
+}
+static inline
+void of_thermal_handle_trip(struct thermal_zone_device *tz)
+{ }
#endif
#endif /* __THERMAL_CORE_H__ */
diff --git a/drivers/thermal/tsens-dbg.c b/drivers/thermal/tsens-dbg.c
new file mode 100644
index 0000000..d965a5c
--- /dev/null
+++ b/drivers/thermal/tsens-dbg.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the term_tm 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 <asm/arch_timer.h>
+#include "tsens.h"
+
+/* debug defines */
+#define TSENS_DBG_BUS_ID_0 0
+#define TSENS_DBG_BUS_ID_1 1
+#define TSENS_DBG_BUS_ID_2 2
+#define TSENS_DBG_BUS_ID_15 15
+#define TSENS_DEBUG_LOOP_COUNT_ID_0 2
+#define TSENS_DEBUG_LOOP_COUNT 5
+#define TSENS_DEBUG_STATUS_REG_START 10
+#define TSENS_DEBUG_OFFSET_RANGE 16
+#define TSENS_DEBUG_OFFSET_WORD1 0x4
+#define TSENS_DEBUG_OFFSET_WORD2 0x8
+#define TSENS_DEBUG_OFFSET_WORD3 0xc
+#define TSENS_DEBUG_OFFSET_ROW 0x10
+#define TSENS_DEBUG_DECIDEGC -950
+#define TSENS_DEBUG_CYCLE_MS 64
+#define TSENS_DEBUG_POLL_MS 200
+#define TSENS_DEBUG_BUS_ID2_MIN_CYCLE 50
+#define TSENS_DEBUG_BUS_ID2_MAX_CYCLE 51
+#define TSENS_DEBUG_ID_MASK_1_4 0xffffffe1
+#define DEBUG_SIZE 10
+
+#define TSENS_DEBUG_CONTROL(n) ((n) + 0x1130)
+#define TSENS_DEBUG_DATA(n) ((n) + 0x1134)
+
+struct tsens_dbg_func {
+ int (*dbg_func)(struct tsens_device *, u32, u32, int *);
+};
+
+static int tsens_dbg_log_temp_reads(struct tsens_device *data, u32 id,
+ u32 dbg_type, int *temp)
+{
+ struct tsens_sensor *sensor;
+ struct tsens_device *tmdev = NULL;
+ u32 idx = 0;
+
+ if (!data)
+ return -EINVAL;
+
+ pr_debug("%d %d\n", id, dbg_type);
+ tmdev = data;
+ sensor = &tmdev->sensor[id];
+ idx = tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].idx;
+ tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].temp[idx%10] = *temp;
+ tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].time_stmp[idx%10] =
+ sched_clock();
+ idx++;
+ tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].idx = idx;
+
+ return 0;
+}
+
+static int tsens_dbg_log_interrupt_timestamp(struct tsens_device *data,
+ u32 id, u32 dbg_type, int *val)
+{
+ struct tsens_device *tmdev = NULL;
+ u32 idx = 0;
+
+ if (!data)
+ return -EINVAL;
+
+ pr_debug("%d %d\n", id, dbg_type);
+ tmdev = data;
+ /* debug */
+ idx = tmdev->tsens_dbg.tsens_thread_iq_dbg.idx;
+ tmdev->tsens_dbg.tsens_thread_iq_dbg.dbg_count[idx%10]++;
+ tmdev->tsens_dbg.tsens_thread_iq_dbg.time_stmp[idx%10] =
+ sched_clock();
+ tmdev->tsens_dbg.tsens_thread_iq_dbg.idx++;
+
+ return 0;
+}
+
+static struct tsens_dbg_func dbg_arr[] = {
+ [TSENS_DBG_LOG_TEMP_READS] = {tsens_dbg_log_temp_reads},
+ [TSENS_DBG_LOG_INTERRUPT_TIMESTAMP] = {
+ tsens_dbg_log_interrupt_timestamp},
+};
+
+int tsens2xxx_dbg(struct tsens_device *data, u32 id, u32 dbg_type, int *val)
+{
+ if (dbg_type >= TSENS_DBG_LOG_MAX)
+ return -EINVAL;
+
+ dbg_arr[dbg_type].dbg_func(data, id, dbg_type, val);
+
+ return 0;
+}
+EXPORT_SYMBOL(tsens2xxx_dbg);
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
new file mode 100644
index 0000000..45d244e
--- /dev/null
+++ b/drivers/thermal/tsens.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 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 __QCOM_TSENS_H__
+#define __QCOM_TSENS_H__
+
+#include <linux/kernel.h>
+#include <linux/thermal.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define DEBUG_SIZE 10
+#define TSENS_MAX_SENSORS 16
+#define TSENS_CONTROLLER_ID(n) ((n) + 0x1000)
+#define TSENS_CTRL_ADDR(n) (n)
+#define TSENS_TM_SN_STATUS(n) ((n) + 0x10a0)
+
+enum tsens_dbg_type {
+ TSENS_DBG_POLL,
+ TSENS_DBG_LOG_TEMP_READS,
+ TSENS_DBG_LOG_INTERRUPT_TIMESTAMP,
+ TSENS_DBG_LOG_MAX
+};
+
+#define tsens_sec_to_msec_value 1000
+
+struct tsens_device;
+
+#if defined(CONFIG_THERMAL_TSENS)
+int tsens2xxx_dbg(struct tsens_device *data, u32 id, u32 dbg_type, int *temp);
+#else
+static inline int tsens2xxx_dbg(struct tsens_device *data, u32 id,
+ u32 dbg_type, int *temp)
+{ return -ENXIO; }
+#endif
+
+struct tsens_dbg {
+ u32 dbg_count[DEBUG_SIZE];
+ u32 idx;
+ unsigned long long time_stmp[DEBUG_SIZE];
+ unsigned long temp[DEBUG_SIZE];
+};
+
+struct tsens_dbg_context {
+ struct tsens_device *tmdev;
+ struct tsens_dbg tsens_thread_iq_dbg;
+ struct tsens_dbg sensor_dbg_info[TSENS_MAX_SENSORS];
+ int tsens_critical_wd_cnt;
+ struct delayed_work tsens_critical_poll_test;
+};
+
+struct tsens_context {
+ enum thermal_device_mode high_th_state;
+ enum thermal_device_mode low_th_state;
+ enum thermal_device_mode crit_th_state;
+ int high_temp;
+ int low_temp;
+ int crit_temp;
+};
+
+struct tsens_sensor {
+ struct tsens_device *tmdev;
+ struct thermal_zone_device *tzd;
+ u32 hw_id;
+ u32 id;
+ const char *sensor_name;
+ struct tsens_context thr_state;
+};
+
+/**
+ * struct tsens_ops - operations as supported by the tsens device
+ * @init: Function to initialize the tsens device
+ * @get_temp: Function which returns the temp in millidegC
+ */
+struct tsens_ops {
+ int (*hw_init)(struct tsens_device *);
+ int (*get_temp)(struct tsens_sensor *, int *);
+ int (*set_trip_temp)(struct tsens_sensor *, int, int);
+ int (*interrupts_reg)(struct tsens_device *);
+ int (*dbg)(struct tsens_device *, u32, u32, int *);
+};
+
+struct tsens_irqs {
+ const char *name;
+ irqreturn_t (*handler)(int, void *);
+};
+
+/**
+ * struct tsens_data - tsens instance specific data
+ * @num_sensors: Max number of sensors supported by platform
+ * @ops: operations the tsens instance supports
+ * @hw_ids: Subset of sensors ids supported by platform, if not the first n
+ */
+struct tsens_data {
+ const u32 num_sensors;
+ const struct tsens_ops *ops;
+ unsigned int *hw_ids;
+ u32 temp_factor;
+ bool cycle_monitor;
+ u32 cycle_compltn_monitor_val;
+ bool wd_bark;
+ u32 wd_bark_val;
+};
+
+struct tsens_device {
+ struct device *dev;
+ struct platform_device *pdev;
+ struct list_head list;
+ u32 num_sensors;
+ struct regmap *map;
+ struct regmap_field *status_field;
+ void *tsens_addr;
+ const struct tsens_ops *ops;
+ struct tsens_dbg_context tsens_dbg;
+ spinlock_t tsens_crit_lock;
+ spinlock_t tsens_upp_low_lock;
+ const struct tsens_data *ctrl_data;
+ struct tsens_sensor sensor[0];
+};
+
+extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
+
+#endif /* __QCOM_TSENS_H__ */
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
new file mode 100644
index 0000000..0f59dc5
--- /dev/null
+++ b/drivers/thermal/tsens2xxx.c
@@ -0,0 +1,543 @@
+/* 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 term_tm 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/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/vmalloc.h>
+#include "tsens.h"
+
+#define TSENS_DRIVER_NAME "msm-tsens"
+
+#define TSENS_TM_INT_EN(n) ((n) + 0x1004)
+#define TSENS_TM_CRITICAL_INT_STATUS(n) ((n) + 0x1014)
+#define TSENS_TM_CRITICAL_INT_CLEAR(n) ((n) + 0x1018)
+#define TSENS_TM_CRITICAL_INT_MASK(n) ((n) + 0x101c)
+#define TSENS_TM_CRITICAL_WD_BARK BIT(31)
+#define TSENS_TM_CRITICAL_CYCLE_MONITOR BIT(30)
+#define TSENS_TM_CRITICAL_INT_EN BIT(2)
+#define TSENS_TM_UPPER_INT_EN BIT(1)
+#define TSENS_TM_LOWER_INT_EN BIT(0)
+#define TSENS_TM_SN_UPPER_LOWER_THRESHOLD(n) ((n) + 0x1020)
+#define TSENS_TM_SN_ADDR_OFFSET 0x4
+#define TSENS_TM_UPPER_THRESHOLD_SET(n) ((n) << 12)
+#define TSENS_TM_UPPER_THRESHOLD_VALUE_SHIFT(n) ((n) >> 12)
+#define TSENS_TM_LOWER_THRESHOLD_VALUE(n) ((n) & 0xfff)
+#define TSENS_TM_UPPER_THRESHOLD_VALUE(n) (((n) & 0xfff000) >> 12)
+#define TSENS_TM_UPPER_THRESHOLD_MASK 0xfff000
+#define TSENS_TM_LOWER_THRESHOLD_MASK 0xfff
+#define TSENS_TM_UPPER_THRESHOLD_SHIFT 12
+#define TSENS_TM_SN_CRITICAL_THRESHOLD(n) ((n) + 0x1060)
+#define TSENS_STATUS_ADDR_OFFSET 2
+#define TSENS_TM_UPPER_INT_MASK(n) (((n) & 0xffff0000) >> 16)
+#define TSENS_TM_LOWER_INT_MASK(n) ((n) & 0xffff)
+#define TSENS_TM_UPPER_LOWER_INT_STATUS(n) ((n) + 0x1008)
+#define TSENS_TM_UPPER_LOWER_INT_CLEAR(n) ((n) + 0x100c)
+#define TSENS_TM_UPPER_LOWER_INT_MASK(n) ((n) + 0x1010)
+#define TSENS_TM_UPPER_INT_SET(n) (1 << (n + 16))
+#define TSENS_TM_SN_CRITICAL_THRESHOLD_MASK 0xfff
+#define TSENS_TM_SN_STATUS_VALID_BIT BIT(21)
+#define TSENS_TM_SN_STATUS_CRITICAL_STATUS BIT(19)
+#define TSENS_TM_SN_STATUS_UPPER_STATUS BIT(18)
+#define TSENS_TM_SN_STATUS_LOWER_STATUS BIT(17)
+#define TSENS_TM_SN_LAST_TEMP_MASK 0xfff
+#define TSENS_TM_CODE_BIT_MASK 0xfff
+#define TSENS_TM_CODE_SIGN_BIT 0x800
+
+#define TSENS_EN BIT(0)
+
+static void msm_tsens_convert_temp(int last_temp, int *temp)
+{
+ int code_mask = ~TSENS_TM_CODE_BIT_MASK;
+
+ if (last_temp & TSENS_TM_CODE_SIGN_BIT) {
+ /* Sign extension for negative value */
+ last_temp |= code_mask;
+ }
+
+ *temp = last_temp * 100;
+}
+
+static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp)
+{
+ struct tsens_device *tmdev = NULL;
+ unsigned int code;
+ void __iomem *sensor_addr;
+ int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
+
+ if (!sensor)
+ return -EINVAL;
+
+ tmdev = sensor->tmdev;
+ sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_addr);
+
+ code = readl_relaxed_no_log(sensor_addr +
+ (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+ last_temp = code & TSENS_TM_SN_LAST_TEMP_MASK;
+
+ if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
+ msm_tsens_convert_temp(last_temp, temp);
+ return 0;
+ }
+
+ code = readl_relaxed_no_log(sensor_addr +
+ (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+ last_temp2 = code & TSENS_TM_SN_LAST_TEMP_MASK;
+ if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
+ last_temp = last_temp2;
+ msm_tsens_convert_temp(last_temp, temp);
+ return 0;
+ }
+
+ code = readl_relaxed_no_log(sensor_addr +
+ (sensor->hw_id <<
+ TSENS_STATUS_ADDR_OFFSET));
+ last_temp3 = code & TSENS_TM_SN_LAST_TEMP_MASK;
+ if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
+ last_temp = last_temp3;
+ msm_tsens_convert_temp(last_temp, temp);
+ return 0;
+ }
+
+ if (last_temp == last_temp2)
+ last_temp = last_temp2;
+ else if (last_temp2 == last_temp3)
+ last_temp = last_temp3;
+
+ msm_tsens_convert_temp(last_temp, temp);
+
+ if (tmdev->ops->dbg)
+ tmdev->ops->dbg(tmdev, (u32) sensor->hw_id,
+ TSENS_DBG_LOG_TEMP_READS, temp);
+
+ return 0;
+}
+
+static int tsens_tm_activate_trip_type(struct tsens_sensor *tm_sensor,
+ int trip, enum thermal_trip_activation_mode mode)
+{
+ struct tsens_device *tmdev = NULL;
+ unsigned int reg_cntl, mask;
+ unsigned long flags;
+ int rc = 0;
+
+ /* clear the interrupt and unmask */
+ if (!tm_sensor || trip < 0)
+ return -EINVAL;
+
+ tmdev = tm_sensor->tmdev;
+ if (!tmdev)
+ return -EINVAL;
+
+ spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+ mask = (tm_sensor->hw_id);
+ switch (trip) {
+ case THERMAL_TRIP_CRITICAL:
+ tmdev->sensor[tm_sensor->hw_id].
+ thr_state.crit_th_state = mode;
+ reg_cntl = readl_relaxed(TSENS_TM_CRITICAL_INT_MASK
+ (tmdev->tsens_addr));
+ if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+ writel_relaxed(reg_cntl | (1 << mask),
+ (TSENS_TM_CRITICAL_INT_MASK
+ (tmdev->tsens_addr)));
+ else
+ writel_relaxed(reg_cntl & ~(1 << mask),
+ (TSENS_TM_CRITICAL_INT_MASK
+ (tmdev->tsens_addr)));
+ break;
+ case THERMAL_TRIP_ACTIVE:
+ tmdev->sensor[tm_sensor->hw_id].
+ thr_state.high_th_state = mode;
+ reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
+ (tmdev->tsens_addr));
+ if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+ writel_relaxed(reg_cntl |
+ (TSENS_TM_UPPER_INT_SET(mask)),
+ (TSENS_TM_UPPER_LOWER_INT_MASK
+ (tmdev->tsens_addr)));
+ else
+ writel_relaxed(reg_cntl &
+ ~(TSENS_TM_UPPER_INT_SET(mask)),
+ (TSENS_TM_UPPER_LOWER_INT_MASK
+ (tmdev->tsens_addr)));
+ break;
+ case THERMAL_TRIP_PASSIVE:
+ tmdev->sensor[tm_sensor->hw_id].
+ thr_state.low_th_state = mode;
+ reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
+ (tmdev->tsens_addr));
+ if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+ writel_relaxed(reg_cntl | (1 << mask),
+ (TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr)));
+ else
+ writel_relaxed(reg_cntl & ~(1 << mask),
+ (TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr)));
+ break;
+ default:
+ rc = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+ /* Activate and enable the respective trip threshold setting */
+ mb();
+
+ return rc;
+}
+
+static int tsens2xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
+ int trip, int temp)
+{
+ unsigned int reg_cntl;
+ unsigned long flags;
+ struct tsens_device *tmdev = NULL;
+ int rc = 0;
+
+ if (!tm_sensor || trip < 0)
+ return -EINVAL;
+
+ tmdev = tm_sensor->tmdev;
+ if (!tmdev)
+ return -EINVAL;
+
+ spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+ switch (trip) {
+ case THERMAL_TRIP_CRITICAL:
+ tmdev->sensor[tm_sensor->hw_id].
+ thr_state.crit_temp = temp;
+ temp &= TSENS_TM_SN_CRITICAL_THRESHOLD_MASK;
+ writel_relaxed(temp,
+ (TSENS_TM_SN_CRITICAL_THRESHOLD(tmdev->tsens_addr) +
+ (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
+ break;
+ case THERMAL_TRIP_ACTIVE:
+ tmdev->sensor[tm_sensor->hw_id].
+ thr_state.high_temp = temp;
+ reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
+ (tmdev->tsens_addr)) +
+ (tm_sensor->hw_id *
+ TSENS_TM_SN_ADDR_OFFSET));
+ temp = TSENS_TM_UPPER_THRESHOLD_SET(temp);
+ temp &= TSENS_TM_UPPER_THRESHOLD_MASK;
+ reg_cntl &= ~TSENS_TM_UPPER_THRESHOLD_MASK;
+ writel_relaxed(reg_cntl | temp,
+ (TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr) +
+ (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
+ break;
+ case THERMAL_TRIP_PASSIVE:
+ tmdev->sensor[tm_sensor->hw_id].
+ thr_state.low_temp = temp;
+ reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
+ (tmdev->tsens_addr)) +
+ (tm_sensor->hw_id *
+ TSENS_TM_SN_ADDR_OFFSET));
+ temp &= TSENS_TM_LOWER_THRESHOLD_MASK;
+ reg_cntl &= ~TSENS_TM_LOWER_THRESHOLD_MASK;
+ writel_relaxed(reg_cntl | temp,
+ (TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr) +
+ (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
+ break;
+ default:
+ pr_err("Invalid trip to TSENS: %d\n", trip);
+ rc = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+ /* Set trip temperature thresholds */
+ mb();
+
+ rc = tsens_tm_activate_trip_type(tm_sensor, trip,
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ if (rc)
+ pr_err("Error during trip activation :%d\n", rc);
+
+ return rc;
+}
+
+static irqreturn_t tsens_tm_critical_irq_thread(int irq, void *data)
+{
+ struct tsens_device *tm = data;
+ unsigned int i, status;
+ unsigned long flags;
+ void __iomem *sensor_status_addr;
+ void __iomem *sensor_int_mask_addr;
+ void __iomem *sensor_critical_addr;
+ void __iomem *wd_critical_addr;
+ int wd_mask;
+
+ sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_addr);
+ sensor_int_mask_addr =
+ TSENS_TM_CRITICAL_INT_MASK(tm->tsens_addr);
+ sensor_critical_addr =
+ TSENS_TM_SN_CRITICAL_THRESHOLD(tm->tsens_addr);
+ wd_critical_addr =
+ TSENS_TM_CRITICAL_INT_STATUS(tm->tsens_addr);
+
+ if (tm->ctrl_data->wd_bark) {
+ wd_mask = readl_relaxed(wd_critical_addr);
+ if (wd_mask & TSENS_TM_CRITICAL_WD_BARK) {
+ /*
+ * Clear watchdog interrupt and
+ * increment global wd count
+ */
+ writel_relaxed(wd_mask | TSENS_TM_CRITICAL_WD_BARK,
+ (TSENS_TM_CRITICAL_INT_CLEAR
+ (tm->tsens_addr)));
+ writel_relaxed(wd_mask & ~(TSENS_TM_CRITICAL_WD_BARK),
+ (TSENS_TM_CRITICAL_INT_CLEAR
+ (tm->tsens_addr)));
+ tm->tsens_dbg.tsens_critical_wd_cnt++;
+ return IRQ_HANDLED;
+ }
+ }
+
+ for (i = 0; i < tm->num_sensors; i++) {
+ int int_mask, int_mask_val;
+ u32 addr_offset;
+
+ spin_lock_irqsave(&tm->tsens_crit_lock, flags);
+ addr_offset = tm->sensor[i].hw_id *
+ TSENS_TM_SN_ADDR_OFFSET;
+ status = readl_relaxed(sensor_status_addr + addr_offset);
+ int_mask = readl_relaxed(sensor_int_mask_addr);
+
+ if ((status & TSENS_TM_SN_STATUS_CRITICAL_STATUS) &&
+ !(int_mask & (1 << tm->sensor[i].hw_id))) {
+ int_mask = readl_relaxed(sensor_int_mask_addr);
+ int_mask_val = (1 << tm->sensor[i].hw_id);
+ /* Mask the corresponding interrupt for the sensors */
+ writel_relaxed(int_mask | int_mask_val,
+ TSENS_TM_CRITICAL_INT_MASK(
+ tm->tsens_addr));
+ /* Clear the corresponding sensors interrupt */
+ writel_relaxed(int_mask_val,
+ TSENS_TM_CRITICAL_INT_CLEAR(tm->tsens_addr));
+ writel_relaxed(0,
+ TSENS_TM_CRITICAL_INT_CLEAR(
+ tm->tsens_addr));
+ tm->sensor[i].thr_state.
+ crit_th_state = THERMAL_DEVICE_DISABLED;
+ }
+ spin_unlock_irqrestore(&tm->tsens_crit_lock, flags);
+ }
+
+ /* Mask critical interrupt */
+ mb();
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t tsens_tm_irq_thread(int irq, void *data)
+{
+ struct tsens_device *tm = data;
+ unsigned int i, status, threshold;
+ unsigned long flags;
+ void __iomem *sensor_status_addr;
+ void __iomem *sensor_int_mask_addr;
+ void __iomem *sensor_upper_lower_addr;
+ u32 addr_offset = 0;
+
+ sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_addr);
+ sensor_int_mask_addr =
+ TSENS_TM_UPPER_LOWER_INT_MASK(tm->tsens_addr);
+ sensor_upper_lower_addr =
+ TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tm->tsens_addr);
+
+ for (i = 0; i < tm->num_sensors; i++) {
+ bool upper_thr = false, lower_thr = false;
+ int int_mask, int_mask_val = 0;
+
+ spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
+ addr_offset = tm->sensor[i].hw_id *
+ TSENS_TM_SN_ADDR_OFFSET;
+ status = readl_relaxed(sensor_status_addr + addr_offset);
+ threshold = readl_relaxed(sensor_upper_lower_addr +
+ addr_offset);
+ int_mask = readl_relaxed(sensor_int_mask_addr);
+
+ if ((status & TSENS_TM_SN_STATUS_UPPER_STATUS) &&
+ !(int_mask &
+ (1 << (tm->sensor[i].hw_id + 16)))) {
+ int_mask = readl_relaxed(sensor_int_mask_addr);
+ int_mask_val = TSENS_TM_UPPER_INT_SET(
+ tm->sensor[i].hw_id);
+ /* Mask the corresponding interrupt for the sensors */
+ writel_relaxed(int_mask | int_mask_val,
+ TSENS_TM_UPPER_LOWER_INT_MASK(
+ tm->tsens_addr));
+ /* Clear the corresponding sensors interrupt */
+ writel_relaxed(int_mask_val,
+ TSENS_TM_UPPER_LOWER_INT_CLEAR(
+ tm->tsens_addr));
+ writel_relaxed(0,
+ TSENS_TM_UPPER_LOWER_INT_CLEAR(
+ tm->tsens_addr));
+ upper_thr = true;
+ tm->sensor[i].thr_state.
+ high_th_state = THERMAL_DEVICE_DISABLED;
+ }
+
+ if ((status & TSENS_TM_SN_STATUS_LOWER_STATUS) &&
+ !(int_mask &
+ (1 << tm->sensor[i].hw_id))) {
+ int_mask = readl_relaxed(sensor_int_mask_addr);
+ int_mask_val = (1 << tm->sensor[i].hw_id);
+ /* Mask the corresponding interrupt for the sensors */
+ writel_relaxed(int_mask | int_mask_val,
+ TSENS_TM_UPPER_LOWER_INT_MASK(
+ tm->tsens_addr));
+ /* Clear the corresponding sensors interrupt */
+ writel_relaxed(int_mask_val,
+ TSENS_TM_UPPER_LOWER_INT_CLEAR(
+ tm->tsens_addr));
+ writel_relaxed(0,
+ TSENS_TM_UPPER_LOWER_INT_CLEAR(
+ tm->tsens_addr));
+ lower_thr = true;
+ tm->sensor[i].thr_state.
+ low_th_state = THERMAL_DEVICE_DISABLED;
+ }
+ spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
+
+ if (upper_thr || lower_thr) {
+ int temp;
+ enum thermal_trip_type trip =
+ THERMAL_TRIP_CONFIGURABLE_LOW;
+
+ if (upper_thr)
+ trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ tsens2xxx_get_temp(&tm->sensor[i], &temp);
+ /* Use id for multiple controllers */
+ pr_debug("sensor:%d trigger temp (%d degC)\n",
+ tm->sensor[i].hw_id,
+ (status & TSENS_TM_SN_LAST_TEMP_MASK));
+ }
+ }
+
+ /* Disable monitoring sensor trip threshold for triggered sensor */
+ mb();
+
+ if (tm->ops->dbg)
+ tm->ops->dbg(tm, 0, TSENS_DBG_LOG_INTERRUPT_TIMESTAMP, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static int tsens2xxx_hw_init(struct tsens_device *tmdev)
+{
+ void __iomem *srot_addr;
+ void __iomem *sensor_int_mask_addr;
+ unsigned int srot_val;
+ int crit_mask;
+
+ srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_addr + 0x4);
+ srot_val = readl_relaxed(srot_addr);
+ if (!(srot_val & TSENS_EN)) {
+ pr_err("TSENS device is not enabled\n");
+ return -ENODEV;
+ }
+
+ if (tmdev->ctrl_data->cycle_monitor) {
+ sensor_int_mask_addr =
+ TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_addr);
+ crit_mask = readl_relaxed(sensor_int_mask_addr);
+ writel_relaxed(
+ crit_mask | tmdev->ctrl_data->cycle_compltn_monitor_val,
+ (TSENS_TM_CRITICAL_INT_MASK
+ (tmdev->tsens_addr)));
+ /*Update critical cycle monitoring*/
+ mb();
+ }
+ writel_relaxed(TSENS_TM_CRITICAL_INT_EN |
+ TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN,
+ TSENS_TM_INT_EN(tmdev->tsens_addr));
+
+ spin_lock_init(&tmdev->tsens_crit_lock);
+ spin_lock_init(&tmdev->tsens_upp_low_lock);
+
+ return 0;
+}
+
+static const struct tsens_irqs tsens2xxx_irqs[] = {
+ { "tsens-upper-lower", tsens_tm_irq_thread},
+ { "tsens-critical", tsens_tm_critical_irq_thread},
+};
+
+static int tsens2xxx_register_interrupts(struct tsens_device *tmdev)
+{
+ struct platform_device *pdev;
+ int i, rc;
+
+ if (!tmdev)
+ return -EINVAL;
+
+ pdev = tmdev->pdev;
+
+ for (i = 0; i < ARRAY_SIZE(tsens2xxx_irqs); i++) {
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, tsens2xxx_irqs[i].name);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq %s\n",
+ tsens2xxx_irqs[i].name);
+ return irq;
+ }
+
+ rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ tsens2xxx_irqs[i].handler,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ tsens2xxx_irqs[i].name, tmdev);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to get irq %s\n",
+ tsens2xxx_irqs[i].name);
+ return rc;
+ }
+ enable_irq_wake(irq);
+ }
+
+ return 0;
+}
+
+static const struct tsens_ops ops_tsens2xxx = {
+ .hw_init = tsens2xxx_hw_init,
+ .get_temp = tsens2xxx_get_temp,
+ .set_trip_temp = tsens2xxx_set_trip_temp,
+ .interrupts_reg = tsens2xxx_register_interrupts,
+ .dbg = tsens2xxx_dbg,
+};
+
+const struct tsens_data data_tsens2xxx = {
+ .cycle_monitor = false,
+ .cycle_compltn_monitor_val = 0,
+ .wd_bark = false,
+ .wd_bark_val = 0,
+ .ops = &ops_tsens2xxx,
+};
+
+const struct tsens_data data_tsens23xx = {
+ .cycle_monitor = true,
+ .cycle_compltn_monitor_val = 0,
+ .wd_bark = true,
+ .wd_bark_val = 0,
+ .ops = &ops_tsens2xxx,
+};
+
+const struct tsens_data data_tsens24xx = {
+ .cycle_monitor = true,
+ .cycle_compltn_monitor_val = 0,
+ .wd_bark = true,
+ .wd_bark_val = 1,
+ .ops = &ops_tsens2xxx,
+};
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index a6c1fae..a391b50 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1380,7 +1380,7 @@
dev_dbg(&intf->dev, "%s called\n", __func__);
- data = kmalloc(sizeof(*data), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -1443,6 +1443,13 @@
break;
}
}
+
+ if (!data->bulk_out || !data->bulk_in) {
+ dev_err(&intf->dev, "bulk endpoints not found\n");
+ retcode = -ENODEV;
+ goto err_put;
+ }
+
/* Find int endpoint */
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
endpoint = &iface_desc->endpoint[n].desc;
@@ -1468,8 +1475,10 @@
if (data->iin_ep_present) {
/* allocate int urb */
data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!data->iin_urb)
+ if (!data->iin_urb) {
+ retcode = -ENOMEM;
goto error_register;
+ }
/* will reference data in int urb */
kref_get(&data->kref);
@@ -1477,8 +1486,10 @@
/* allocate buffer for interrupt in */
data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
GFP_KERNEL);
- if (!data->iin_buffer)
+ if (!data->iin_buffer) {
+ retcode = -ENOMEM;
goto error_register;
+ }
/* fill interrupt urb */
usb_fill_int_urb(data->iin_urb, data->usb_dev,
@@ -1511,6 +1522,7 @@
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
usbtmc_free_int(data);
+err_put:
kref_put(&data->kref, usbtmc_delete);
return retcode;
}
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 1f7036c..eef716b 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -275,6 +275,16 @@
/*
* Adjust bInterval for quirked devices.
+ */
+ /*
+ * This quirk fixes bIntervals reported in ms.
+ */
+ if (to_usb_device(ddev)->quirks &
+ USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
+ n = clamp(fls(d->bInterval) + 3, i, j);
+ i = j = n;
+ }
+ /*
* This quirk fixes bIntervals reported in
* linear microframes.
*/
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 2c4bd54..53d730e 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2540,6 +2540,7 @@
}
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
/* Make sure that the other roothub is also deallocated. */
+ usb_atomic_notify_dead_bus(&hcd->self);
}
EXPORT_SYMBOL_GPL (usb_hc_died);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ffa53d8..c3d249f 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4279,7 +4279,7 @@
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
- if (!udev->usb2_hw_lpm_capable)
+ if (!udev->usb2_hw_lpm_capable || !udev->bos)
return;
if (hub)
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
index 7728c91..af91b1e 100644
--- a/drivers/usb/core/notify.c
+++ b/drivers/usb/core/notify.c
@@ -17,6 +17,7 @@
#include "usb.h"
static BLOCKING_NOTIFIER_HEAD(usb_notifier_list);
+static ATOMIC_NOTIFIER_HEAD(usb_atomic_notifier_list);
/**
* usb_register_notify - register a notifier callback whenever a usb change happens
@@ -67,3 +68,33 @@
{
blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
}
+
+/**
+ * usb_register_atomic_notify - register a atomic notifier callback whenever a
+ * HC dies
+ * @nb: pointer to the atomic notifier block for the callback events.
+ *
+ */
+void usb_register_atomic_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_register(&usb_atomic_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_register_atomic_notify);
+
+/**
+ * usb_unregister_atomic_notify - unregister a atomic notifier callback
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ */
+void usb_unregister_atomic_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&usb_atomic_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_unregister_atomic_notify);
+
+
+void usb_atomic_notify_dead_bus(struct usb_bus *ubus)
+{
+ atomic_notifier_call_chain(&usb_atomic_notifier_list, USB_BUS_DIED,
+ ubus);
+}
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 24f9f98..96b21b0 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -170,6 +170,14 @@
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Baum Vario Ultra */
+ { USB_DEVICE(0x0904, 0x6101), .driver_info =
+ USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+ { USB_DEVICE(0x0904, 0x6102), .driver_info =
+ USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+ { USB_DEVICE(0x0904, 0x6103), .driver_info =
+ USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+
/* Keytouch QWERTY Panel keyboard */
{ USB_DEVICE(0x0926, 0x3333), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 5331812..fbff25f 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -175,6 +175,7 @@
extern void usb_notify_remove_device(struct usb_device *udev);
extern void usb_notify_add_bus(struct usb_bus *ubus);
extern void usb_notify_remove_bus(struct usb_bus *ubus);
+extern void usb_atomic_notify_dead_bus(struct usb_bus *ubus);
extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
struct usb_hub_descriptor *desc);
diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index a30766c..5e3828d 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -535,13 +535,15 @@
{
struct usb_composite_dev *cdev = acm->port.func.config->cdev;
int status;
+ __le16 serial_state;
spin_lock(&acm->lock);
if (acm->notify_req) {
dev_dbg(&cdev->gadget->dev, "acm ttyGS%d serial state %04x\n",
acm->port_num, acm->serial_state);
+ serial_state = cpu_to_le16(acm->serial_state);
status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
- 0, &acm->serial_state, sizeof(acm->serial_state));
+ 0, &serial_state, sizeof(acm->serial_state));
} else {
acm->pending = true;
status = 0;
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 4d8694a..c6aa884 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -1425,6 +1425,7 @@
struct usb_request *req;
int i;
+ mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
while ((req = mtp_req_get(dev, &dev->tx_idle)))
mtp_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 29b41b5..c7689d0 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -625,7 +625,7 @@
uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
uvc_ss_streaming_comp.wBytesPerInterval =
cpu_to_le16(max_packet_size * max_packet_mult *
- opts->streaming_maxburst);
+ (opts->streaming_maxburst + 1));
/* Allocate endpoints. */
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 2975e80..9a67ae3 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -346,6 +346,9 @@
if (iface_desc->desc.bInterfaceClass != 0x0A)
return -ENODEV;
+ if (iface_desc->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL)
diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c
index 7717651..d3d1247 100644
--- a/drivers/usb/misc/lvstest.c
+++ b/drivers/usb/misc/lvstest.c
@@ -366,6 +366,10 @@
hdev = interface_to_usbdev(intf);
desc = intf->cur_altsetting;
+
+ if (desc->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
endpoint = &desc->endpoint[0].desc;
/* valid only for SS root hub */
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 356d312..9ff6652 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -708,6 +708,11 @@
interface = intf->cur_altsetting;
+ if (interface->desc.bNumEndpoints < 3) {
+ usb_put_dev(usbdev);
+ return -ENODEV;
+ }
+
/*
* Allocate parport interface
*/
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 338575f..358feca 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2467,8 +2467,8 @@
pm_runtime_get_sync(musb->controller);
musb_host_cleanup(musb);
musb_gadget_cleanup(musb);
- spin_lock_irqsave(&musb->lock, flags);
musb_platform_disable(musb);
+ spin_lock_irqsave(&musb->lock, flags);
musb_generic_disable(musb);
spin_unlock_irqrestore(&musb->lock, flags);
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index d4d7c56..cb443df 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -232,8 +232,27 @@
transferred < cppi41_channel->packet_sz)
cppi41_channel->prog_len = 0;
- if (cppi41_channel->is_tx)
- empty = musb_is_tx_fifo_empty(hw_ep);
+ if (cppi41_channel->is_tx) {
+ u8 type;
+
+ if (is_host_active(musb))
+ type = hw_ep->out_qh->type;
+ else
+ type = hw_ep->ep_in.type;
+
+ if (type == USB_ENDPOINT_XFER_ISOC)
+ /*
+ * Don't use the early-TX-interrupt workaround below
+ * for Isoch transfter. Since Isoch are periodic
+ * transfer, by the time the next transfer is
+ * scheduled, the current one should be done already.
+ *
+ * This avoids audio playback underrun issue.
+ */
+ empty = true;
+ else
+ empty = musb_is_tx_fifo_empty(hw_ep);
+ }
if (!cppi41_channel->is_tx || empty) {
cppi41_trans_done(cppi41_channel);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 42cc72e..af67a0d 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -233,6 +233,14 @@
#define BANDRICH_PRODUCT_1012 0x1012
#define QUALCOMM_VENDOR_ID 0x05C6
+/* These Quectel products use Qualcomm's vendor ID */
+#define QUECTEL_PRODUCT_UC20 0x9003
+#define QUECTEL_PRODUCT_UC15 0x9090
+
+#define QUECTEL_VENDOR_ID 0x2c7c
+/* These Quectel products use Quectel's vendor ID */
+#define QUECTEL_PRODUCT_EC21 0x0121
+#define QUECTEL_PRODUCT_EC25 0x0125
#define CMOTECH_VENDOR_ID 0x16d8
#define CMOTECH_PRODUCT_6001 0x6001
@@ -1161,7 +1169,14 @@
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
- { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9003), /* Quectel UC20 */
+ /* Quectel products using Qualcomm vendor ID */
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ /* Quectel products using Quectel vendor ID */
+ { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 696458d..38b3f0d 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -169,6 +169,8 @@
{DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81b1)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81b3)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
+ {DEVICE_SWI(0x413c, 0x81b5)}, /* Dell Wireless 5811e QDL */
+ {DEVICE_SWI(0x413c, 0x81b6)}, /* Dell Wireless 5811e QDL */
/* Huawei devices */
{DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
index 252c7bd..d01496f 100644
--- a/drivers/usb/wusbcore/wa-hc.c
+++ b/drivers/usb/wusbcore/wa-hc.c
@@ -39,6 +39,9 @@
int result;
struct device *dev = &iface->dev;
+ if (iface->cur_altsetting->desc.bNumEndpoints < 3)
+ return -ENODEV;
+
result = wa_rpipes_create(wa);
if (result < 0)
goto error_rpipes_create;
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
index 0aa6c3c..35a1e77 100644
--- a/drivers/uwb/hwa-rc.c
+++ b/drivers/uwb/hwa-rc.c
@@ -823,6 +823,9 @@
struct hwarc *hwarc;
struct device *dev = &iface->dev;
+ if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
result = -ENOMEM;
uwb_rc = uwb_rc_alloc();
if (uwb_rc == NULL) {
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c
index 2bfc846..6345e85 100644
--- a/drivers/uwb/i1480/dfu/usb.c
+++ b/drivers/uwb/i1480/dfu/usb.c
@@ -362,6 +362,9 @@
result);
}
+ if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+ return -ENODEV;
+
result = -ENOMEM;
i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
if (i1480_usb == NULL) {
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index b87f5cf..4db10d7 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1167,6 +1167,8 @@
p->userfont = 0;
}
+static void set_vc_hi_font(struct vc_data *vc, bool set);
+
static void fbcon_deinit(struct vc_data *vc)
{
struct display *p = &fb_display[vc->vc_num];
@@ -1202,6 +1204,9 @@
if (free_font)
vc->vc_font.data = NULL;
+ if (vc->vc_hi_font_mask)
+ set_vc_hi_font(vc, false);
+
if (!con_is_bound(&fb_con))
fbcon_exit();
@@ -2438,32 +2443,10 @@
return 0;
}
-static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
- const u8 * data, int userfont)
+/* set/clear vc_hi_font_mask and update vc attrs accordingly */
+static void set_vc_hi_font(struct vc_data *vc, bool set)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
- struct fbcon_ops *ops = info->fbcon_par;
- struct display *p = &fb_display[vc->vc_num];
- int resize;
- int cnt;
- char *old_data = NULL;
-
- if (con_is_visible(vc) && softback_lines)
- fbcon_set_origin(vc);
-
- resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
- if (p->userfont)
- old_data = vc->vc_font.data;
- if (userfont)
- cnt = FNTCHARCNT(data);
- else
- cnt = 256;
- vc->vc_font.data = (void *)(p->fontdata = data);
- if ((p->userfont = userfont))
- REFCOUNT(data)++;
- vc->vc_font.width = w;
- vc->vc_font.height = h;
- if (vc->vc_hi_font_mask && cnt == 256) {
+ if (!set) {
vc->vc_hi_font_mask = 0;
if (vc->vc_can_do_color) {
vc->vc_complement_mask >>= 1;
@@ -2486,7 +2469,7 @@
((c & 0xfe00) >> 1) | (c & 0xff);
vc->vc_attr >>= 1;
}
- } else if (!vc->vc_hi_font_mask && cnt == 512) {
+ } else {
vc->vc_hi_font_mask = 0x100;
if (vc->vc_can_do_color) {
vc->vc_complement_mask <<= 1;
@@ -2518,8 +2501,38 @@
} else
vc->vc_video_erase_char = c & ~0x100;
}
-
}
+}
+
+static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
+ const u8 * data, int userfont)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct display *p = &fb_display[vc->vc_num];
+ int resize;
+ int cnt;
+ char *old_data = NULL;
+
+ if (con_is_visible(vc) && softback_lines)
+ fbcon_set_origin(vc);
+
+ resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
+ if (p->userfont)
+ old_data = vc->vc_font.data;
+ if (userfont)
+ cnt = FNTCHARCNT(data);
+ else
+ cnt = 256;
+ vc->vc_font.data = (void *)(p->fontdata = data);
+ if ((p->userfont = userfont))
+ REFCOUNT(data)++;
+ vc->vc_font.width = w;
+ vc->vc_font.height = h;
+ if (vc->vc_hi_font_mask && cnt == 256)
+ set_vc_hi_font(vc, false);
+ else if (!vc->vc_hi_font_mask && cnt == 512)
+ set_vc_hi_font(vc, true);
if (resize) {
int cols, rows;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 9d2738e..2c2e679 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -427,6 +427,8 @@
* Prime this virtqueue with one buffer so the hypervisor can
* use it to signal us later (it can't be broken yet!).
*/
+ update_balloon_stats(vb);
+
sg_init_one(&sg, vb->stats, sizeof vb->stats);
if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
< 0)
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index 4ce10bc..4b85746 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -27,10 +27,10 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/syscore_ops.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
#include <xen/xen.h>
-#include <xen/xen-ops.h>
#include <xen/interface/platform.h>
#include <asm/xen/hypercall.h>
@@ -466,15 +466,33 @@
return rc;
}
-static int xen_acpi_processor_resume(struct notifier_block *nb,
- unsigned long action, void *data)
+static void xen_acpi_processor_resume_worker(struct work_struct *dummy)
{
+ int rc;
+
bitmap_zero(acpi_ids_done, nr_acpi_bits);
- return xen_upload_processor_pm_data();
+
+ rc = xen_upload_processor_pm_data();
+ if (rc != 0)
+ pr_info("ACPI data upload failed, error = %d\n", rc);
}
-struct notifier_block xen_acpi_processor_resume_nb = {
- .notifier_call = xen_acpi_processor_resume,
+static void xen_acpi_processor_resume(void)
+{
+ static DECLARE_WORK(wq, xen_acpi_processor_resume_worker);
+
+ /*
+ * xen_upload_processor_pm_data() calls non-atomic code.
+ * However, the context for xen_acpi_processor_resume is syscore
+ * with only the boot CPU online and in an atomic context.
+ *
+ * So defer the upload for some point safer.
+ */
+ schedule_work(&wq);
+}
+
+static struct syscore_ops xap_syscore_ops = {
+ .resume = xen_acpi_processor_resume,
};
static int __init xen_acpi_processor_init(void)
@@ -527,7 +545,7 @@
if (rc)
goto err_unregister;
- xen_resume_notifier_register(&xen_acpi_processor_resume_nb);
+ register_syscore_ops(&xap_syscore_ops);
return 0;
err_unregister:
@@ -544,7 +562,7 @@
{
int i;
- xen_resume_notifier_unregister(&xen_acpi_processor_resume_nb);
+ unregister_syscore_ops(&xap_syscore_ops);
kfree(acpi_ids_done);
kfree(acpi_id_present);
kfree(acpi_id_cst_present);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 98f87fe..61cfcce 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -352,7 +352,6 @@
static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
{
struct dentry *dir;
- struct fscrypt_info *ci;
int dir_has_key, cached_with_key;
if (flags & LOOKUP_RCU)
@@ -364,18 +363,11 @@
return 0;
}
- ci = d_inode(dir)->i_crypt_info;
- if (ci && ci->ci_keyring_key &&
- (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
- (1 << KEY_FLAG_REVOKED) |
- (1 << KEY_FLAG_DEAD))))
- ci = NULL;
-
/* this should eventually be an flag in d_flags */
spin_lock(&dentry->d_lock);
cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
spin_unlock(&dentry->d_lock);
- dir_has_key = (ci != NULL);
+ dir_has_key = (d_inode(dir)->i_crypt_info != NULL);
dput(dir);
/*
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index 9b774f4..80bb956 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -350,7 +350,7 @@
fname->disk_name.len = iname->len;
return 0;
}
- ret = get_crypt_info(dir);
+ ret = fscrypt_get_encryption_info(dir);
if (ret && ret != -EOPNOTSUPP)
return ret;
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index 67fb6d8..bb46063 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -99,6 +99,7 @@
kfree(full_key_descriptor);
if (IS_ERR(keyring_key))
return PTR_ERR(keyring_key);
+ down_read(&keyring_key->sem);
if (keyring_key->type != &key_type_logon) {
printk_once(KERN_WARNING
@@ -106,11 +107,9 @@
res = -ENOKEY;
goto out;
}
- down_read(&keyring_key->sem);
ukp = user_key_payload(keyring_key);
if (ukp->datalen != sizeof(struct fscrypt_key)) {
res = -EINVAL;
- up_read(&keyring_key->sem);
goto out;
}
master_key = (struct fscrypt_key *)ukp->data;
@@ -121,17 +120,11 @@
"%s: key size incorrect: %d\n",
__func__, master_key->size);
res = -ENOKEY;
- up_read(&keyring_key->sem);
goto out;
}
res = derive_key_aes(ctx->nonce, master_key->raw, raw_key);
- up_read(&keyring_key->sem);
- if (res)
- goto out;
-
- crypt_info->ci_keyring_key = keyring_key;
- return 0;
out:
+ up_read(&keyring_key->sem);
key_put(keyring_key);
return res;
}
@@ -173,12 +166,11 @@
if (!ci)
return;
- key_put(ci->ci_keyring_key);
crypto_free_skcipher(ci->ci_ctfm);
kmem_cache_free(fscrypt_info_cachep, ci);
}
-int get_crypt_info(struct inode *inode)
+int fscrypt_get_encryption_info(struct inode *inode)
{
struct fscrypt_info *crypt_info;
struct fscrypt_context ctx;
@@ -188,21 +180,15 @@
u8 *raw_key = NULL;
int res;
+ if (inode->i_crypt_info)
+ return 0;
+
res = fscrypt_initialize();
if (res)
return res;
if (!inode->i_sb->s_cop->get_context)
return -EOPNOTSUPP;
-retry:
- crypt_info = ACCESS_ONCE(inode->i_crypt_info);
- if (crypt_info) {
- if (!crypt_info->ci_keyring_key ||
- key_validate(crypt_info->ci_keyring_key) == 0)
- return 0;
- fscrypt_put_encryption_info(inode, crypt_info);
- goto retry;
- }
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
if (res < 0) {
@@ -230,7 +216,6 @@
crypt_info->ci_data_mode = ctx.contents_encryption_mode;
crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
crypt_info->ci_ctfm = NULL;
- crypt_info->ci_keyring_key = NULL;
memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
sizeof(crypt_info->ci_master_key));
@@ -285,14 +270,8 @@
if (res)
goto out;
- kzfree(raw_key);
- raw_key = NULL;
- if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
- put_crypt_info(crypt_info);
- goto retry;
- }
- return 0;
-
+ if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL)
+ crypt_info = NULL;
out:
if (res == -ENOKEY)
res = 0;
@@ -300,6 +279,7 @@
kzfree(raw_key);
return res;
}
+EXPORT_SYMBOL(fscrypt_get_encryption_info);
void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
{
@@ -317,17 +297,3 @@
put_crypt_info(ci);
}
EXPORT_SYMBOL(fscrypt_put_encryption_info);
-
-int fscrypt_get_encryption_info(struct inode *inode)
-{
- struct fscrypt_info *ci = inode->i_crypt_info;
-
- if (!ci ||
- (ci->ci_keyring_key &&
- (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
- (1 << KEY_FLAG_REVOKED) |
- (1 << KEY_FLAG_DEAD)))))
- return get_crypt_info(inode);
- return 0;
-}
-EXPORT_SYMBOL(fscrypt_get_encryption_info);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 004eebb..a5807fd 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1171,10 +1171,9 @@
set_buffer_uptodate(dir_block);
err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
if (err)
- goto out;
+ return err;
set_buffer_verified(dir_block);
-out:
- return err;
+ return ext4_mark_inode_dirty(handle, inode);
}
static int ext4_convert_inline_data_nolock(handle_t *handle,
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 4448ed3..3eeed8f 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -131,31 +131,26 @@
}
static int ext4_xattr_block_csum_verify(struct inode *inode,
- sector_t block_nr,
- struct ext4_xattr_header *hdr)
+ struct buffer_head *bh)
{
- if (ext4_has_metadata_csum(inode->i_sb) &&
- (hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr)))
- return 0;
- return 1;
+ struct ext4_xattr_header *hdr = BHDR(bh);
+ int ret = 1;
+
+ if (ext4_has_metadata_csum(inode->i_sb)) {
+ lock_buffer(bh);
+ ret = (hdr->h_checksum == ext4_xattr_block_csum(inode,
+ bh->b_blocknr, hdr));
+ unlock_buffer(bh);
+ }
+ return ret;
}
static void ext4_xattr_block_csum_set(struct inode *inode,
- sector_t block_nr,
- struct ext4_xattr_header *hdr)
+ struct buffer_head *bh)
{
- if (!ext4_has_metadata_csum(inode->i_sb))
- return;
-
- hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr);
-}
-
-static inline int ext4_handle_dirty_xattr_block(handle_t *handle,
- struct inode *inode,
- struct buffer_head *bh)
-{
- ext4_xattr_block_csum_set(inode, bh->b_blocknr, BHDR(bh));
- return ext4_handle_dirty_metadata(handle, inode, bh);
+ if (ext4_has_metadata_csum(inode->i_sb))
+ BHDR(bh)->h_checksum = ext4_xattr_block_csum(inode,
+ bh->b_blocknr, BHDR(bh));
}
static inline const struct xattr_handler *
@@ -218,7 +213,7 @@
if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
BHDR(bh)->h_blocks != cpu_to_le32(1))
return -EFSCORRUPTED;
- if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
+ if (!ext4_xattr_block_csum_verify(inode, bh))
return -EFSBADCRC;
error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
bh->b_data);
@@ -601,23 +596,22 @@
}
}
+ ext4_xattr_block_csum_set(inode, bh);
/*
* Beware of this ugliness: Releasing of xattr block references
* from different inodes can race and so we have to protect
* from a race where someone else frees the block (and releases
* its journal_head) before we are done dirtying the buffer. In
* nojournal mode this race is harmless and we actually cannot
- * call ext4_handle_dirty_xattr_block() with locked buffer as
+ * call ext4_handle_dirty_metadata() with locked buffer as
* that function can call sync_dirty_buffer() so for that case
* we handle the dirtying after unlocking the buffer.
*/
if (ext4_handle_valid(handle))
- error = ext4_handle_dirty_xattr_block(handle, inode,
- bh);
+ error = ext4_handle_dirty_metadata(handle, inode, bh);
unlock_buffer(bh);
if (!ext4_handle_valid(handle))
- error = ext4_handle_dirty_xattr_block(handle, inode,
- bh);
+ error = ext4_handle_dirty_metadata(handle, inode, bh);
if (IS_SYNC(inode))
ext4_handle_sync(handle);
dquot_free_block(inode, EXT4_C2B(EXT4_SB(inode->i_sb), 1));
@@ -846,13 +840,14 @@
ext4_xattr_cache_insert(ext4_mb_cache,
bs->bh);
}
+ ext4_xattr_block_csum_set(inode, bs->bh);
unlock_buffer(bs->bh);
if (error == -EFSCORRUPTED)
goto bad_block;
if (!error)
- error = ext4_handle_dirty_xattr_block(handle,
- inode,
- bs->bh);
+ error = ext4_handle_dirty_metadata(handle,
+ inode,
+ bs->bh);
if (error)
goto cleanup;
goto inserted;
@@ -950,10 +945,11 @@
ce->e_reusable = 0;
ea_bdebug(new_bh, "reusing; refcount now=%d",
ref);
+ ext4_xattr_block_csum_set(inode, new_bh);
unlock_buffer(new_bh);
- error = ext4_handle_dirty_xattr_block(handle,
- inode,
- new_bh);
+ error = ext4_handle_dirty_metadata(handle,
+ inode,
+ new_bh);
if (error)
goto cleanup_dquot;
}
@@ -1003,11 +999,12 @@
goto getblk_failed;
}
memcpy(new_bh->b_data, s->base, new_bh->b_size);
+ ext4_xattr_block_csum_set(inode, new_bh);
set_buffer_uptodate(new_bh);
unlock_buffer(new_bh);
ext4_xattr_cache_insert(ext4_mb_cache, new_bh);
- error = ext4_handle_dirty_xattr_block(handle,
- inode, new_bh);
+ error = ext4_handle_dirty_metadata(handle, inode,
+ new_bh);
if (error)
goto cleanup;
}
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 927da49..7d4b557 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1125,10 +1125,8 @@
/* Set up a default-sized revoke table for the new mount. */
err = jbd2_journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH);
- if (err) {
- kfree(journal);
- return NULL;
- }
+ if (err)
+ goto err_cleanup;
spin_lock_init(&journal->j_history_lock);
@@ -1145,23 +1143,25 @@
journal->j_wbufsize = n;
journal->j_wbuf = kmalloc_array(n, sizeof(struct buffer_head *),
GFP_KERNEL);
- if (!journal->j_wbuf) {
- kfree(journal);
- return NULL;
- }
+ if (!journal->j_wbuf)
+ goto err_cleanup;
bh = getblk_unmovable(journal->j_dev, start, journal->j_blocksize);
if (!bh) {
pr_err("%s: Cannot get buffer for journal superblock\n",
__func__);
- kfree(journal->j_wbuf);
- kfree(journal);
- return NULL;
+ goto err_cleanup;
}
journal->j_sb_buffer = bh;
journal->j_superblock = (journal_superblock_t *)bh->b_data;
return journal;
+
+err_cleanup:
+ kfree(journal->j_wbuf);
+ jbd2_journal_destroy_revoke(journal);
+ kfree(journal);
+ return NULL;
}
/* jbd2_journal_init_dev and jbd2_journal_init_inode:
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index 91171dc..3cd7305 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -280,6 +280,7 @@
fail1:
jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
+ journal->j_revoke_table[0] = NULL;
fail0:
return -ENOMEM;
}
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 6726440..e9fb2e8 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -361,6 +361,7 @@
/* Event queued up for userspace to read */
struct drm_pending_event {
struct completion *completion;
+ void (*completion_release)(struct completion *completion);
struct drm_event *event;
struct fence *fence;
struct list_head link;
diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
index 41eb823..13de1e1 100644
--- a/include/dt-bindings/clock/qcom,gpucc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * 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
@@ -14,42 +14,42 @@
#ifndef _DT_BINDINGS_CLK_MSM_GPU_CC_SDM845_H
#define _DT_BINDINGS_CLK_MSM_GPU_CC_SDM845_H
+/* GPUCC clock registers */
#define GPU_CC_ACD_AHB_CLK 0
#define GPU_CC_ACD_CXO_CLK 1
-#define GPU_CC_AHB_CLK 2
+#define GPU_CC_AHB_CLK 2
#define GPU_CC_CRC_AHB_CLK 3
#define GPU_CC_CX_APB_CLK 4
-#define GPU_CC_CX_GFX3D_CLK 5
-#define GPU_CC_CX_GFX3D_SLV_CLK 6
-#define GPU_CC_CX_GMU_CLK 7
-#define GPU_CC_CX_QDSS_AT_CLK 8
-#define GPU_CC_CX_QDSS_TRIG_CLK 9
-#define GPU_CC_CX_QDSS_TSCTR_CLK 10
-#define GPU_CC_CX_SNOC_DVM_CLK 11
-#define GPU_CC_CXO_AON_CLK 12
-#define GPU_CC_CXO_CLK 13
-#define GPU_CC_DEBUG_CLK 14
-#define GPU_CC_GX_CXO_CLK 15
-#define GPU_CC_GX_GMU_CLK 16
-#define GPU_CC_GX_QDSS_TSCTR_CLK 17
-#define GPU_CC_GX_VSENSE_CLK 18
-#define GPU_CC_PLL0 19
-#define GPU_CC_PLL0_OUT_EVEN 20
-#define GPU_CC_PLL0_OUT_MAIN 21
-#define GPU_CC_PLL0_OUT_ODD 22
-#define GPU_CC_PLL0_OUT_TEST 23
-#define GPU_CC_PLL1 24
-#define GPU_CC_PLL1_OUT_EVEN 25
-#define GPU_CC_PLL1_OUT_MAIN 26
-#define GPU_CC_PLL1_OUT_ODD 27
-#define GPU_CC_PLL1_OUT_TEST 28
-#define GPU_CC_PLL_TEST_CLK 29
-#define GPU_CC_RBCPR_AHB_CLK 30
-#define GPU_CC_RBCPR_CLK 31
-#define GPU_CC_RBCPR_CLK_SRC 32
-#define GPU_CC_SLEEP_CLK 33
-#define GPU_CC_SPDM_GX_GFX3D_DIV_CLK 34
+#define GPU_CC_CX_GMU_CLK 5
+#define GPU_CC_CX_QDSS_AT_CLK 6
+#define GPU_CC_CX_QDSS_TRIG_CLK 7
+#define GPU_CC_CX_QDSS_TSCTR_CLK 8
+#define GPU_CC_CX_SNOC_DVM_CLK 9
+#define GPU_CC_CXO_AON_CLK 10
+#define GPU_CC_CXO_CLK 11
+#define GPU_CC_DEBUG_CLK 12
+#define GPU_CC_GX_CXO_CLK 13
+#define GPU_CC_GX_GMU_CLK 14
+#define GPU_CC_GX_QDSS_TSCTR_CLK 15
+#define GPU_CC_GX_VSENSE_CLK 16
+#define GPU_CC_PLL0_OUT_MAIN 17
+#define GPU_CC_PLL0_OUT_ODD 18
+#define GPU_CC_PLL0_OUT_TEST 19
+#define GPU_CC_PLL1 20
+#define GPU_CC_PLL1_OUT_EVEN 21
+#define GPU_CC_PLL1_OUT_MAIN 22
+#define GPU_CC_PLL1_OUT_ODD 23
+#define GPU_CC_PLL1_OUT_TEST 24
+#define GPU_CC_PLL_TEST_CLK 25
+#define GPU_CC_RBCPR_AHB_CLK 26
+#define GPU_CC_RBCPR_CLK 27
+#define GPU_CC_RBCPR_CLK_SRC 28
+#define GPU_CC_SLEEP_CLK 29
+#define GPU_CC_GMU_CLK_SRC 30
+#define GPU_CC_CX_GFX3D_CLK 31
+#define GPU_CC_CX_GFX3D_SLV_CLK 32
+/* GPUCC reset clock registers */
#define GPUCC_GPU_CC_ACD_BCR 0
#define GPUCC_GPU_CC_CX_BCR 1
#define GPUCC_GPU_CC_GFX3D_AON_BCR 2
@@ -59,4 +59,9 @@
#define GPUCC_GPU_CC_SPDM_BCR 6
#define GPUCC_GPU_CC_XO_BCR 7
+/* GFX3D clock registers */
+#define GPU_CC_PLL0 0
+#define GPU_CC_PLL0_OUT_EVEN 1
+#define GPU_CC_GX_GFX3D_CLK_SRC 2
+#define GPU_CC_GX_GFX3D_CLK 3
#endif
diff --git a/include/linux/ccp.h b/include/linux/ccp.h
index a765333..edc5d04 100644
--- a/include/linux/ccp.h
+++ b/include/linux/ccp.h
@@ -556,7 +556,7 @@
* struct ccp_cmd - CPP operation request
* @entry: list element (ccp driver use only)
* @work: work element used for callbacks (ccp driver use only)
- * @ccp: CCP device to be run on (ccp driver use only)
+ * @ccp: CCP device to be run on
* @ret: operation return code (ccp driver use only)
* @flags: cmd processing flags
* @engine: CCP operation to perform
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index c156f50..4fa2623 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -30,6 +30,11 @@
typedef int (*get_static_t)(cpumask_t *cpumask, int interval,
unsigned long voltage, u32 *power);
+typedef int (*plat_mitig_t)(int cpu, u32 clip_freq);
+
+struct cpu_cooling_ops {
+ plat_mitig_t ceil_limit, floor_limit;
+};
#ifdef CONFIG_CPU_THERMAL
/**
@@ -43,6 +48,10 @@
cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
u32 capacitance, get_static_t plat_static_func);
+struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+ struct cpu_cooling_ops *ops);
+
/**
* of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
* @np: a valid struct device_node to the cooling device device tree node.
@@ -112,6 +121,13 @@
return NULL;
}
+static inline struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+ struct cpu_cooling_ops *ops)
+{
+ return NULL;
+}
+
static inline
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
{
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
index ff8b11b..f6dfc29 100644
--- a/include/linux/fscrypto.h
+++ b/include/linux/fscrypto.h
@@ -79,7 +79,6 @@
u8 ci_filename_mode;
u8 ci_flags;
struct crypto_skcipher *ci_ctfm;
- struct key *ci_keyring_key;
u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
};
@@ -256,7 +255,6 @@
extern int fscrypt_inherit_context(struct inode *, struct inode *,
void *, bool);
/* keyinfo.c */
-extern int get_crypt_info(struct inode *);
extern int fscrypt_get_encryption_info(struct inode *);
extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
diff --git a/include/linux/iio/sw_device.h b/include/linux/iio/sw_device.h
index 23ca415..fa79319 100644
--- a/include/linux/iio/sw_device.h
+++ b/include/linux/iio/sw_device.h
@@ -62,7 +62,7 @@
const char *name,
struct config_item_type *type)
{
-#ifdef CONFIG_CONFIGFS_FS
+#if IS_ENABLED(CONFIG_CONFIGFS_FS)
config_group_init_type_name(&d->group, name, type);
#endif
}
diff --git a/include/linux/mailbox/qmp.h b/include/linux/mailbox/qmp.h
new file mode 100644
index 0000000..df3565b
--- /dev/null
+++ b/include/linux/mailbox/qmp.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 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 _QMP_H_
+#define _QMP_H_
+
+#include <linux/types.h>
+
+/**
+ * struct qmp_pkt - Packet structure to be used for TX and RX with QMP
+ * @size size of data
+ * @data Buffer holding data of this packet
+ */
+struct qmp_pkt {
+ u32 size;
+ void *data;
+};
+
+#endif /* _QMP_H_ */
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 8a507d2..c6c8d24 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -334,6 +334,7 @@
struct slim_device *slim_slave;
struct mutex io_lock;
struct mutex xfer_lock;
+ struct mutex reset_lock;
u8 version;
int reset_gpio;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 510a73a..d265f60 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -273,6 +273,7 @@
/* for byte mode */
#define MMC_QUIRK_NONSTD_SDIO (1<<2) /* non-standard SDIO card attached */
/* (missing CIA registers) */
+#define MMC_QUIRK_BROKEN_CLK_GATING (1<<3) /* clock gating the sdio bus will make card fail */
#define MMC_QUIRK_NONSTD_FUNC_IF (1<<4) /* SDIO card has nonstd function interfaces */
#define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */
#define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index fac3b5c..b7b92bf 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -316,6 +316,18 @@
mmc_pm_flag_t pm_caps; /* supported pm features */
+#ifdef CONFIG_MMC_CLKGATE
+ int clk_requests; /* internal reference counter */
+ unsigned int clk_delay; /* number of MCI clk hold cycles */
+ bool clk_gated; /* clock gated */
+ struct delayed_work clk_gate_work; /* delayed clock gate */
+ unsigned int clk_old; /* old clock value cache */
+ spinlock_t clk_lock; /* lock for clk fields */
+ struct mutex clk_gate_mutex; /* mutex for clock gating */
+ struct device_attribute clkgate_delay_attr;
+ unsigned long clkgate_delay;
+#endif
+
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_segs; /* see blk_queue_max_segments */
@@ -523,6 +535,26 @@
return host->caps2 & MMC_CAP2_PACKED_WR;
}
+#ifdef CONFIG_MMC_CLKGATE
+void mmc_host_clk_hold(struct mmc_host *host);
+void mmc_host_clk_release(struct mmc_host *host);
+unsigned int mmc_host_clk_rate(struct mmc_host *host);
+
+#else
+static inline void mmc_host_clk_hold(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_release(struct mmc_host *host)
+{
+}
+
+static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
+{
+ return host->ios.clock;
+}
+#endif
+
static inline int mmc_card_hs(struct mmc_card *card)
{
return card->host->ios.timing == MMC_TIMING_SD_HS ||
diff --git a/include/linux/qdsp6v2/apr_tal.h b/include/linux/qdsp6v2/apr_tal.h
index 32c977f..bac5e90 100644
--- a/include/linux/qdsp6v2/apr_tal.h
+++ b/include/linux/qdsp6v2/apr_tal.h
@@ -32,7 +32,6 @@
#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
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
new file mode 100644
index 0000000..60cc768
--- /dev/null
+++ b/include/linux/sde_rsc.h
@@ -0,0 +1,245 @@
+/* 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 _SDE_RSC_H_
+#define _SDE_RSC_H_
+
+#include <linux/kernel.h>
+
+/* primary display rsc index */
+#define SDE_RSC_INDEX 0
+
+#define MAX_RSC_CLIENT_NAME_LEN 128
+
+/**
+ * event will be triggered before sde core power collapse,
+ * mdss gdsc is still on
+ */
+#define SDE_RSC_EVENT_PRE_CORE_PC 0x1
+/**
+ * event will be triggered after sde core collapse complete,
+ * mdss gdsc is off now
+ */
+#define SDE_RSC_EVENT_POST_CORE_PC 0x2
+/**
+ * event will be triggered before restoring the sde core from power collapse,
+ * mdss gdsc is still off
+ */
+#define SDE_RSC_EVENT_PRE_CORE_RESTORE 0x4
+/**
+ * event will be triggered after restoring the sde core from power collapse,
+ * mdss gdsc is on now
+ */
+#define SDE_RSC_EVENT_POST_CORE_RESTORE 0x8
+/**
+ * event attached with solver state enabled
+ * all clients in clk_state or cmd_state
+ */
+#define SDE_RSC_EVENT_SOLVER_ENABLED 0x10
+/**
+ * event attached with solver state disabled
+ * one of the client requested for vid state
+ */
+#define SDE_RSC_EVENT_SOLVER_DISABLED 0x20
+
+/**
+ * sde_rsc_state: sde rsc state information
+ * SDE_RSC_IDLE_STATE: A client requests for idle state when there is no
+ * pixel or cmd transfer expected. An idle vote from
+ * all clients lead to power collapse state.
+ * SDE_RSC_CLK_STATE: A client requests for clk state when it wants to
+ * only avoid mode-2 entry/exit. For ex: V4L2 driver,
+ * sde power handle, etc.
+ * SDE_RSC_CMD_STATE: A client requests for cmd state when it wants to
+ * enable the solver mode.
+ * SDE_RSC_VID_STATE: A client requests for vid state it wants to avoid
+ * solver enable because client is fetching data from
+ * continuously.
+ */
+enum sde_rsc_state {
+ SDE_RSC_IDLE_STATE,
+ SDE_RSC_CLK_STATE,
+ SDE_RSC_CMD_STATE,
+ SDE_RSC_VID_STATE,
+};
+
+/**
+ * struct sde_rsc_client: stores the rsc client for sde driver
+ * @name: name of the client
+ * @current_state: current client state
+ * @crtc_id: crtc_id associated with this rsc client.
+ * @rsc_index: rsc index of a client - only index "0" valid.
+ * @list: list to attach client master list
+ */
+struct sde_rsc_client {
+ char name[MAX_RSC_CLIENT_NAME_LEN];
+ short current_state;
+ int crtc_id;
+ u32 rsc_index;
+ struct list_head list;
+};
+
+/**
+ * struct sde_rsc_event: local event registration entry structure
+ * @cb_func: Pointer to desired callback function
+ * @usr: User pointer to pass to callback on event trigger
+ * @rsc_index: rsc index of a client - only index "0" valid.
+ * @event_type: refer comments in event_register
+ * @list: list to attach event master list
+ */
+struct sde_rsc_event {
+ void (*cb_func)(uint32_t event_type, void *usr);
+ void *usr;
+ u32 rsc_index;
+ uint32_t event_type;
+ struct list_head list;
+};
+
+/**
+ * struct sde_rsc_cmd_config: provides panel configuration to rsc
+ * when client is command mode. It is not required to set it during
+ * video mode.
+ *
+ * @fps: panel te interval
+ * @vtotal: current vertical total (height + vbp + vfp)
+ * @jitter: panel can set the jitter to wake up rsc/solver early
+ * This value causes mdp core to exit certain mode
+ * early. Default is 10% jitter
+ * @prefill_lines: max prefill lines based on panel
+ */
+struct sde_rsc_cmd_config {
+ u32 fps;
+ u32 vtotal;
+ u32 jitter;
+ u32 prefill_lines;
+};
+
+#ifdef CONFIG_DRM_SDE_RSC
+/**
+ * sde_rsc_client_create() - create the client for sde rsc.
+ * Different displays like DSI, HDMI, DP, WB, etc should call this
+ * api to register their vote for rpmh. They still need to vote for
+ * power handle to get the clocks.
+
+ * @rsc_index: A client will be created on this RSC. As of now only
+ * SDE_RSC_INDEX is valid rsc index.
+ * @name: Caller needs to provide some valid string to identify
+ * the client. "primary", "dp", "hdmi" are suggested name.
+ * @is_primary: Caller needs to provide information if client is primary
+ * or not. Primary client votes will be redirected to
+ * display rsc.
+ * @config: fps, vtotal, porches, etc configuration for command mode
+ * panel
+ *
+ * Return: client node pointer.
+ */
+struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *name,
+ bool is_primary_display);
+
+/**
+ * sde_rsc_client_destroy() - Destroy the sde rsc client.
+ *
+ * @client: Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: none
+ */
+void sde_rsc_client_destroy(struct sde_rsc_client *client);
+
+/**
+ * sde_rsc_client_state_update() - rsc client state update
+ * Video mode, cmd mode and clk state are supported as modes. A client need to
+ * set this property during panel time. A switching client can set the
+ * property to change the state
+ *
+ * @client: Client pointer provided by sde_rsc_client_create().
+ * @state: Client state - video/cmd
+ * @config: fps, vtotal, porches, etc configuration for command mode
+ * panel
+ * @crtc_id: current client's crtc id
+ *
+ * Return: error code.
+ */
+int sde_rsc_client_state_update(struct sde_rsc_client *client,
+ enum sde_rsc_state state,
+ struct sde_rsc_cmd_config *config, int crtc_id);
+
+/**
+ * sde_rsc_client_vote() - ab/ib vote from rsc client
+ *
+ * @client: Client pointer provided by sde_rsc_client_create().
+ * @ab: aggregated bandwidth vote from client.
+ * @ib: instant bandwidth vote from client.
+ *
+ * Return: error code.
+ */
+int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
+ u64 ab_vote, u64 ib_vote);
+
+/**
+ * sde_rsc_register_event - register a callback function for an event
+ * @rsc_index: A client will be created on this RSC. As of now only
+ * SDE_RSC_INDEX is valid rsc index.
+ * @event_type: event type to register; client sets 0x3 if it wants
+ * to register for CORE_PC and CORE_RESTORE - both events.
+ * @cb_func: Pointer to desired callback function
+ * @usr: User pointer to pass to callback on event trigger
+ * Returns: sde_rsc_event pointer on success
+ */
+struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
+ void (*cb_func)(uint32_t event_type, void *usr), void *usr);
+
+/**
+ * sde_rsc_unregister_event - unregister callback for an event
+ * @sde_rsc_event: event returned by sde_rsc_register_event
+ */
+void sde_rsc_unregister_event(struct sde_rsc_event *event);
+
+#else
+
+static inline struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index,
+ char *name, bool is_primary_display)
+{
+ return NULL;
+}
+
+static inline void sde_rsc_client_destroy(struct sde_rsc_client *client)
+{
+}
+
+static inline int sde_rsc_client_state_update(struct sde_rsc_client *client,
+ enum sde_rsc_state state,
+ struct sde_rsc_cmd_config *config, int crtc_id)
+{
+ return 0;
+}
+
+static inline int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
+ u64 ab_vote, u64 ib_vote)
+{
+ return 0;
+}
+
+static inline struct sde_rsc_event *sde_rsc_register_event(int rsc_index,
+ uint32_t event_type,
+ void (*cb_func)(uint32_t event_type, void *usr), void *usr)
+{
+ return NULL;
+}
+
+static inline void sde_rsc_unregister_event(struct sde_rsc_event *event)
+{
+}
+
+#endif /* CONFIG_DRM_SDE_RSC */
+
+#endif /* _SDE_RSC_H_ */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 8d0210e..8491bdc 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -142,6 +142,8 @@
int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
+ int (*set_min_state)(struct thermal_cooling_device *, unsigned long);
+ int (*get_min_state)(struct thermal_cooling_device *, unsigned long *);
int (*get_requested_power)(struct thermal_cooling_device *,
struct thermal_zone_device *, u32 *);
int (*state2power)(struct thermal_cooling_device *,
@@ -161,6 +163,8 @@
struct mutex lock; /* protect thermal_instances list */
struct list_head thermal_instances;
struct list_head node;
+ unsigned long sysfs_cur_state_req;
+ unsigned long sysfs_min_state_req;
};
struct thermal_attr {
@@ -260,6 +264,7 @@
void (*unbind_from_tz)(struct thermal_zone_device *tz);
int (*throttle)(struct thermal_zone_device *tz, int trip);
struct list_head governor_list;
+ int min_state_throttle;
};
/* Structure that holds binding parameters for a zone */
@@ -348,6 +353,12 @@
* Used by thermal zone drivers (default 0).
*/
int offset;
+
+ /*
+ * @tracks_low: Indicates that the thermal zone params are for
+ * temperatures falling below the thresholds.
+ */
+ bool tracks_low;
};
struct thermal_genl_event {
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 93094ba..1f39661 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1905,8 +1905,11 @@
#define USB_DEVICE_REMOVE 0x0002
#define USB_BUS_ADD 0x0003
#define USB_BUS_REMOVE 0x0004
+#define USB_BUS_DIED 0x0005
extern void usb_register_notify(struct notifier_block *nb);
extern void usb_unregister_notify(struct notifier_block *nb);
+extern void usb_register_atomic_notify(struct notifier_block *nb);
+extern void usb_unregister_atomic_notify(struct notifier_block *nb);
/* debugfs stuff */
extern struct dentry *usb_debug_root;
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 1d0043d..de2a722 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -50,4 +50,10 @@
/* device can't handle Link Power Management */
#define USB_QUIRK_NO_LPM BIT(10)
+/*
+ * Device reports its bInterval as linear frames instead of the
+ * USB 2.0 calculation.
+ */
+#define USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL BIT(11)
+
#endif /* __LINUX_USB_QUIRKS_H */
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 6de9dfa..065d441 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -42,6 +42,8 @@
#define ADM_MATRIX_ID_AUDIO_TX 1
#define ADM_MATRIX_ID_COMPRESSED_AUDIO_RX 2
+
+#define ADM_MATRIX_ID_LISTEN_TX 4
/* Enumeration for an audio Tx matrix ID.*/
#define ADM_MATRIX_ID_AUDIOX 1
@@ -96,6 +98,16 @@
*/
#define ADM_CMD_DEVICE_OPEN_V5 0x00010326
+/* This command allows a client to open a COPP/Voice Proc the
+ * way as ADM_CMD_DEVICE_OPEN_V5 but supports multiple endpoint2
+ * channels.
+ *
+ * @return
+ * #ADM_CMDRSP_DEVICE_OPEN_V6 with the resulting status and
+ * COPP ID.
+ */
+#define ADM_CMD_DEVICE_OPEN_V6 0x00010356
+
/* Definition for a low latency stream session. */
#define ADM_LOW_LATENCY_DEVICE_SESSION 0x2000
@@ -251,6 +263,129 @@
*/
} __packed;
+/* ADM device open command payload of the
+ * #ADM_CMD_DEVICE_OPEN_V6 command.
+ */
+struct adm_cmd_device_open_v6 {
+ 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.
+ */
+
+ u16 dev_num_channel_eid2;
+/* Number of channels the voice processor block sends
+ * to/receives from the endpoint2.
+ * Supported values: 1 to 8.
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+ u16 bit_width_eid2;
+/* Bit width (in bits) that the voice processor sends
+ * to/receives from the endpoint2.
+ * Supported values: 16 and 24.
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+ u32 sample_rate_eid2;
+/* Sampling rate at which the voice processor Tx block
+ * interfaces with the endpoint2.
+ * Supported values for Tx voice processor: >0 and <=384 kHz
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+ u8 dev_channel_mapping_eid2[8];
+/* Array of channel mapping of buffers that the voice processor
+ * 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 the Tx voice processor.
+ * The values are ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+} __packed;
+
/*
* This command allows the client to close a COPP and disconnect
* the device session.
@@ -369,6 +504,15 @@
/* Reserved. This field must be set to zero.*/
} __packed;
+/* Returns the status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V6 command. */
+#define ADM_CMDRSP_DEVICE_OPEN_V6 0x00010357
+
+/* Payload of the #ADM_CMDRSP_DEVICE_OPEN_V6 message,
+ * which returns the
+ * status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V6 command
+ * is the exact same as ADM_CMDRSP_DEVICE_OPEN_V5.
+ */
+
/* This command allows a query of one COPP parameter. */
#define ADM_CMD_GET_PP_PARAMS_V5 0x0001032A
@@ -1204,6 +1348,8 @@
* #AFE_MODULE_SIDETONE_IIR_FILTER module.
*/
#define AFE_PARAM_ID_SIDETONE_IIR_FILTER_CONFIG 0x00010204
+#define MAX_SIDETONE_IIR_DATA_SIZE 224
+#define MAX_NO_IIR_FILTER_STAGE 10
struct afe_sidetone_iir_filter_config_params {
u16 num_biquad_stages;
@@ -1215,6 +1361,7 @@
/* Pregain for the compensating filter response.
* Supported values: Any number in Q13 format
*/
+ uint8_t iir_config[MAX_SIDETONE_IIR_DATA_SIZE];
} __packed;
#define AFE_MODULE_LOOPBACK 0x00010205
@@ -1365,6 +1512,55 @@
} __packed;
+struct afe_loopback_sidetone_gain {
+ u16 rx_port_id;
+ u16 gain;
+} __packed;
+
+struct loopback_cfg_data {
+ 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;
+
+struct afe_st_loopback_cfg_v1 {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 gain_pdata;
+ struct afe_loopback_sidetone_gain gain_data;
+ struct afe_port_param_data_v2 cfg_pdata;
+ struct loopback_cfg_data cfg_data;
+} __packed;
+
+struct afe_loopback_iir_cfg_v2 {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 st_iir_enable_pdata;
+ struct afe_mod_enable_param st_iir_mode_enable_data;
+ struct afe_port_param_data_v2 st_iir_filter_config_pdata;
+ struct afe_sidetone_iir_filter_config_params st_iir_filter_config_data;
+} __packed;
#define AFE_MODULE_SPEAKER_PROTECTION 0x00010209
#define AFE_PARAM_ID_SPKR_PROT_CONFIG 0x0001020a
#define AFE_API_VERSION_SPKR_PROT_CONFIG 0x1
@@ -4128,6 +4324,9 @@
/* Enumeration for the raw AAC format. */
#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW 3
+/* Enumeration for the AAC LATM format. */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_LATM 4
+
#define ASM_MEDIA_FMT_AAC_AOT_LC 2
#define ASM_MEDIA_FMT_AAC_AOT_SBR 5
#define ASM_MEDIA_FMT_AAC_AOT_PS 29
@@ -4783,8 +4982,8 @@
} __packed;
-#define ASM_MEDIA_FMT_AC3 0x00010DEE
-#define ASM_MEDIA_FMT_EAC3 0x00010DEF
+#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
@@ -4793,7 +4992,6 @@
#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.
@@ -5816,6 +6014,138 @@
/* Reserved for future use. This field must be set to zero. */
} __packed;
+
+#define ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK 0x00010DBA
+
+/* Bitmask for the stream's Performance mode. */
+#define ASM_BIT_MASK_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK \
+ (0x70000000UL)
+
+/* Bit shift for the stream's Performance mode. */
+#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK 28
+
+/* Bitmask for the decoder converter enable flag. */
+#define ASM_BIT_MASK_DECODER_CONVERTER_FLAG (0x00000078UL)
+
+/* Shift value for the decoder converter enable flag. */
+#define ASM_SHIFT_DECODER_CONVERTER_FLAG 3
+
+/* Converter mode is None (Default). */
+#define ASM_CONVERTER_MODE_NONE 0
+
+/* Converter mode is DDP-to-DD. */
+#define ASM_DDP_DD_CONVERTER_MODE 1
+
+/* Identifies a special converter mode where source and sink formats
+ * are the same but postprocessing must applied. Therefore, Decode
+ * @rarrow Re-encode is necessary.
+ */
+#define ASM_POST_PROCESS_CONVERTER_MODE 2
+
+
+struct asm_stream_cmd_open_transcode_loopback_t {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode Flags specifies the performance mode in which this stream
+ * is to be opened.
+ * Supported values{for bits 30 to 28}(stream_perf_mode flag)
+ *
+ * #ASM_LEGACY_STREAM_SESSION -- This mode ensures backward
+ * compatibility to the original behavior
+ * of ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK
+ *
+ * #ASM_LOW_LATENCY_STREAM_SESSION -- Opens a loopback session by using
+ * shortened buffers in low latency POPP
+ * - Recommendation: Do not enable high latency algorithms. They might
+ * negate the benefits of opening a low latency stream, and they
+ * might also suffer quality degradation from unexpected jitter.
+ * - This Low Latency mode is supported only for PCM In and PCM Out
+ * loopbacks. An error is returned if Low Latency mode is opened for
+ * other transcode loopback modes.
+ * - To configure this subfield, use
+ * ASM_BIT_MASK_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK and
+ * ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK.
+ *
+ * Supported values{for bits 6 to 3} (decoder-converter compatibility)
+ * #ASM_CONVERTER_MODE_NONE (0x0) -- Default
+ * #ASM_DDP_DD_CONVERTER_MODE (0x1)
+ * #ASM_POST_PROCESS_CONVERTER_MODE (0x2)
+ * 0x3-0xF -- Reserved for future use
+ * - Use #ASM_BIT_MASK_DECODER_CONVERTER_FLAG and
+ * ASM_SHIFT_DECODER_CONVERTER_FLAG to set this bit
+ * All other bits are reserved; clients must set them to 0.
+ */
+
+ u32 src_format_id;
+/* Specifies the media format of the input audio stream.
+ *
+ * Supported values
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3
+ * - #ASM_MEDIA_FMT_DTS
+ * - #ASM_MEDIA_FMT_EAC3_DEC
+ * - #ASM_MEDIA_FMT_EAC3
+ * - #ASM_MEDIA_FMT_AC3_DEC
+ * - #ASM_MEDIA_FMT_AC3
+ */
+ u32 sink_format_id;
+/* Specifies the media format of the output stream.
+ *
+ * Supported values
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3
+ * - #ASM_MEDIA_FMT_DTS (not supported in Low Latency mode)
+ * - #ASM_MEDIA_FMT_EAC3_DEC (not supported in Low Latency mode)
+ * - #ASM_MEDIA_FMT_EAC3 (not supported in Low Latency mode)
+ * - #ASM_MEDIA_FMT_AC3_DEC (not supported in Low Latency mode)
+ * - #ASM_MEDIA_FMT_AC3 (not supported in Low Latency mode)
+ */
+
+ u32 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_MCH_PEAK_VOL
+ * - #ASM_STREAM_POSTPROC_TOPO_ID_NONE
+ * Topologies can be added through #ASM_CMD_ADD_TOPOLOGIES.
+ * This field is ignored for the Converter mode, in which no
+ * postprocessing is performed.
+ */
+
+ u16 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 0. Otherwise, an error is returned.
+ */
+
+ u16 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 0. Otherwise, an error is returned.
+ */
+
+ u16 bits_per_sample;
+/* Number of bits per sample processed by the ASM modules.
+ * Supported values 16, 24
+ */
+
+ u16 reserved;
+/* This field must be set to 0.
+ */
+} __packed;
+
+
#define ASM_STREAM_CMD_CLOSE 0x00010BCD
#define ASM_STREAM_CMD_FLUSH 0x00010BCE
@@ -6771,6 +7101,12 @@
/*< Clients must set this field to zero. */
} __packed;
+struct adm_set_mic_gain_params {
+ struct adm_cmd_set_pp_params_v5 params;
+ struct adm_param_data_v5 data;
+ struct admx_mic_gain mic_gain_data;
+} __packed;
+
/* end_addtogroup audio_pp_param_ids */
/* @ingroup audio_pp_module_ids
@@ -8662,6 +8998,31 @@
struct asm_stream_cmd_get_pp_params_v2 param;
} __packed;
+/* Opcode to set BT address and license for aptx decoder */
+#define APTX_DECODER_BT_ADDRESS 0x00013201
+#define APTX_CLASSIC_DEC_LICENSE_ID 0x00013202
+
+struct aptx_dec_bt_addr_cfg {
+ uint32_t lap;
+ uint32_t uap;
+ uint32_t nap;
+} __packed;
+
+struct aptx_dec_bt_dev_addr {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct aptx_dec_bt_addr_cfg bt_addr_cfg;
+} __packed;
+
+struct asm_aptx_dec_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+ u32 sample_rate;
+/* Number of samples per second.
+ * Supported values: 44100 and 48000 Hz
+ */
+} __packed;
+
/* LSM Specific */
#define VW_FEAT_DIM (39)
@@ -8689,6 +9050,7 @@
#define LSM_SESSION_EVENT_DETECTION_STATUS_V2 (0x00012B01)
#define LSM_DATA_EVENT_READ_DONE (0x00012B02)
#define LSM_DATA_EVENT_STATUS (0x00012B03)
+#define LSM_SESSION_EVENT_DETECTION_STATUS_V3 (0x00012B04)
#define LSM_MODULE_ID_VOICE_WAKEUP (0x00012C00)
#define LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD (0x00012C01)
@@ -8701,6 +9063,12 @@
#define LSM_PARAM_ID_LAB_ENABLE (0x00012C09)
#define LSM_PARAM_ID_LAB_CONFIG (0x00012C0A)
#define LSM_MODULE_ID_FRAMEWORK (0x00012C0E)
+#define LSM_PARAM_ID_SWMAD_CFG (0x00012C18)
+#define LSM_PARAM_ID_SWMAD_MODEL (0x00012C19)
+#define LSM_PARAM_ID_SWMAD_ENABLE (0x00012C1A)
+#define LSM_PARAM_ID_POLLING_ENABLE (0x00012C1B)
+#define LSM_PARAM_ID_MEDIA_FMT (0x00012C1E)
+#define LSM_PARAM_ID_FWK_MODE_CONFIG (0x00012C27)
/* HW MAD specific */
#define AFE_MODULE_HW_MAD (0x00010230)
@@ -9826,6 +10194,7 @@
COMPRESSED_PASSTHROUGH,
COMPRESSED_PASSTHROUGH_CONVERT,
COMPRESSED_PASSTHROUGH_DSD,
+ LISTEN,
};
#define AUDPROC_MODULE_ID_COMPRESSED_MUTE 0x00010770
@@ -9897,4 +10266,21 @@
#define AUDPROC_PARAM_ID_AUDIOSPHERE_DESIGN_MULTICHANNEL_INPUT 0x0001091D
#define AUDPROC_PARAM_ID_AUDIOSPHERE_OPERATING_INPUT_MEDIA_INFO 0x0001091E
+
+#define AUDPROC_MODULE_ID_VOICE_TX_SECNS 0x10027059
+#define AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH 0x10014444
+
+struct admx_sec_primary_mic_ch {
+ uint16_t version;
+ uint16_t reserved;
+ uint16_t sec_primary_mic_ch;
+ uint16_t reserved1;
+} __packed;
+
+
+struct adm_set_sec_primary_ch_params {
+ struct adm_cmd_set_pp_params_v5 params;
+ struct adm_param_data_v5 data;
+ struct admx_sec_primary_mic_ch sec_primary_mic_ch_data;
+} __packed;
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/cpe_core.h b/include/sound/cpe_core.h
index f4af562..411c2ff 100644
--- a/include/sound/cpe_core.h
+++ b/include/sound/cpe_core.h
@@ -162,7 +162,7 @@
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 *data, uint32_t param_type);
void (*lsm_get_snd_model_offset)
(void *core_handle, struct cpe_lsm_session *,
size_t *offset);
diff --git a/include/sound/jack.h b/include/sound/jack.h
index c66e4e9..722a20e 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -66,12 +66,12 @@
SND_JACK_MICROPHONE2,
/* Kept separate from switches to facilitate implementation */
- SND_JACK_BTN_0 = 0x4000,
- SND_JACK_BTN_1 = 0x2000,
- SND_JACK_BTN_2 = 0x1000,
- SND_JACK_BTN_3 = 0x0800,
- SND_JACK_BTN_4 = 0x0400,
- SND_JACK_BTN_5 = 0x0200,
+ SND_JACK_BTN_0 = 0x8000,
+ SND_JACK_BTN_1 = 0x4000,
+ SND_JACK_BTN_2 = 0x2000,
+ SND_JACK_BTN_3 = 0x1000,
+ SND_JACK_BTN_4 = 0x0800,
+ SND_JACK_BTN_5 = 0x0400,
};
struct snd_jack {
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index c9a429d..2537631 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, 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
@@ -96,12 +96,18 @@
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 perf_mode, uint32_t passthr_mode);
int adm_connect_afe_port(int mode, int session_id, int port_id);
void adm_ec_ref_rx_id(int port_id);
+void adm_num_ec_ref_rx_chans(int num_chans);
+
+void adm_ec_ref_rx_bit_width(int bit_width);
+
+void adm_ec_ref_rx_sampling_rate(int sampling_rate);
+
int adm_get_lowlatency_copp_id(int port_id);
int adm_set_multi_ch_map(char *channel_map, int path);
@@ -130,6 +136,11 @@
int adm_set_softvolume(int port_id, int copp_idx,
struct audproc_softvolume_params *softvol_param);
+int adm_set_mic_gain(int port_id, int copp_idx, int volume);
+
+int adm_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx,
+ int primary_mic_ch);
+
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,
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 367e75d..afd68e7 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -265,7 +265,7 @@
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_sidetone_enable(u16 tx_port_id, u16 rx_port_id, bool enable);
int afe_loopback_gain(u16 port_id, u16 volume);
int afe_validate_port(u16 port_id);
int afe_get_port_index(u16 port_id);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 7321481..cb23898 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -53,6 +53,7 @@
#define FORMAT_G711_MLAW_FS 0x001b
#define FORMAT_DTS 0x001c
#define FORMAT_DSD 0x001d
+#define FORMAT_APTX 0x001e
#define ENCDEC_SBCBITRATE 0x0001
#define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -270,7 +271,7 @@
uint16_t bits_per_sample);
int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
- uint16_t bits_per_sample);
+ uint16_t bits_per_sample, bool ts_mode);
int q6asm_open_write(struct audio_client *ac, uint32_t format
/*, uint16_t bits_per_sample*/);
@@ -552,6 +553,9 @@
int q6asm_media_format_block_dsd(struct audio_client *ac,
struct asm_dsd_cfg *cfg, int stream_id);
+int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac,
+ uint32_t sr, int stream_id);
+
int q6asm_ds1_set_endp_params(struct audio_client *ac,
int param_id, int param_value);
@@ -574,6 +578,10 @@
int q6asm_dts_eagle_get(struct audio_client *ac, int param_id, uint32_t size,
void *data, struct param_outband *po, int m_id);
+/* Send aptx decoder BT address */
+int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac,
+ struct aptx_dec_bt_addr_cfg *cfg);
+
/* Set SoftPause Params */
int q6asm_set_softpause(struct audio_client *ac,
struct asm_softpause_params *param);
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
index 22a62da..26106a8 100644
--- a/include/sound/q6lsm.h
+++ b/include/sound/q6lsm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+ * 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
@@ -21,6 +21,10 @@
#define MAX_NUM_CONFIDENCE 20
+#define ADM_LSM_PORT_ID 0xADCB
+
+#define LSM_MAX_NUM_CHANNELS 8
+
typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv);
@@ -49,11 +53,12 @@
uint32_t mem_map_handle;
};
-struct lsm_lab_hw_params {
+struct lsm_hw_params {
u16 sample_rate;
u16 sample_size;
u32 buf_sz;
u32 period_count;
+ u16 num_chs;
};
struct lsm_client {
@@ -79,8 +84,12 @@
bool lab_enable;
bool lab_started;
struct lsm_lab_buffer *lab_buffer;
- struct lsm_lab_hw_params hw_params;
+ struct lsm_hw_params hw_params;
bool use_topology;
+ int session_state;
+ bool poll_enable;
+ int perf_mode;
+ uint32_t event_mode;
};
struct lsm_stream_cmd_open_tx {
@@ -134,6 +143,27 @@
uint16_t reserved;
} __packed;
+struct lsm_param_poll_enable {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ /* indicates to voice wakeup that HW MAD/SW polling is enabled or not */
+ uint32_t polling_enable;
+} __packed;
+
+struct lsm_param_fwk_mode_cfg {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ uint32_t mode;
+} __packed;
+
+struct lsm_param_media_fmt {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ uint32_t sample_rate;
+ uint16_t num_channels;
+ uint16_t bit_width;
+ uint8_t channel_mapping[LSM_MAX_NUM_CHANNELS];
+} __packed;
/*
* This param cannot be sent in this format.
@@ -163,11 +193,22 @@
struct lsm_param_min_confidence_levels conf_payload;
} __packed;
-struct lsm_cmd_set_opmode_connectport {
+struct lsm_cmd_set_params_opmode {
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;
+ struct lsm_param_op_mode op_mode;
+} __packed;
+
+struct lsm_cmd_set_connectport {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr params_hdr;
+ struct lsm_param_connect_to_port connect_to_port;
+} __packed;
+
+struct lsm_cmd_poll_enable {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr params_hdr;
+ struct lsm_param_poll_enable poll_enable;
} __packed;
struct lsm_param_epd_thres {
@@ -250,6 +291,19 @@
uint32_t flags;
} __packed;
+struct lsm_cmd_set_fwk_mode_cfg {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr params_hdr;
+ struct lsm_param_fwk_mode_cfg fwk_mode_cfg;
+} __packed;
+
+struct lsm_cmd_set_media_fmt {
+ struct apr_hdr msg_hdr;
+ struct lsm_set_params_hdr params_hdr;
+ struct lsm_param_media_fmt media_fmt;
+} __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);
@@ -274,8 +328,11 @@
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);
+ uint32_t param_type);
void q6lsm_sm_set_param_data(struct lsm_client *client,
struct lsm_params_info *p_info,
size_t *offset);
+int q6lsm_set_port_connected(struct lsm_client *client);
+int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode);
+int q6lsm_set_media_fmt_params(struct lsm_client *client);
#endif /* __Q6LSM_H__ */
diff --git a/include/trace/events/rpmh.h b/include/trace/events/rpmh.h
index 62e7216..919877d 100644
--- a/include/trace/events/rpmh.h
+++ b/include/trace/events/rpmh.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* 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
@@ -20,86 +20,89 @@
DECLARE_EVENT_CLASS(rpmh_ack_recvd,
- TP_PROTO(int m, u32 addr, int errno),
+ TP_PROTO(const char *s, int m, u32 addr, int errno),
- TP_ARGS(m, addr, errno),
+ TP_ARGS(s, m, addr, errno),
TP_STRUCT__entry(
+ __field(const char *, name)
__field(int, m)
__field(u32, addr)
__field(int, errno)
),
TP_fast_assign(
+ __entry->name = s;
__entry->m = m;
__entry->addr = addr;
__entry->errno = errno;
),
- TP_printk("ack: tcs-m:%d addr: 0x%08x errno: %d",
- __entry->m, __entry->addr, __entry->errno)
+ TP_printk("%s: ack: tcs-m:%d addr: 0x%08x errno: %d",
+ __entry->name, __entry->m, __entry->addr, __entry->errno)
);
DEFINE_EVENT(rpmh_ack_recvd, rpmh_notify_irq,
- TP_PROTO(int m, u32 addr, int err),
- TP_ARGS(m, addr, err)
+ TP_PROTO(const char *s, int m, u32 addr, int err),
+ TP_ARGS(s, m, addr, err)
);
DEFINE_EVENT(rpmh_ack_recvd, rpmh_notify,
- TP_PROTO(int m, u32 addr, int err),
- TP_ARGS(m, addr, err)
+ TP_PROTO(const char *s, int m, u32 addr, int err),
+ TP_ARGS(s, m, addr, err)
);
TRACE_EVENT(rpmh_send_msg,
- TP_PROTO(void *b, int m, int n, u32 h, u32 a, u32 v, bool c),
+ TP_PROTO(const char *s, int m, int n, u32 h, u32 a, u32 v, bool c, bool t),
- TP_ARGS(b, m, n, h, a, v, c),
+ TP_ARGS(s, m, n, h, a, v, c, t),
TP_STRUCT__entry(
- __field(void *, base)
+ __field(const char*, name)
__field(int, m)
__field(int, n)
__field(u32, hdr)
__field(u32, addr)
__field(u32, data)
__field(bool, complete)
+ __field(bool, trigger)
),
TP_fast_assign(
- __entry->base = b;
+ __entry->name = s;
__entry->m = m;
__entry->n = n;
__entry->hdr = h;
__entry->addr = a;
__entry->data = v;
__entry->complete = c;
+ __entry->trigger = t;
),
- TP_printk("msg: base: 0x%p tcs(m): %d cmd(n): %d msgid: 0x%08x addr: 0x%08x data: 0x%08x complete: %d",
- __entry->base + (672 * __entry->m) + (20 * __entry->n),
- __entry->m, __entry->n, __entry->hdr,
- __entry->addr, __entry->data, __entry->complete)
+ TP_printk("%s: send-msg: tcs(m): %d cmd(n): %d msgid: 0x%08x addr: 0x%08x data: 0x%08x complete: %d trigger: %d",
+ __entry->name, __entry->m, __entry->n, __entry->hdr,
+ __entry->addr, __entry->data, __entry->complete, __entry->trigger)
);
TRACE_EVENT(rpmh_control_msg,
- TP_PROTO(void *r, u32 v),
+ TP_PROTO(const char *s, u32 v),
- TP_ARGS(r, v),
+ TP_ARGS(s, v),
TP_STRUCT__entry(
- __field(void *, reg)
+ __field(const char *, name)
__field(u32, data)
),
TP_fast_assign(
- __entry->reg = r;
+ __entry->name = s;
__entry->data = v;
),
- TP_printk("ctrl-msg: reg: 0x%p data: 0x%08x",
- __entry->reg, __entry->data)
+ TP_printk("%s: ctrl-msg: data: 0x%08x",
+ __entry->name, __entry->data)
);
#endif /* _TRACE_RPMH_H */
diff --git a/include/uapi/linux/msm_audio_calibration.h b/include/uapi/linux/msm_audio_calibration.h
index 11af32e..5a0b860 100644
--- a/include/uapi/linux/msm_audio_calibration.h
+++ b/include/uapi/linux/msm_audio_calibration.h
@@ -98,12 +98,15 @@
ULP_LSM_TOPOLOGY_ID_CAL_TYPE,
AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE,
AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE,
+ AFE_SIDETONE_IIR_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
+#define AFE_SIDETONE_IIR_CAL_TYPE AFE_SIDETONE_IIR_CAL_TYPE
+
enum {
VERSION_0_0,
};
@@ -346,6 +349,19 @@
int32_t pid;
};
+#define MAX_SIDETONE_IIR_DATA_SIZE 224
+#define MAX_NO_IIR_FILTER_STAGE 10
+
+struct audio_cal_info_sidetone_iir {
+ uint16_t iir_enable;
+ uint16_t num_biquad_stages;
+ uint16_t pregain;
+ int32_t tx_acdb_id;
+ int32_t rx_acdb_id;
+ int32_t mid;
+ int32_t pid;
+ uint8_t iir_config[MAX_SIDETONE_IIR_DATA_SIZE];
+};
struct audio_cal_info_lsm_top {
int32_t topology;
int32_t acdb_id;
@@ -580,6 +596,17 @@
struct audio_cal_type_sidetone cal_type;
};
+struct audio_cal_type_sidetone_iir {
+ struct audio_cal_type_header cal_hdr;
+ struct audio_cal_data cal_data;
+ struct audio_cal_info_sidetone_iir cal_info;
+};
+
+struct audio_cal_sidetone_iir {
+ struct audio_cal_header hdr;
+ struct audio_cal_type_sidetone_iir cal_type;
+};
+
struct audio_cal_type_lsm_top {
struct audio_cal_type_header cal_hdr;
struct audio_cal_data cal_data;
diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h
index 75f61fb..09593e7 100644
--- a/include/uapi/sound/compress_params.h
+++ b/include/uapi/sound/compress_params.h
@@ -104,7 +104,8 @@
#define SND_AUDIOCODEC_ALAC ((__u32) 0x00000020)
#define SND_AUDIOCODEC_APE ((__u32) 0x00000021)
#define SND_AUDIOCODEC_DSD ((__u32) 0x00000022)
-#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_DSD
+#define SND_AUDIOCODEC_APTX ((__u32) 0x00000023)
+#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_APTX
/*
* Profile and modes are listed with bit masks. This allows for a
@@ -398,6 +399,12 @@
__u32 seek_table_present;
};
+struct snd_dec_aptx {
+ __u32 lap;
+ __u32 uap;
+ __u32 nap;
+};
+
union snd_codec_options {
struct snd_enc_wma wma;
struct snd_enc_vorbis vorbis;
@@ -409,6 +416,7 @@
struct snd_dec_vorbis vorbis_dec;
struct snd_dec_alac alac;
struct snd_dec_ape ape;
+ struct snd_dec_aptx aptx_dec;
};
/** struct snd_codec_desc - description of codec capabilities
diff --git a/include/uapi/sound/lsm_params.h b/include/uapi/sound/lsm_params.h
index eafdc11..9ca5930 100644
--- a/include/uapi/sound/lsm_params.h
+++ b/include/uapi/sound/lsm_params.h
@@ -1,6 +1,9 @@
#ifndef _UAPI_LSM_PARAMS_H__
#define _UAPI_LSM_PARAMS_H__
+#define LSM_POLLING_ENABLE_SUPPORT
+#define LSM_EVENT_TIMESTAMP_MODE_SUPPORT
+
#include <linux/types.h>
#include <sound/asound.h>
@@ -18,6 +21,19 @@
#define LSM_OUT_TRANSFER_MODE_RT (0)
#define LSM_OUT_TRANSFER_MODE_FTRT (1)
+#define LSM_ENDPOINT_DETECT_THRESHOLD (0)
+#define LSM_OPERATION_MODE (1)
+#define LSM_GAIN (2)
+#define LSM_MIN_CONFIDENCE_LEVELS (3)
+#define LSM_REG_SND_MODEL (4)
+#define LSM_DEREG_SND_MODEL (5)
+#define LSM_CUSTOM_PARAMS (6)
+#define LSM_POLLING_ENABLE (7)
+#define LSM_PARAMS_MAX (LSM_POLLING_ENABLE + 1)
+
+#define LSM_EVENT_NON_TIME_STAMP_MODE (0)
+#define LSM_EVENT_TIME_STAMP_MODE (1)
+
enum lsm_app_id {
LSM_VOICE_WAKEUP_APP_ID = 1,
LSM_VOICE_WAKEUP_APP_ID_V2 = 2,
@@ -35,18 +51,6 @@
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
@@ -75,6 +79,14 @@
__u16 gain;
};
+/*
+ * Data for LSM_POLLING_ENABLE param_type
+ * @poll_en: Polling enable or disable
+ */
+struct snd_lsm_poll_enable {
+ bool poll_en;
+};
+
struct snd_lsm_sound_model_v2 {
__u8 __user *data;
@@ -95,11 +107,20 @@
__u8 payload[0];
};
+struct snd_lsm_event_status_v3 {
+ __u32 timestamp_lsw;
+ __u32 timestamp_msw;
+ __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;
+ bool poll_enable;
};
/*
@@ -122,7 +143,7 @@
__u32 param_id;
__u32 param_size;
__u8 __user *param_data;
- enum LSM_PARAM_TYPE param_type;
+ uint32_t param_type;
};
/*
@@ -171,5 +192,9 @@
struct snd_lsm_module_params)
#define SNDRV_LSM_OUT_FORMAT_CFG _IOW('U', 0x0C, \
struct snd_lsm_output_format_cfg)
+#define SNDRV_LSM_SET_PORT _IO('U', 0x0D)
+#define SNDRV_LSM_SET_FWK_MODE_CONFIG _IOW('U', 0x0E, uint32_t)
+#define SNDRV_LSM_EVENT_STATUS_V3 _IOW('U', 0x0F, \
+ struct snd_lsm_event_status_v3)
#endif
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 124eb6a..0085f66 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -1770,12 +1770,11 @@
#ifdef CONFIG_SMP
if (tsk_nr_cpus_allowed(p) > 1 && rq->dl.overloaded)
queue_push_tasks(rq);
-#else
+#endif
if (dl_task(rq->curr))
check_preempt_curr_dl(rq, p, 0);
else
resched_curr(rq);
-#endif
}
}
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index e43344f..4de373f 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -3180,6 +3180,13 @@
update_task_ravg(rq->curr, rq, TASK_UPDATE, sched_ktime_clock(),
0);
+ /*
+ * Ensure that we don't report load for 'cpu' again via the
+ * cpufreq_update_util path in the window that started at
+ * rq->window_start
+ */
+ rq->load_reported_window = rq->window_start;
+
account_load_subtractions(rq);
load[i] = rq->prev_runnable_sum;
nload[i] = rq->nt_prev_runnable_sum;
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index bcac711..709f719 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -2410,10 +2410,9 @@
#ifdef CONFIG_SMP
if (tsk_nr_cpus_allowed(p) > 1 && rq->rt.overloaded)
queue_push_tasks(rq);
-#else
+#endif /* CONFIG_SMP */
if (p->prio < rq->curr->prio)
resched_curr(rq);
-#endif /* CONFIG_SMP */
}
}
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index d243688..d3f6c26 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -1334,7 +1334,6 @@
if ((map->osd_state[osd] & CEPH_OSD_EXISTS) &&
(xorstate & CEPH_OSD_EXISTS)) {
pr_info("osd%d does not exist\n", osd);
- map->osd_weight[osd] = CEPH_OSD_IN;
ret = set_primary_affinity(map, osd,
CEPH_OSD_DEFAULT_PRIMARY_AFFINITY);
if (ret)
diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c
index 11fce17..46e8830 100644
--- a/net/core/netclassid_cgroup.c
+++ b/net/core/netclassid_cgroup.c
@@ -69,27 +69,17 @@
return 0;
}
-static void update_classid(struct cgroup_subsys_state *css, void *v)
-{
- struct css_task_iter it;
- struct task_struct *p;
-
- css_task_iter_start(css, &it);
- while ((p = css_task_iter_next(&it))) {
- task_lock(p);
- iterate_fd(p->files, 0, update_classid_sock, v);
- task_unlock(p);
- }
- css_task_iter_end(&it);
-}
-
static void cgrp_attach(struct cgroup_taskset *tset)
{
struct cgroup_subsys_state *css;
+ struct task_struct *p;
- cgroup_taskset_first(tset, &css);
- update_classid(css,
- (void *)(unsigned long)css_cls_state(css)->classid);
+ cgroup_taskset_for_each(p, css, tset) {
+ task_lock(p);
+ iterate_fd(p->files, 0, update_classid_sock,
+ (void *)(unsigned long)css_cls_state(css)->classid);
+ task_unlock(p);
+ }
}
static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
@@ -101,12 +91,22 @@
u64 value)
{
struct cgroup_cls_state *cs = css_cls_state(css);
+ struct css_task_iter it;
+ struct task_struct *p;
cgroup_sk_alloc_disable();
cs->classid = (u32)value;
- update_classid(css, (void *)(unsigned long)cs->classid);
+ css_task_iter_start(css, &it);
+ while ((p = css_task_iter_next(&it))) {
+ task_lock(p);
+ iterate_fd(p->files, 0, update_classid_sock,
+ (void *)(unsigned long)cs->classid);
+ task_unlock(p);
+ }
+ css_task_iter_end(&it);
+
return 0;
}
diff --git a/net/core/sock.c b/net/core/sock.c
index 87a740b..19562f7 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1437,6 +1437,11 @@
pr_debug("%s: optmem leakage (%d bytes) detected\n",
__func__, atomic_read(&sk->sk_omem_alloc));
+ if (sk->sk_frag.page) {
+ put_page(sk->sk_frag.page);
+ sk->sk_frag.page = NULL;
+ }
+
if (sk->sk_peer_cred)
put_cred(sk->sk_peer_cred);
put_pid(sk->sk_peer_pid);
@@ -1533,6 +1538,12 @@
is_charged = sk_filter_charge(newsk, filter);
if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk, sk))) {
+ /* We need to make sure that we don't uncharge the new
+ * socket if we couldn't charge it in the first place
+ * as otherwise we uncharge the parent's filter.
+ */
+ if (!is_charged)
+ RCU_INIT_POINTER(newsk->sk_filter, NULL);
/* It is still raw copy of parent, so invalidate
* destructor and make plain sk_free() */
newsk->sk_destruct = NULL;
@@ -2741,11 +2752,6 @@
sk_refcnt_debug_release(sk);
- if (sk->sk_frag.page) {
- put_page(sk->sk_frag.page);
- sk->sk_frag.page = NULL;
- }
-
sock_put(sk);
}
EXPORT_SYMBOL(sk_common_release);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 18412f9..98fd2f7 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1082,7 +1082,8 @@
net = sock_net(skb->sk);
nlh = nlmsg_hdr(skb);
- if (skb->len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len ||
+ if (skb->len < nlmsg_total_size(sizeof(*frn)) ||
+ skb->len < nlh->nlmsg_len ||
nlmsg_len(nlh) < sizeof(*frn))
return;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 723059a..e074816 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5572,6 +5572,7 @@
struct inet_connection_sock *icsk = inet_csk(sk);
tcp_set_state(sk, TCP_ESTABLISHED);
+ icsk->icsk_ack.lrcvtime = tcp_time_stamp;
if (skb) {
icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
@@ -5790,7 +5791,6 @@
* to stand against the temptation 8) --ANK
*/
inet_csk_schedule_ack(sk);
- icsk->icsk_ack.lrcvtime = tcp_time_stamp;
tcp_enter_quickack_mode(sk);
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
TCP_DELACK_MAX, TCP_RTO_MAX);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 6234eba..8615a6b 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -466,6 +466,7 @@
newtp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT);
minmax_reset(&newtp->rtt_min, tcp_time_stamp, ~0U);
newicsk->icsk_rto = TCP_TIMEOUT_INIT;
+ newicsk->icsk_ack.lrcvtime = tcp_time_stamp;
newtp->packets_out = 0;
newtp->retrans_out = 0;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index f6fbd25..26d5718 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1037,6 +1037,7 @@
ipc6.hlimit = -1;
ipc6.tclass = -1;
ipc6.dontfrag = -1;
+ sockc.tsflags = sk->sk_tsflags;
/* destination address check */
if (sin6) {
@@ -1157,7 +1158,6 @@
fl6.flowi6_mark = sk->sk_mark;
fl6.flowi6_uid = sk->sk_uid;
- sockc.tsflags = sk->sk_tsflags;
if (msg->msg_controllen) {
opt = &opt_space;
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index ae25ded..0792541 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -588,7 +588,7 @@
ipv4 = true;
break;
case OVS_TUNNEL_KEY_ATTR_IPV6_SRC:
- SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst,
+ SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.src,
nla_get_in6_addr(a), is_mask);
ipv6 = true;
break;
@@ -649,6 +649,8 @@
tun_flags |= TUNNEL_VXLAN_OPT;
opts_type = type;
break;
+ case OVS_TUNNEL_KEY_ATTR_PAD:
+ break;
default:
OVS_NLERR(log, "Unknown IP tunnel attribute %d",
type);
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 6a0d485..c36757e 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -146,6 +146,7 @@
if (s) {
struct unix_sock *u = unix_sk(s);
+ BUG_ON(!atomic_long_read(&u->inflight));
BUG_ON(list_empty(&u->link));
if (atomic_long_dec_and_test(&u->inflight))
@@ -341,6 +342,14 @@
}
list_del(&cursor);
+ /* Now gc_candidates contains only garbage. Restore original
+ * inflight counters for these as well, and remove the skbuffs
+ * which are creating the cycle(s).
+ */
+ skb_queue_head_init(&hitlist);
+ list_for_each_entry(u, &gc_candidates, link)
+ scan_children(&u->sk, inc_inflight, &hitlist);
+
/* not_cycle_list contains those sockets which do not make up a
* cycle. Restore these to the inflight list.
*/
@@ -350,14 +359,6 @@
list_move_tail(&u->link, &gc_inflight_list);
}
- /* Now gc_candidates contains only garbage. Restore original
- * inflight counters for these as well, and remove the skbuffs
- * which are creating the cycle(s).
- */
- skb_queue_head_init(&hitlist);
- list_for_each_entry(u, &gc_candidates, link)
- scan_children(&u->sk, inc_inflight, &hitlist);
-
spin_unlock(&unix_gc_lock);
/* Here we are. Hitlist is filled. Die. */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 034f70c..9ed6b0f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -548,21 +548,17 @@
{
int err;
- rtnl_lock();
-
if (!cb->args[0]) {
err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
nl80211_fam.attrbuf, nl80211_fam.maxattr,
nl80211_policy);
if (err)
- goto out_unlock;
+ return err;
*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
nl80211_fam.attrbuf);
- if (IS_ERR(*wdev)) {
- err = PTR_ERR(*wdev);
- goto out_unlock;
- }
+ if (IS_ERR(*wdev))
+ return PTR_ERR(*wdev);
*rdev = wiphy_to_rdev((*wdev)->wiphy);
/* 0 is the first index - add 1 to parse only once */
cb->args[0] = (*rdev)->wiphy_idx + 1;
@@ -572,10 +568,8 @@
struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
struct wireless_dev *tmp;
- if (!wiphy) {
- err = -ENODEV;
- goto out_unlock;
- }
+ if (!wiphy)
+ return -ENODEV;
*rdev = wiphy_to_rdev(wiphy);
*wdev = NULL;
@@ -586,21 +580,11 @@
}
}
- if (!*wdev) {
- err = -ENODEV;
- goto out_unlock;
- }
+ if (!*wdev)
+ return -ENODEV;
}
return 0;
- out_unlock:
- rtnl_unlock();
- return err;
-}
-
-static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
-{
- rtnl_unlock();
}
/* IE validation */
@@ -2584,17 +2568,17 @@
int filter_wiphy = -1;
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
+ int ret;
rtnl_lock();
if (!cb->args[2]) {
struct nl80211_dump_wiphy_state state = {
.filter_wiphy = -1,
};
- int ret;
ret = nl80211_dump_wiphy_parse(skb, cb, &state);
if (ret)
- return ret;
+ goto out_unlock;
filter_wiphy = state.filter_wiphy;
@@ -2639,12 +2623,14 @@
wp_idx++;
}
out:
- rtnl_unlock();
-
cb->args[0] = wp_idx;
cb->args[1] = if_idx;
- return skb->len;
+ ret = skb->len;
+ out_unlock:
+ rtnl_unlock();
+
+ return ret;
}
static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
@@ -4371,9 +4357,10 @@
int sta_idx = cb->args[2];
int err;
+ rtnl_lock();
err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
if (err)
- return err;
+ goto out_err;
if (!wdev->netdev) {
err = -EINVAL;
@@ -4408,7 +4395,7 @@
cb->args[2] = sta_idx;
err = skb->len;
out_err:
- nl80211_finish_wdev_dump(rdev);
+ rtnl_unlock();
return err;
}
@@ -5179,9 +5166,10 @@
int path_idx = cb->args[2];
int err;
+ rtnl_lock();
err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
if (err)
- return err;
+ goto out_err;
if (!rdev->ops->dump_mpath) {
err = -EOPNOTSUPP;
@@ -5214,7 +5202,7 @@
cb->args[2] = path_idx;
err = skb->len;
out_err:
- nl80211_finish_wdev_dump(rdev);
+ rtnl_unlock();
return err;
}
@@ -5374,9 +5362,10 @@
int path_idx = cb->args[2];
int err;
+ rtnl_lock();
err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
if (err)
- return err;
+ goto out_err;
if (!rdev->ops->dump_mpp) {
err = -EOPNOTSUPP;
@@ -5409,7 +5398,7 @@
cb->args[2] = path_idx;
err = skb->len;
out_err:
- nl80211_finish_wdev_dump(rdev);
+ rtnl_unlock();
return err;
}
@@ -7559,9 +7548,12 @@
int start = cb->args[2], idx = 0;
int err;
+ rtnl_lock();
err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
- if (err)
+ if (err) {
+ rtnl_unlock();
return err;
+ }
wdev_lock(wdev);
spin_lock_bh(&rdev->bss_lock);
@@ -7584,7 +7576,7 @@
wdev_unlock(wdev);
cb->args[2] = idx;
- nl80211_finish_wdev_dump(rdev);
+ rtnl_unlock();
return skb->len;
}
@@ -7668,9 +7660,10 @@
int res;
bool radio_stats;
+ rtnl_lock();
res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
if (res)
- return res;
+ goto out_err;
/* prepare_wdev_dump parsed the attributes */
radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
@@ -7711,7 +7704,7 @@
cb->args[2] = survey_idx;
res = skb->len;
out_err:
- nl80211_finish_wdev_dump(rdev);
+ rtnl_unlock();
return res;
}
@@ -11302,17 +11295,13 @@
void *data = NULL;
unsigned int data_len = 0;
- rtnl_lock();
-
if (cb->args[0]) {
/* subtract the 1 again here */
struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
struct wireless_dev *tmp;
- if (!wiphy) {
- err = -ENODEV;
- goto out_unlock;
- }
+ if (!wiphy)
+ return -ENODEV;
*rdev = wiphy_to_rdev(wiphy);
*wdev = NULL;
@@ -11333,13 +11322,11 @@
nl80211_fam.attrbuf, nl80211_fam.maxattr,
nl80211_policy);
if (err)
- goto out_unlock;
+ return err;
if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] ||
- !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
- err = -EINVAL;
- goto out_unlock;
- }
+ !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
+ return -EINVAL;
*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
nl80211_fam.attrbuf);
@@ -11348,10 +11335,8 @@
*rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
nl80211_fam.attrbuf);
- if (IS_ERR(*rdev)) {
- err = PTR_ERR(*rdev);
- goto out_unlock;
- }
+ if (IS_ERR(*rdev))
+ return PTR_ERR(*rdev);
vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]);
subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
@@ -11364,19 +11349,15 @@
if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
continue;
- if (!vcmd->dumpit) {
- err = -EOPNOTSUPP;
- goto out_unlock;
- }
+ if (!vcmd->dumpit)
+ return -EOPNOTSUPP;
vcmd_idx = i;
break;
}
- if (vcmd_idx < 0) {
- err = -EOPNOTSUPP;
- goto out_unlock;
- }
+ if (vcmd_idx < 0)
+ return -EOPNOTSUPP;
if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) {
data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
@@ -11393,9 +11374,6 @@
/* keep rtnl locked in successful case */
return 0;
- out_unlock:
- rtnl_unlock();
- return err;
}
static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
@@ -11410,9 +11388,10 @@
int err;
struct nlattr *vendor_data;
+ rtnl_lock();
err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
if (err)
- return err;
+ goto out;
vcmd_idx = cb->args[2];
data = (void *)cb->args[3];
@@ -11421,18 +11400,26 @@
if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV)) {
- if (!wdev)
- return -EINVAL;
+ if (!wdev) {
+ err = -EINVAL;
+ goto out;
+ }
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
- !wdev->netdev)
- return -EINVAL;
+ !wdev->netdev) {
+ err = -EINVAL;
+ goto out;
+ }
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
if (wdev->netdev &&
- !netif_running(wdev->netdev))
- return -ENETDOWN;
- if (!wdev->netdev && !wdev->p2p_started)
- return -ENETDOWN;
+ !netif_running(wdev->netdev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+ if (!wdev->netdev && !wdev->p2p_started) {
+ err = -ENETDOWN;
+ goto out;
+ }
}
}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 5bf7e1bf..e0437a7 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -3062,6 +3062,11 @@
{
int rv;
+ /* Initialize the per-net locks here */
+ spin_lock_init(&net->xfrm.xfrm_state_lock);
+ spin_lock_init(&net->xfrm.xfrm_policy_lock);
+ mutex_init(&net->xfrm.xfrm_cfg_mutex);
+
rv = xfrm_statistics_init(net);
if (rv < 0)
goto out_statistics;
@@ -3078,11 +3083,6 @@
if (rv < 0)
goto out;
- /* Initialize the per-net locks here */
- spin_lock_init(&net->xfrm.xfrm_state_lock);
- spin_lock_init(&net->xfrm.xfrm_policy_lock);
- mutex_init(&net->xfrm.xfrm_cfg_mutex);
-
return 0;
out:
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 671a1d0..a7e27e1 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -412,7 +412,14 @@
up = nla_data(rp);
ulen = xfrm_replay_state_esn_len(up);
- if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen)
+ /* Check the overall length and the internal bitmap length to avoid
+ * potential overflow. */
+ if (nla_len(rp) < ulen ||
+ xfrm_replay_state_esn_len(replay_esn) != ulen ||
+ replay_esn->bmp_len != up->bmp_len)
+ return -EINVAL;
+
+ if (up->replay_window > up->bmp_len * sizeof(__u32) * 8)
return -EINVAL;
return 0;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 8dd39fe..bbba7be 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -375,7 +375,8 @@
* the elapsed time to detect xruns.
*/
jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
- if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
+ if ((jdelta < runtime->hw_ptr_buffer_jiffies / 2) ||
+ (runtime->hw_ptr_buffer_jiffies <= 0))
goto no_delta_check;
hdelta = jdelta - delta * HZ / runtime->rate;
xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 4c93520..f3b1d7f 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1832,6 +1832,7 @@
info->output_pool != client->pool->size)) {
if (snd_seq_write_pool_allocated(client)) {
/* remove all existing cells */
+ snd_seq_pool_mark_closing(client->pool);
snd_seq_queue_client_leave_cells(client->number);
snd_seq_pool_done(client->pool);
}
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 86240d0..3f4efcb 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -70,6 +70,9 @@
return;
*fifo = NULL;
+ if (f->pool)
+ snd_seq_pool_mark_closing(f->pool);
+
snd_seq_fifo_clear(f);
/* wake up clients if any */
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index dfa5156..5847c44 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -414,6 +414,18 @@
return 0;
}
+/* refuse the further insertion to the pool */
+void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
+{
+ unsigned long flags;
+
+ if (snd_BUG_ON(!pool))
+ return;
+ spin_lock_irqsave(&pool->lock, flags);
+ pool->closing = 1;
+ spin_unlock_irqrestore(&pool->lock, flags);
+}
+
/* remove events */
int snd_seq_pool_done(struct snd_seq_pool *pool)
{
@@ -424,10 +436,6 @@
return -EINVAL;
/* wait for closing all threads */
- spin_lock_irqsave(&pool->lock, flags);
- pool->closing = 1;
- spin_unlock_irqrestore(&pool->lock, flags);
-
if (waitqueue_active(&pool->output_sleep))
wake_up(&pool->output_sleep);
@@ -484,6 +492,7 @@
*ppool = NULL;
if (pool == NULL)
return 0;
+ snd_seq_pool_mark_closing(pool);
snd_seq_pool_done(pool);
kfree(pool);
return 0;
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
index 4a2ec77..32f959c 100644
--- a/sound/core/seq/seq_memory.h
+++ b/sound/core/seq/seq_memory.h
@@ -84,6 +84,7 @@
int snd_seq_pool_init(struct snd_seq_pool *pool);
/* done pool - free events */
+void snd_seq_pool_mark_closing(struct snd_seq_pool *pool);
int snd_seq_pool_done(struct snd_seq_pool *pool);
/* create pool */
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index ab4cdab..79edd88 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1905,7 +1905,7 @@
return err;
/* Set DMA transfer mask */
- if (dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
+ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
} else {
dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 0c62b1d..112caa2 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6058,6 +6058,8 @@
ALC295_STANDARD_PINS,
{0x17, 0x21014040},
{0x18, 0x21a19050}),
+ SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC295_STANDARD_PINS),
SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC298_STANDARD_PINS,
{0x17, 0x90170110}),
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9685b02..e0198d2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -927,11 +927,11 @@
config AUDIO_EXT_CLK
tristate
- default y if SND_SOC_WCD9335=y || SND_SOC_WCD9330=y || SND_SOC_MSM8X16_WCD=y
+ default y if SND_SOC_WCD9335=y || SND_SOC_WCD9330=y || SND_SOC_SDM660_CDC=y
config SND_SOC_WCD_MBHC
tristate
- default y if (SND_SOC_MSM8909_WCD=y || SND_SOC_MSM8X16_WCD=y || SND_SOC_WCD9335=y) && SND_SOC_MDMCALIFORNIUM!=y
+ default y if (SND_SOC_MSM8909_WCD=y || SND_SOC_SDM660_CDC=y || SND_SOC_WCD9335=y) && SND_SOC_MDMCALIFORNIUM!=y
config SND_SOC_WCD_DSP_MGR
tristate
@@ -1164,6 +1164,7 @@
HDMI audio drivers should be built only if the platform
supports hdmi panel.
-source "sound/soc/codecs/msm8x16/Kconfig"
+source "sound/soc/codecs/sdm660_cdc/Kconfig"
+source "sound/soc/codecs/msm_sdw/Kconfig"
endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 78db388..20ae32e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -482,4 +482,5 @@
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
-obj-y += msm8x16/
+obj-y += sdm660_cdc/
+obj-y += msm_sdw/
diff --git a/sound/soc/codecs/msm8x16/Makefile b/sound/soc/codecs/msm8x16/Makefile
deleted file mode 100644
index 1e4522f..0000000
--- a/sound/soc/codecs/msm8x16/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-snd-soc-msm8952-wcd-objs := msm8x16-wcd.o msm8x16-wcd-tables.o msm89xx-regmap.o
-obj-$(CONFIG_SND_SOC_MSM8X16_WCD) += snd-soc-msm8952-wcd.o msm8916-wcd-irq.o
diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c b/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c
deleted file mode 100644
index b969639..0000000
--- a/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/* 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 "msm8x16-wcd.h"
-
-const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE] = {
- [MSM89XX_PMIC_DIGITAL_REVISION1] = 1,
- [MSM89XX_PMIC_DIGITAL_REVISION2] = 1,
- [MSM89XX_PMIC_DIGITAL_PERPH_TYPE] = 1,
- [MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_RT_STS] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_SET_TYPE] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_EN_SET] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_EN_CLR] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_PENDING_STS] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_MID_SEL] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_PRIORITY] = 1,
- [MSM89XX_PMIC_DIGITAL_GPIO_MODE] = 1,
- [MSM89XX_PMIC_DIGITAL_PIN_CTL_OE] = 1,
- [MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA] = 1,
- [MSM89XX_PMIC_DIGITAL_PIN_STATUS] = 1,
- [MSM89XX_PMIC_DIGITAL_HDRIVE_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_RST_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2] = 1,
- [MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3] = 1,
- [MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0] = 1,
- [MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1] = 1,
- [MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2] = 1,
- [MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3] = 1,
- [MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_SPARE_0] = 1,
- [MSM89XX_PMIC_DIGITAL_SPARE_1] = 1,
- [MSM89XX_PMIC_DIGITAL_SPARE_2] = 1,
- [MSM89XX_PMIC_ANALOG_REVISION1] = 1,
- [MSM89XX_PMIC_ANALOG_REVISION2] = 1,
- [MSM89XX_PMIC_ANALOG_REVISION3] = 1,
- [MSM89XX_PMIC_ANALOG_REVISION4] = 1,
- [MSM89XX_PMIC_ANALOG_PERPH_TYPE] = 1,
- [MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE] = 1,
- [MSM89XX_PMIC_ANALOG_INT_RT_STS] = 1,
- [MSM89XX_PMIC_ANALOG_INT_SET_TYPE] = 1,
- [MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH] = 1,
- [MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW] = 1,
- [MSM89XX_PMIC_ANALOG_INT_EN_SET] = 1,
- [MSM89XX_PMIC_ANALOG_INT_EN_CLR] = 1,
- [MSM89XX_PMIC_ANALOG_INT_LATCHED_STS] = 1,
- [MSM89XX_PMIC_ANALOG_INT_PENDING_STS] = 1,
- [MSM89XX_PMIC_ANALOG_INT_MID_SEL] = 1,
- [MSM89XX_PMIC_ANALOG_INT_PRIORITY] = 1,
- [MSM89XX_PMIC_ANALOG_MICB_1_EN] = 1,
- [MSM89XX_PMIC_ANALOG_MICB_1_VAL] = 1,
- [MSM89XX_PMIC_ANALOG_MICB_1_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS] = 1,
- [MSM89XX_PMIC_ANALOG_MICB_2_EN] = 1,
- [MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT] = 1,
- [MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT] = 1,
- [MSM89XX_PMIC_ANALOG_TX_1_EN] = 1,
- [MSM89XX_PMIC_ANALOG_TX_2_EN] = 1,
- [MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1] = 1,
- [MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2] = 1,
- [MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS] = 1,
- [MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV] = 1,
- [MSM89XX_PMIC_ANALOG_TX_3_EN] = 1,
- [MSM89XX_PMIC_ANALOG_NCP_EN] = 1,
- [MSM89XX_PMIC_ANALOG_NCP_CLK] = 1,
- [MSM89XX_PMIC_ANALOG_NCP_DEGLITCH] = 1,
- [MSM89XX_PMIC_ANALOG_NCP_FBCTRL] = 1,
- [MSM89XX_PMIC_ANALOG_NCP_BIAS] = 1,
- [MSM89XX_PMIC_ANALOG_NCP_VCTRL] = 1,
- [MSM89XX_PMIC_ANALOG_NCP_TEST] = 1,
- [MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER] = 1,
- [MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT] = 1,
- [MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_RX_EAR_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_RX_ATEST] = 1,
- [MSM89XX_PMIC_ANALOG_RX_HPH_STATUS] = 1,
- [MSM89XX_PMIC_ANALOG_RX_EAR_STATUS] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG] = 1,
- [MSM89XX_PMIC_ANALOG_CURRENT_LIMIT] = 1,
- [MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE] = 1,
- [MSM89XX_PMIC_ANALOG_BYPASS_MODE] = 1,
- [MSM89XX_PMIC_ANALOG_BOOST_EN_CTL] = 1,
- [MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO] = 1,
- [MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE] = 1,
- [MSM89XX_PMIC_ANALOG_BOOST_TEST1_1] = 1,
- [MSM89XX_PMIC_ANALOG_BOOST_TEST_2] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS] = 1,
- [MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS] = 1,
- [MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR] = 1,
- [MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL] = 1,
- [MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL] = 1,
- [MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR] = 1,
- [MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR] = 1,
- [MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR] = 1,
- [MSM89XX_PMIC_DIGITAL_SEC_ACCESS] = 1,
- [MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3] = 1,
- [MSM89XX_PMIC_ANALOG_SEC_ACCESS] = 1,
-};
-
-const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
- [MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_SD_CTL] = 1,
- [MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_RX1_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_RX2_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_RX3_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_RX1_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_RX2_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_RX3_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_RX1_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_RX2_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_RX3_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_RX1_B4_CTL] = 1,
- [MSM89XX_CDC_CORE_RX2_B4_CTL] = 1,
- [MSM89XX_CDC_CORE_RX3_B4_CTL] = 1,
- [MSM89XX_CDC_CORE_RX1_B5_CTL] = 1,
- [MSM89XX_CDC_CORE_RX2_B5_CTL] = 1,
- [MSM89XX_CDC_CORE_RX3_B5_CTL] = 1,
- [MSM89XX_CDC_CORE_RX1_B6_CTL] = 1,
- [MSM89XX_CDC_CORE_RX2_B6_CTL] = 1,
- [MSM89XX_CDC_CORE_RX3_B6_CTL] = 1,
- [MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1,
- [MSM89XX_CDC_CORE_TOP_CTL] = 1,
- [MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1,
- [MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1,
- [MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1,
- [MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1,
- [MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1,
- [MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1,
- [MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1,
- [MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1,
- [MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1,
- [MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1,
- [MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1,
- [MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1,
- [MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1,
- [MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1,
- [MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1,
- [MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1,
- [MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1,
- [MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1,
- [MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1,
- [MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1,
- [MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1,
- [MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1,
- [MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1,
- [MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1,
- [MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1,
- [MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1,
- [MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1,
- [MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1,
- [MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1,
- [MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
-};
diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd.c b/sound/soc/codecs/msm8x16/msm8x16-wcd.c
deleted file mode 100644
index f76dde7..0000000
--- a/sound/soc/codecs/msm8x16/msm8x16-wcd.c
+++ /dev/null
@@ -1,6022 +0,0 @@
-/* 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/module.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/printk.h>
-#include <linux/ratelimit.h>
-#include <linux/debugfs.h>
-#include <linux/io.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/spmi.h>
-#include <linux/of_gpio.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/qdsp6v2/apr.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <sound/q6afe-v2.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-#include <sound/q6core.h>
-#include <soc/qcom/subsystem_notif.h>
-#include "../../msm/msmfalcon-common.h"
-#include "../wcd-mbhc-v2.h"
-#include "msm8916-wcd-irq.h"
-#include "msm8x16-wcd.h"
-
-#define DRV_NAME "msm-codec"
-#define MSM89XX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
-#define MSM89XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
-
-#define NUM_INTERPOLATORS 3
-#define BITS_PER_REG 8
-#define MSM89XX_TX_PORT_NUMBER 4
-
-#define MSM89XX_I2S_MASTER_MODE_MASK 0x08
-#define MSM89XX_DIGITAL_CODEC_BASE_ADDR 0x771C000
-#define PMIC_SLAVE_ID_0 0
-#define PMIC_SLAVE_ID_1 1
-
-#define PMIC_MBG_OK 0x2C08
-#define PMIC_LDO7_EN_CTL 0x4646
-#define MASK_MSB_BIT 0x80
-
-#define CODEC_DT_MAX_PROP_SIZE 40
-#define MSM89XX_DIGITAL_CODEC_REG_SIZE 0x400
-#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
-
-#define MCLK_RATE_9P6MHZ 9600000
-#define MCLK_RATE_12P288MHZ 12288000
-
-#define BUS_DOWN 1
-
-/*
- *50 Milliseconds sufficient for DSP bring up in the modem
- * after Sub System Restart
- */
-#define ADSP_STATE_READY_TIMEOUT_MS 50
-
-#define HPHL_PA_DISABLE (0x01 << 1)
-#define HPHR_PA_DISABLE (0x01 << 2)
-#define EAR_PA_DISABLE (0x01 << 3)
-#define SPKR_PA_DISABLE (0x01 << 4)
-
-enum {
- BOOST_SWITCH = 0,
- BOOST_ALWAYS,
- BYPASS_ALWAYS,
- BOOST_ON_FOREVER,
-};
-
-#define EAR_PMD 0
-#define EAR_PMU 1
-#define SPK_PMD 2
-#define SPK_PMU 3
-
-#define MICBIAS_DEFAULT_VAL 1800000
-#define MICBIAS_MIN_VAL 1600000
-#define MICBIAS_STEP_SIZE 50000
-
-#define DEFAULT_BOOST_VOLTAGE 5000
-#define MIN_BOOST_VOLTAGE 4000
-#define MAX_BOOST_VOLTAGE 5550
-#define BOOST_VOLTAGE_STEP 50
-
-#define MSM89XX_MBHC_BTN_COARSE_ADJ 100 /* in mV */
-#define MSM89XX_MBHC_BTN_FINE_ADJ 12 /* in mV */
-
-#define VOLTAGE_CONVERTER(value, min_value, step_size)\
- ((value - min_value)/step_size)
-
-enum {
- AIF1_PB = 0,
- AIF1_CAP,
- AIF2_VIFEED,
- NUM_CODEC_DAIS,
-};
-
-enum {
- RX_MIX1_INP_SEL_ZERO = 0,
- RX_MIX1_INP_SEL_IIR1,
- RX_MIX1_INP_SEL_IIR2,
- RX_MIX1_INP_SEL_RX1,
- RX_MIX1_INP_SEL_RX2,
- RX_MIX1_INP_SEL_RX3,
-};
-
-static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
-static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
-static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[];
-/* By default enable the internal speaker boost */
-static bool spkr_boost_en = true;
-
-#define MSM89XX_ACQUIRE_LOCK(x) \
- mutex_lock_nested(&x, SINGLE_DEPTH_NESTING)
-
-#define MSM89XX_RELEASE_LOCK(x) mutex_unlock(&x)
-
-
-/* Codec supports 2 IIR filters */
-enum {
- IIR1 = 0,
- IIR2,
- IIR_MAX,
-};
-
-/* Codec supports 5 bands */
-enum {
- BAND1 = 0,
- BAND2,
- BAND3,
- BAND4,
- BAND5,
- BAND_MAX,
-};
-
-struct hpf_work {
- struct msm8x16_wcd_priv *msm8x16_wcd;
- u32 decimator;
- u8 tx_hpf_cut_of_freq;
- struct delayed_work dwork;
-};
-
-static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
-
-static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
- "cdc-vdd-mic-bias",
-};
-
-static unsigned long rx_digital_gain_reg[] = {
- MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
- MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
- MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
-};
-
-static unsigned long tx_digital_gain_reg[] = {
- MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
- MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
-};
-
-enum {
- MSM89XX_SPMI_DIGITAL = 0,
- MSM89XX_SPMI_ANALOG,
- MSM89XX_CODEC_CORE,
- MAX_MSM89XX_DEVICE
-};
-
-static struct wcd_mbhc_register
- wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
-
- WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x80, 7, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x40, 6, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x20, 5, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x18, 3, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x01, 0, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0xC0, 6, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x20, 5, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x10, 4, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x08, 3, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x06, 1, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x80, 7, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
- MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0xF0, 4, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
- MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0x0C, 2, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
- MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL, 0x03, 0, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
- MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x01,
- 0, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
- MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x02,
- 1, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
- MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x08,
- 3, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
- MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x04,
- 2, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
- MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0x10, 4, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
- MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT, 0xFF, 0, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x70, 4, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
- MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0xFF,
- 0, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
- MSM89XX_PMIC_ANALOG_MICB_2_EN, 0xC0, 6, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
- MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFC, 2, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
- MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x10, 4, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
- MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x20, 5, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
- MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x30, 4, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
- MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT,
- 0x10, 4, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
- MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20, 5, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
- 0, 0, 0, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
- 0, 0, 0, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
- 0, 0, 0, 0),
-};
-
-struct msm8x16_wcd_spmi {
- struct spmi_device *spmi;
- int base;
-};
-
-/* Multiply gain_adj and offset by 1000 and 100 to avoid float arithmetic */
-static const struct wcd_imped_i_ref imped_i_ref[] = {
- {I_h4_UA, 8, 800, 9000, 10000},
- {I_pt5_UA, 10, 100, 990, 4600},
- {I_14_UA, 17, 14, 1050, 700},
- {I_l4_UA, 10, 4, 1165, 110},
- {I_1_UA, 0, 1, 1200, 65},
-};
-
-static const struct wcd_mbhc_intr intr_ids = {
- .mbhc_sw_intr = MSM89XX_IRQ_MBHC_HS_DET,
- .mbhc_btn_press_intr = MSM89XX_IRQ_MBHC_PRESS,
- .mbhc_btn_release_intr = MSM89XX_IRQ_MBHC_RELEASE,
- .mbhc_hs_ins_intr = MSM89XX_IRQ_MBHC_INSREM_DET1,
- .mbhc_hs_rem_intr = MSM89XX_IRQ_MBHC_INSREM_DET,
- .hph_left_ocp = MSM89XX_IRQ_HPHL_OCP,
- .hph_right_ocp = MSM89XX_IRQ_HPHR_OCP,
-};
-
-static int msm_digcdc_clock_control(bool flag);
-static int msm8x16_wcd_dt_parse_vreg_info(struct device *dev,
- struct msm8x16_wcd_regulator *vreg,
- const char *vreg_name, bool ondemand);
-static struct msm8x16_wcd_pdata *msm8x16_wcd_populate_dt_pdata(
- struct device *dev);
-static int msm8x16_wcd_enable_ext_mb_source(struct wcd_mbhc *mbhc,
- bool turn_on);
-static void msm8x16_trim_btn_reg(struct snd_soc_codec *codec);
-static void msm8x16_wcd_set_micb_v(struct snd_soc_codec *codec);
-static void msm8x16_wcd_set_boost_v(struct snd_soc_codec *codec);
-static void msm8x16_wcd_set_auto_zeroing(struct snd_soc_codec *codec,
- bool enable);
-static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec,
- bool micbias1, bool micbias2);
-static bool msm8x16_wcd_use_mb(struct snd_soc_codec *codec);
-
-struct msm8x16_wcd_spmi msm8x16_wcd_modules[MAX_MSM89XX_DEVICE];
-
-static void *adsp_state_notifier;
-
-static struct snd_soc_codec *registered_codec;
-static struct snd_soc_codec *registered_digcodec;
-
-static int get_codec_version(struct msm8x16_wcd_priv *msm8x16_wcd)
-{
- if (msm8x16_wcd->codec_version == DIANGU)
- return DIANGU;
- else if (msm8x16_wcd->codec_version == CAJON_2_0)
- return CAJON_2_0;
- else if (msm8x16_wcd->codec_version == CAJON)
- return CAJON;
- else if (msm8x16_wcd->codec_version == CONGA)
- return CONGA;
- else if (msm8x16_wcd->pmic_rev == TOMBAK_2_0)
- return TOMBAK_2_0;
- else if (msm8x16_wcd->pmic_rev == TOMBAK_1_0)
- return TOMBAK_1_0;
-
- pr_err("%s: unsupported codec version\n", __func__);
- return UNSUPPORTED;
-}
-
-static int msm_digcdc_clock_control(bool flag)
-{
- int ret = -EINVAL;
- struct msm_asoc_mach_data *pdata = NULL;
-
- pdata = snd_soc_card_get_drvdata(registered_codec->component.card);
-
- if (flag) {
- mutex_lock(&pdata->cdc_int_mclk0_mutex);
- if (atomic_read(&pdata->int_mclk0_enabled) == false) {
- 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("failed to enable the INT_MCLK0\n");
- goto err_mclk;
- }
- pr_err("enabled digital codec core clk\n");
- atomic_set(&pdata->int_mclk0_enabled, true);
- schedule_delayed_work(&pdata->disable_int_mclk0_work,
- 50);
- }
-err_mclk:
- mutex_unlock(&pdata->cdc_int_mclk0_mutex);
- return ret;
- }
- return 0;
-}
-
-void enable_digital_callback(void *flag)
-{
- msm_digcdc_clock_control(true);
-}
-
-void disable_digital_callback(void *flag)
-{
- msm_digcdc_clock_control(false);
-}
-
-static int snd_soc_read_wrapper(struct snd_soc_codec *codec, u16 reg)
-{
- int ret = -EINVAL;
- struct msm8x16_wcd *msm8x16_wcd = codec->control_data;
-
- pr_err("%s reg = %x\n", __func__, reg);
- mutex_lock(&msm8x16_wcd->io_lock);
- if (MSM89XX_IS_PMIC_CDC_REG(reg))
- ret = snd_soc_read(codec, reg);
- else if (MSM89XX_IS_CDC_CORE_REG(reg))
- ret = snd_soc_read(registered_digcodec, reg);
- mutex_unlock(&msm8x16_wcd->io_lock);
-
- return ret;
-}
-
-static int snd_soc_write_wrapper(struct snd_soc_codec *codec, u16 reg, u8 val)
-{
- int ret = -EINVAL;
- struct msm8x16_wcd *msm8x16_wcd = codec->control_data;
-
- pr_err("%s reg = %x\n", __func__, reg);
- mutex_lock(&msm8x16_wcd->io_lock);
- if (MSM89XX_IS_PMIC_CDC_REG(reg))
- ret = snd_soc_write(codec, reg, val);
- else if (MSM89XX_IS_CDC_CORE_REG(reg))
- ret = snd_soc_write(registered_digcodec, reg, val);
- mutex_unlock(&msm8x16_wcd->io_lock);
-
- return ret;
-}
-
-static int snd_soc_update_bits_wrapper(struct snd_soc_codec *codec,
- u16 reg, u8 mask, u8 val)
-{
- int ret = -EINVAL;
- struct msm8x16_wcd *msm8x16_wcd = codec->control_data;
-
- pr_err("%s reg = %x\n", __func__, reg);
- mutex_lock(&msm8x16_wcd->io_lock);
- if (MSM89XX_IS_PMIC_CDC_REG(reg))
- ret = snd_soc_update_bits(codec, reg, mask, val);
- else if (MSM89XX_IS_CDC_CORE_REG(reg))
- ret = snd_soc_update_bits(registered_digcodec, reg, mask, val);
- mutex_unlock(&msm8x16_wcd->io_lock);
-
- return ret;
-}
-
-static void wcd_mbhc_meas_imped(struct snd_soc_codec *codec,
- s16 *impedance_l, s16 *impedance_r)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if ((msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_BOTH) ||
- (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL)) {
- /* Enable ZDET_L_MEAS_EN */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x08, 0x08);
- /* Wait for 2ms for measurement to complete */
- usleep_range(2000, 2100);
- /* Read Left impedance value from Result1 */
- *impedance_l = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
- /* Enable ZDET_R_MEAS_EN */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x08, 0x00);
- }
- if ((msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_BOTH) ||
- (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x04, 0x04);
- /* Wait for 2ms for measurement to complete */
- usleep_range(2000, 2100);
- /* Read Right impedance value from Result1 */
- *impedance_r = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x04, 0x00);
- }
-}
-
-static void msm8x16_set_ref_current(struct snd_soc_codec *codec,
- enum wcd_curr_ref curr_ref)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- pr_err("%s: curr_ref: %d\n", __func__, curr_ref);
-
- if (get_codec_version(msm8x16_wcd) < CAJON)
- pr_err("%s: Setting ref current not required\n", __func__);
-
- msm8x16_wcd->imped_i_ref = imped_i_ref[curr_ref];
-
- switch (curr_ref) {
- case I_h4_UA:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN,
- 0x07, 0x01);
- break;
- case I_pt5_UA:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN,
- 0x07, 0x04);
- break;
- case I_14_UA:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN,
- 0x07, 0x03);
- break;
- case I_l4_UA:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN,
- 0x07, 0x01);
- break;
- case I_1_UA:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN,
- 0x07, 0x00);
- break;
- default:
- pr_err("%s: No ref current set\n", __func__);
- break;
- }
-}
-
-static bool msm8x16_adj_ref_current(struct snd_soc_codec *codec,
- s16 *impedance_l, s16 *impedance_r)
-{
- int i = 2;
- s16 compare_imp = 0;
-
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)
- compare_imp = *impedance_r;
- else
- compare_imp = *impedance_l;
-
- if (get_codec_version(msm8x16_wcd) < CAJON) {
- pr_err("%s: Reference current adjustment not required\n",
- __func__);
- return false;
- }
-
- while (compare_imp < imped_i_ref[i].min_val) {
- msm8x16_set_ref_current(codec,
- imped_i_ref[++i].curr_ref);
- wcd_mbhc_meas_imped(codec,
- impedance_l, impedance_r);
- compare_imp = (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)
- ? *impedance_r : *impedance_l;
- }
-
- return true;
-}
-
-void msm8x16_wcd_spk_ext_pa_cb(
- int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
- int enable), struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- pr_err("%s: Enter\n", __func__);
- msm8x16_wcd->codec_spk_ext_pa_cb = codec_spk_ext_pa;
-}
-
-void msm8x16_wcd_hph_comp_cb(
- int (*codec_hph_comp_gpio)(bool enable), struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- pr_err("%s: Enter\n", __func__);
- msm8x16_wcd->codec_hph_comp_gpio = codec_hph_comp_gpio;
-}
-
-static void msm8x16_wcd_compute_impedance(struct snd_soc_codec *codec, s16 l,
- s16 r, uint32_t *zl, uint32_t *zr, bool high)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- uint32_t rl = 0, rr = 0;
- struct wcd_imped_i_ref R = msm8x16_wcd->imped_i_ref;
- int codec_ver = get_codec_version(msm8x16_wcd);
-
- switch (codec_ver) {
- case TOMBAK_1_0:
- case TOMBAK_2_0:
- case CONGA:
- if (high) {
- pr_err("%s: This plug has high range impedance\n",
- __func__);
- rl = (uint32_t)(((100 * (l * 400 - 200))/96) - 230);
- rr = (uint32_t)(((100 * (r * 400 - 200))/96) - 230);
- } else {
- pr_err("%s: This plug has low range impedance\n",
- __func__);
- rl = (uint32_t)(((1000 * (l * 2 - 1))/1165) - (13/10));
- rr = (uint32_t)(((1000 * (r * 2 - 1))/1165) - (13/10));
- }
- break;
- case CAJON:
- case CAJON_2_0:
- case DIANGU:
- if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL) {
- rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
- (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
- rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
- - R.offset * R.gain_adj)/(R.gain_adj * 100));
- } else if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR) {
- rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
- - R.offset * R.gain_adj)/(R.gain_adj * 100));
- rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
- (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
- } else if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_NONE) {
- rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
- (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
- rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
- (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
- } else {
- rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
- - R.offset * R.gain_adj)/(R.gain_adj * 100));
- rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
- - R.offset * R.gain_adj)/(R.gain_adj * 100));
- }
- break;
- default:
- pr_err("%s: No codec mentioned\n", __func__);
- break;
- }
- *zl = rl;
- *zr = rr;
-}
-
-static struct firmware_cal *msm8x16_wcd_get_hwdep_fw_cal(
- struct wcd_mbhc *mbhc,
- enum wcd_cal_type type)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd;
- struct firmware_cal *hwdep_cal;
- struct snd_soc_codec *codec = mbhc->codec;
-
- if (!codec) {
- pr_err("%s: NULL codec pointer\n", __func__);
- return NULL;
- }
- msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- hwdep_cal = wcdcal_get_fw_cal(msm8x16_wcd->fw_data, type);
- if (!hwdep_cal) {
- dev_err(codec->dev, "%s: cal not sent by %d\n",
- __func__, type);
- return NULL;
- }
- return hwdep_cal;
-}
-
-static void wcd9xxx_spmi_irq_control(struct snd_soc_codec *codec,
- int irq, bool enable)
-{
- if (enable)
- wcd9xxx_spmi_enable_irq(irq);
- else
- wcd9xxx_spmi_disable_irq(irq);
-}
-
-static void msm8x16_mbhc_clk_setup(struct snd_soc_codec *codec,
- bool enable)
-{
- if (enable)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x08, 0x08);
- else
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x08, 0x00);
-}
-
-static int msm8x16_mbhc_map_btn_code_to_num(struct snd_soc_codec *codec)
-{
- int btn_code;
- int btn;
-
- btn_code = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
-
- switch (btn_code) {
- case 0:
- btn = 0;
- break;
- case 1:
- btn = 1;
- break;
- case 3:
- btn = 2;
- break;
- case 7:
- btn = 3;
- break;
- case 15:
- btn = 4;
- break;
- default:
- btn = -EINVAL;
- break;
- };
-
- return btn;
-}
-
-static bool msm8x16_spmi_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
-{
- if (lock)
- return wcd9xxx_spmi_lock_sleep();
- wcd9xxx_spmi_unlock_sleep();
- return 0;
-}
-
-static bool msm8x16_wcd_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
-{
- if (micb_num == MIC_BIAS_1)
- return (snd_soc_read_wrapper(mbhc->codec,
- MSM89XX_PMIC_ANALOG_MICB_1_EN) &
- 0x80);
- if (micb_num == MIC_BIAS_2)
- return (snd_soc_read_wrapper(mbhc->codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN) &
- 0x80);
- return false;
-}
-
-static void msm8x16_wcd_enable_master_bias(struct snd_soc_codec *codec,
- bool enable)
-{
- if (enable)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
- 0x30, 0x30);
- else
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
- 0x30, 0x00);
-}
-
-static void msm8x16_wcd_mbhc_common_micb_ctrl(struct snd_soc_codec *codec,
- int event, bool enable)
-{
- u16 reg;
- u8 mask;
- u8 val;
-
- switch (event) {
- case MBHC_COMMON_MICB_PRECHARGE:
- reg = MSM89XX_PMIC_ANALOG_MICB_1_CTL;
- mask = 0x60;
- val = (enable ? 0x60 : 0x00);
- break;
- case MBHC_COMMON_MICB_SET_VAL:
- reg = MSM89XX_PMIC_ANALOG_MICB_1_VAL;
- mask = 0xFF;
- val = (enable ? 0xC0 : 0x00);
- break;
- case MBHC_COMMON_MICB_TAIL_CURR:
- reg = MSM89XX_PMIC_ANALOG_MICB_1_EN;
- mask = 0x04;
- val = (enable ? 0x04 : 0x00);
- break;
- };
- snd_soc_update_bits_wrapper(codec, reg, mask, val);
-}
-
-static void msm8x16_wcd_mbhc_internal_micbias_ctrl(struct snd_soc_codec *codec,
- int micbias_num, bool enable)
-{
- if (micbias_num == 1) {
- if (enable)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
- 0x10, 0x10);
- else
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
- 0x10, 0x00);
- }
-}
-
-static bool msm8x16_wcd_mbhc_hph_pa_on_status(struct snd_soc_codec *codec)
-{
- return (snd_soc_read_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN) &
- 0x30) ? true : false;
-}
-
-static void msm8x16_wcd_mbhc_program_btn_thr(struct snd_soc_codec *codec,
- s16 *btn_low, s16 *btn_high,
- int num_btn, bool is_micbias)
-{
- int i;
- u32 course, fine, reg_val;
- u16 reg_addr = MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL;
- s16 *btn_voltage;
-
- btn_voltage = ((is_micbias) ? btn_high : btn_low);
-
- for (i = 0; i < num_btn; i++) {
- course = (btn_voltage[i] / MSM89XX_MBHC_BTN_COARSE_ADJ);
- fine = ((btn_voltage[i] % MSM89XX_MBHC_BTN_COARSE_ADJ) /
- MSM89XX_MBHC_BTN_FINE_ADJ);
-
- reg_val = (course << 5) | (fine << 2);
- snd_soc_update_bits_wrapper(codec, reg_addr, 0xFC, reg_val);
- pr_err("%s: course: %d fine: %d reg_addr: %x reg_val: %x\n",
- __func__, course, fine, reg_addr, reg_val);
- reg_addr++;
- }
-}
-
-static void msm8x16_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
- uint32_t *zr)
-{
- struct snd_soc_codec *codec = mbhc->codec;
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- s16 impedance_l, impedance_r;
- s16 impedance_l_fixed;
- s16 reg0, reg1, reg2, reg3, reg4;
- bool high = false;
- bool min_range_used = false;
-
- WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
- reg0 = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER);
- reg1 = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL);
- reg2 = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2);
- reg3 = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN);
- reg4 = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL);
-
- msm8x16_wcd->imped_det_pin = WCD_MBHC_DET_BOTH;
- mbhc->hph_type = WCD_MBHC_HPH_NONE;
-
- /* disable FSM and micbias and enable pullup*/
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x80, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN,
- 0xA5, 0x25);
- /*
- * Enable legacy electrical detection current sources
- * and disable fast ramp and enable manual switching
- * of extra capacitance
- */
- pr_err("%s: Setup for impedance det\n", __func__);
-
- msm8x16_set_ref_current(codec, I_h4_UA);
-
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
- 0x06, 0x02);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER,
- 0x02, 0x02);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL,
- 0x02, 0x00);
-
- pr_err("%s: Start performing impedance detection\n",
- __func__);
-
- wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
-
- if (impedance_l > 2 || impedance_r > 2) {
- high = true;
- if (!mbhc->mbhc_cfg->mono_stero_detection) {
- /* Set ZDET_CHG to 0 to discharge ramp */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x02, 0x00);
- /* wait 40ms for the discharge ramp to complete */
- usleep_range(40000, 40100);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
- 0x03, 0x00);
- msm8x16_wcd->imped_det_pin = (impedance_l > 2 &&
- impedance_r > 2) ?
- WCD_MBHC_DET_NONE :
- ((impedance_l > 2) ?
- WCD_MBHC_DET_HPHR :
- WCD_MBHC_DET_HPHL);
- if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_NONE)
- goto exit;
- } else {
- if (get_codec_version(msm8x16_wcd) >= CAJON) {
- if (impedance_l == 63 && impedance_r == 63) {
- pr_err("%s: HPHL and HPHR are floating\n",
- __func__);
- msm8x16_wcd->imped_det_pin =
- WCD_MBHC_DET_NONE;
- mbhc->hph_type = WCD_MBHC_HPH_NONE;
- } else if (impedance_l == 63
- && impedance_r < 63) {
- pr_err("%s: Mono HS with HPHL floating\n",
- __func__);
- msm8x16_wcd->imped_det_pin =
- WCD_MBHC_DET_HPHR;
- mbhc->hph_type = WCD_MBHC_HPH_MONO;
- } else if (impedance_r == 63 &&
- impedance_l < 63) {
- pr_err("%s: Mono HS with HPHR floating\n",
- __func__);
- msm8x16_wcd->imped_det_pin =
- WCD_MBHC_DET_HPHL;
- mbhc->hph_type = WCD_MBHC_HPH_MONO;
- } else if (impedance_l > 3 && impedance_r > 3 &&
- (impedance_l == impedance_r)) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
- 0x06, 0x06);
- wcd_mbhc_meas_imped(codec, &impedance_l,
- &impedance_r);
- if (impedance_r == impedance_l)
- pr_err("%s: Mono Headset\n",
- __func__);
- msm8x16_wcd->imped_det_pin =
- WCD_MBHC_DET_NONE;
- mbhc->hph_type =
- WCD_MBHC_HPH_MONO;
- } else {
- pr_err("%s: STEREO headset is found\n",
- __func__);
- msm8x16_wcd->imped_det_pin =
- WCD_MBHC_DET_BOTH;
- mbhc->hph_type = WCD_MBHC_HPH_STEREO;
- }
- }
- }
- }
-
- msm8x16_set_ref_current(codec, I_pt5_UA);
- msm8x16_set_ref_current(codec, I_14_UA);
-
- /* Enable RAMP_L, RAMP_R & ZDET_CHG*/
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
- 0x03, 0x03);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x02, 0x02);
- /* wait for 50msec for the HW to apply ramp on HPHL and HPHR */
- usleep_range(50000, 50100);
- /* Enable ZDET_DISCHG_CAP_CTL to add extra capacitance */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x01, 0x01);
- /* wait for 5msec for the voltage to get stable */
- usleep_range(5000, 5100);
-
-
- wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
-
- min_range_used = msm8x16_adj_ref_current(codec,
- &impedance_l, &impedance_r);
- if (!mbhc->mbhc_cfg->mono_stero_detection) {
- /* Set ZDET_CHG to 0 to discharge ramp */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x02, 0x00);
- /* wait for 40msec for the capacitor to discharge */
- usleep_range(40000, 40100);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
- 0x03, 0x00);
- goto exit;
- }
-
- /* we are setting ref current to the minimun range or the measured
- * value larger than the minimum value, so min_range_used is true.
- * If the headset is mono headset with either HPHL or HPHR floating
- * then we have already done the mono stereo detection and do not
- * need to continue further.
- */
-
- if (!min_range_used ||
- msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL ||
- msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)
- goto exit;
-
-
- /* Disable Set ZDET_CONN_RAMP_L and enable ZDET_CONN_FIXED_L */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
- 0x02, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
- 0x02, 0x02);
- /* Set ZDET_CHG to 0 */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x02, 0x00);
- /* wait for 40msec for the capacitor to discharge */
- usleep_range(40000, 40100);
-
- /* Set ZDET_CONN_RAMP_R to 0 */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
- 0x01, 0x00);
- /* Enable ZDET_L_MEAS_EN */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x08, 0x08);
- /* wait for 2msec for the HW to compute left inpedance value */
- usleep_range(2000, 2100);
- /* Read Left impedance value from Result1 */
- impedance_l_fixed = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
- /* Disable ZDET_L_MEAS_EN */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x08, 0x00);
- /*
- * Assume impedance_l is L1, impedance_l_fixed is L2.
- * If the following condition is met, we can take this
- * headset as mono one with impedance of L2.
- * Otherwise, take it as stereo with impedance of L1.
- * Condition:
- * abs[(L2-0.5L1)/(L2+0.5L1)] < abs [(L2-L1)/(L2+L1)]
- */
- if ((abs(impedance_l_fixed - impedance_l/2) *
- (impedance_l_fixed + impedance_l)) >=
- (abs(impedance_l_fixed - impedance_l) *
- (impedance_l_fixed + impedance_l/2))) {
- pr_err("%s: STEREO plug type detected\n",
- __func__);
- mbhc->hph_type = WCD_MBHC_HPH_STEREO;
- } else {
- pr_err("%s: MONO plug type detected\n",
- __func__);
- mbhc->hph_type = WCD_MBHC_HPH_MONO;
- impedance_l = impedance_l_fixed;
- }
- /* Enable ZDET_CHG */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x02, 0x02);
- /* wait for 10msec for the capacitor to charge */
- usleep_range(10000, 10100);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
- 0x02, 0x02);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
- 0x02, 0x00);
- /* Set ZDET_CHG to 0 to discharge HPHL */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
- 0x02, 0x00);
- /* wait for 40msec for the capacitor to discharge */
- usleep_range(40000, 40100);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
- 0x02, 0x00);
-
-exit:
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, reg4);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN, reg3);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, reg1);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, reg0);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, reg2);
- msm8x16_wcd_compute_impedance(codec, impedance_l, impedance_r,
- zl, zr, high);
-
- pr_err("%s: RL %d ohm, RR %d ohm\n", __func__, *zl, *zr);
- pr_err("%s: Impedance detection completed\n", __func__);
-}
-
-static int msm8x16_register_notifier(struct wcd_mbhc *mbhc,
- struct notifier_block *nblock,
- bool enable)
-{
- struct snd_soc_codec *codec = mbhc->codec;
- struct msm8x16_wcd_priv *msm8x16_wcd =
- snd_soc_codec_get_drvdata(codec);
-
- if (enable)
- return blocking_notifier_chain_register(&msm8x16_wcd->notifier,
- nblock);
- return blocking_notifier_chain_unregister(
- &msm8x16_wcd->notifier, nblock);
-}
-
-static int msm8x16_wcd_request_irq(struct snd_soc_codec *codec,
- int irq, irq_handler_t handler,
- const char *name, void *data)
-{
- return wcd9xxx_spmi_request_irq(irq, handler, name, data);
-}
-
-static int msm8x16_wcd_free_irq(struct snd_soc_codec *codec,
- int irq, void *data)
-{
- return wcd9xxx_spmi_free_irq(irq, data);
-}
-
-static const struct wcd_mbhc_cb mbhc_cb = {
- .enable_mb_source = msm8x16_wcd_enable_ext_mb_source,
- .trim_btn_reg = msm8x16_trim_btn_reg,
- .compute_impedance = msm8x16_wcd_mbhc_calc_impedance,
- .set_micbias_value = msm8x16_wcd_set_micb_v,
- .set_auto_zeroing = msm8x16_wcd_set_auto_zeroing,
- .get_hwdep_fw_cal = msm8x16_wcd_get_hwdep_fw_cal,
- .set_cap_mode = msm8x16_wcd_configure_cap,
- .register_notifier = msm8x16_register_notifier,
- .request_irq = msm8x16_wcd_request_irq,
- .irq_control = wcd9xxx_spmi_irq_control,
- .free_irq = msm8x16_wcd_free_irq,
- .clk_setup = msm8x16_mbhc_clk_setup,
- .map_btn_code_to_num = msm8x16_mbhc_map_btn_code_to_num,
- .lock_sleep = msm8x16_spmi_lock_sleep,
- .micbias_enable_status = msm8x16_wcd_micb_en_status,
- .mbhc_bias = msm8x16_wcd_enable_master_bias,
- .mbhc_common_micb_ctrl = msm8x16_wcd_mbhc_common_micb_ctrl,
- .micb_internal = msm8x16_wcd_mbhc_internal_micbias_ctrl,
- .hph_pa_on_status = msm8x16_wcd_mbhc_hph_pa_on_status,
- .set_btn_thr = msm8x16_wcd_mbhc_program_btn_thr,
- .extn_use_mb = msm8x16_wcd_use_mb,
-};
-
-static const uint32_t wcd_imped_val[] = {4, 8, 12, 13, 16,
- 20, 24, 28, 32,
- 36, 40, 44, 48};
-
-void msm8x16_notifier_call(struct snd_soc_codec *codec,
- const enum wcd_notify_event event)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- pr_err("%s: notifier call event %d\n", __func__, event);
- blocking_notifier_call_chain(&msm8x16_wcd->notifier, event,
- &msm8x16_wcd->mbhc);
-}
-
-static void msm8x16_wcd_boost_on(struct snd_soc_codec *codec)
-{
- u8 dest = 0x00;
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-
- if ((dest & MASK_MSB_BIT) == 0) {
- pr_err("PMIC MBG not ON, enable codec hw_en MB bit again\n");
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
- /* Allow 1ms for PMIC MBG state to be updated */
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- }
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3,
- 0x0F, 0x0F);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SEC_ACCESS,
- 0xA5);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3,
- 0x0F);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
- 0x30);
- if (get_codec_version(msm8x16_wcd) < CAJON_2_0) {
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_CURRENT_LIMIT,
- 0x82);
- } else {
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_CURRENT_LIMIT,
- 0xA2);
- }
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
- 0x69, 0x69);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG,
- 0x01, 0x01);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO,
- 0x88, 0x88);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
- 0x03, 0x03);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL,
- 0xE1, 0xE1);
- if (get_codec_version(msm8x16_wcd) < CAJON_2_0) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x20, 0x20);
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
- 0xDF, 0xDF);
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- } else {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
- 0x40, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x20, 0x20);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
- 0x80, 0x80);
- usleep_range(500, 510);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
- 0x40, 0x40);
- usleep_range(500, 510);
- }
-}
-
-static void msm8x16_wcd_boost_off(struct snd_soc_codec *codec)
-{
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
- 0xDF, 0x5F);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x20, 0x00);
-}
-
-static void msm8x16_wcd_bypass_on(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (get_codec_version(msm8x16_wcd) < CAJON_2_0) {
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SEC_ACCESS,
- 0xA5);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3,
- 0x07);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x02, 0x02);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x01, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x40, 0x40);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x80, 0x80);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
- 0xDF, 0xDF);
- } else {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x20, 0x20);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x20, 0x20);
- }
-}
-
-static void msm8x16_wcd_bypass_off(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (get_codec_version(msm8x16_wcd) < CAJON_2_0) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
- 0x80, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x80, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x02, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x40, 0x00);
- } else {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_BYPASS_MODE,
- 0x20, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x20, 0x00);
- }
-}
-
-static void msm8x16_wcd_boost_mode_sequence(struct snd_soc_codec *codec,
- int flag)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (flag == EAR_PMU) {
- switch (msm8x16_wcd->boost_option) {
- case BOOST_SWITCH:
- if (msm8x16_wcd->ear_pa_boost_set) {
- msm8x16_wcd_boost_off(codec);
- msm8x16_wcd_bypass_on(codec);
- }
- break;
- case BOOST_ALWAYS:
- msm8x16_wcd_boost_on(codec);
- break;
- case BYPASS_ALWAYS:
- msm8x16_wcd_bypass_on(codec);
- break;
- case BOOST_ON_FOREVER:
- msm8x16_wcd_boost_on(codec);
- break;
- default:
- pr_err("%s: invalid boost option: %d\n", __func__,
- msm8x16_wcd->boost_option);
- break;
- }
- } else if (flag == EAR_PMD) {
- switch (msm8x16_wcd->boost_option) {
- case BOOST_SWITCH:
- if (msm8x16_wcd->ear_pa_boost_set)
- msm8x16_wcd_bypass_off(codec);
- break;
- case BOOST_ALWAYS:
- msm8x16_wcd_boost_off(codec);
- /* 80ms for EAR boost to settle down */
- msleep(80);
- break;
- case BYPASS_ALWAYS:
- /* nothing to do as bypass on always */
- break;
- case BOOST_ON_FOREVER:
- /* nothing to do as boost on forever */
- break;
- default:
- pr_err("%s: invalid boost option: %d\n", __func__,
- msm8x16_wcd->boost_option);
- break;
- }
- } else if (flag == SPK_PMU) {
- switch (msm8x16_wcd->boost_option) {
- case BOOST_SWITCH:
- if (msm8x16_wcd->spk_boost_set) {
- msm8x16_wcd_bypass_off(codec);
- msm8x16_wcd_boost_on(codec);
- }
- break;
- case BOOST_ALWAYS:
- msm8x16_wcd_boost_on(codec);
- break;
- case BYPASS_ALWAYS:
- msm8x16_wcd_bypass_on(codec);
- break;
- case BOOST_ON_FOREVER:
- msm8x16_wcd_boost_on(codec);
- break;
- default:
- pr_err("%s: invalid boost option: %d\n", __func__,
- msm8x16_wcd->boost_option);
- break;
- }
- } else if (flag == SPK_PMD) {
- switch (msm8x16_wcd->boost_option) {
- case BOOST_SWITCH:
- if (msm8x16_wcd->spk_boost_set) {
- msm8x16_wcd_boost_off(codec);
- /*
- * Add 40 ms sleep for the spk
- * boost to settle down
- */
- msleep(40);
- }
- break;
- case BOOST_ALWAYS:
- msm8x16_wcd_boost_off(codec);
- /*
- * Add 40 ms sleep for the spk
- * boost to settle down
- */
- msleep(40);
- break;
- case BYPASS_ALWAYS:
- /* nothing to do as bypass on always */
- break;
- case BOOST_ON_FOREVER:
- /* nothing to do as boost on forever */
- break;
- default:
- pr_err("%s: invalid boost option: %d\n", __func__,
- msm8x16_wcd->boost_option);
- break;
- }
- }
-}
-
-static int msm8x16_wcd_dt_parse_vreg_info(struct device *dev,
- struct msm8x16_wcd_regulator *vreg, const char *vreg_name,
- bool ondemand)
-{
- int len, ret = 0;
- const __be32 *prop;
- char prop_name[CODEC_DT_MAX_PROP_SIZE];
- struct device_node *regnode = NULL;
- u32 prop_val;
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
- vreg_name);
- regnode = of_parse_phandle(dev->of_node, prop_name, 0);
-
- if (!regnode) {
- dev_err(dev, "Looking up %s property in node %s failed\n",
- prop_name, dev->of_node->full_name);
- return -ENODEV;
- }
-
- dev_err(dev, "Looking up %s property in node %s\n",
- prop_name, dev->of_node->full_name);
-
- vreg->name = vreg_name;
- vreg->ondemand = ondemand;
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,%s-voltage", vreg_name);
- prop = of_get_property(dev->of_node, prop_name, &len);
-
- if (!prop || (len != (2 * sizeof(__be32)))) {
- dev_err(dev, "%s %s property\n",
- prop ? "invalid format" : "no", prop_name);
- return -EINVAL;
- }
- vreg->min_uv = be32_to_cpup(&prop[0]);
- vreg->max_uv = be32_to_cpup(&prop[1]);
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,%s-current", vreg_name);
-
- ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
- if (ret) {
- dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
- return -EFAULT;
- }
- vreg->optimum_ua = prop_val;
-
- dev_err(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
- vreg->min_uv, vreg->max_uv, vreg->optimum_ua, vreg->ondemand);
- return 0;
-}
-
-static void msm8x16_wcd_dt_parse_boost_info(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd_priv =
- snd_soc_codec_get_drvdata(codec);
- const char *prop_name = "qcom,cdc-boost-voltage";
- int boost_voltage, ret;
-
- ret = of_property_read_u32(codec->dev->of_node, prop_name,
- &boost_voltage);
- if (ret) {
- dev_err(codec->dev, "Looking up %s property in node %s failed\n",
- prop_name, codec->dev->of_node->full_name);
- boost_voltage = DEFAULT_BOOST_VOLTAGE;
- }
- if (boost_voltage < MIN_BOOST_VOLTAGE ||
- boost_voltage > MAX_BOOST_VOLTAGE) {
- dev_err(codec->dev,
- "Incorrect boost voltage. Reverting to default\n");
- boost_voltage = DEFAULT_BOOST_VOLTAGE;
- }
-
- msm8x16_wcd_priv->boost_voltage =
- VOLTAGE_CONVERTER(boost_voltage, MIN_BOOST_VOLTAGE,
- BOOST_VOLTAGE_STEP);
- dev_err(codec->dev, "Boost voltage value is: %d\n",
- boost_voltage);
-}
-
-static void msm8x16_wcd_dt_parse_micbias_info(struct device *dev,
- struct wcd9xxx_micbias_setting *micbias)
-{
- const char *prop_name = "qcom,cdc-micbias-cfilt-mv";
- int ret;
-
- ret = of_property_read_u32(dev->of_node, prop_name,
- &micbias->cfilt1_mv);
- if (ret) {
- dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
- micbias->cfilt1_mv = MICBIAS_DEFAULT_VAL;
- }
-}
-
-static struct msm8x16_wcd_pdata *msm8x16_wcd_populate_dt_pdata(
- struct device *dev)
-{
- struct msm8x16_wcd_pdata *pdata;
- int ret, static_cnt, ond_cnt, idx, i;
- const char *name = NULL;
- const char *static_prop_name = "qcom,cdc-static-supplies";
- const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return NULL;
-
- static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
- if (static_cnt < 0) {
- dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
- static_cnt);
- ret = -EINVAL;
- goto err;
- }
-
- /* On-demand supply list is an optional property */
- ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
- if (ond_cnt < 0)
- ond_cnt = 0;
-
- WARN_ON(static_cnt <= 0 || ond_cnt < 0);
- if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
- dev_err(dev, "%s: Num of supplies %u > max supported %zd\n",
- __func__, (static_cnt + ond_cnt),
- ARRAY_SIZE(pdata->regulator));
- ret = -EINVAL;
- goto err;
- }
-
- for (idx = 0; idx < static_cnt; idx++) {
- ret = of_property_read_string_index(dev->of_node,
- static_prop_name, idx,
- &name);
- if (ret) {
- dev_err(dev, "%s: of read string %s idx %d error %d\n",
- __func__, static_prop_name, idx, ret);
- goto err;
- }
-
- dev_err(dev, "%s: Found static cdc supply %s\n", __func__,
- name);
- ret = msm8x16_wcd_dt_parse_vreg_info(dev,
- &pdata->regulator[idx],
- name, false);
- if (ret) {
- dev_err(dev, "%s:err parsing vreg for %s idx %d\n",
- __func__, name, idx);
- goto err;
- }
- }
-
- for (i = 0; i < ond_cnt; i++, idx++) {
- ret = of_property_read_string_index(dev->of_node, ond_prop_name,
- i, &name);
- if (ret) {
- dev_err(dev, "%s: err parsing on_demand for %s idx %d\n",
- __func__, ond_prop_name, i);
- goto err;
- }
-
- dev_err(dev, "%s: Found on-demand cdc supply %s\n", __func__,
- name);
- ret = msm8x16_wcd_dt_parse_vreg_info(dev,
- &pdata->regulator[idx],
- name, true);
- if (ret) {
- dev_err(dev, "%s: err parsing vreg on_demand for %s idx %d\n",
- __func__, name, idx);
- goto err;
- }
- }
- msm8x16_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
- return pdata;
-err:
- devm_kfree(dev, pdata);
- dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
- __func__, ret);
- return NULL;
-}
-
-static int msm8x16_wcd_codec_enable_on_demand_supply(
- struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- int ret = 0;
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- struct on_demand_supply *supply;
-
- if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
- dev_err(codec->dev, "%s: error index > MAX Demand supplies",
- __func__);
- ret = -EINVAL;
- goto out;
- }
- dev_err(codec->dev, "%s: supply: %s event: %d ref: %d\n",
- __func__, on_demand_supply_name[w->shift], event,
- atomic_read(&msm8x16_wcd->on_demand_list[w->shift].ref));
-
- supply = &msm8x16_wcd->on_demand_list[w->shift];
- WARN_ONCE(!supply->supply, "%s isn't defined\n",
- on_demand_supply_name[w->shift]);
- if (!supply->supply) {
- dev_err(codec->dev, "%s: err supply not present ond for %d",
- __func__, w->shift);
- goto out;
- }
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- if (atomic_inc_return(&supply->ref) == 1)
- ret = regulator_enable(supply->supply);
- if (ret)
- dev_err(codec->dev, "%s: Failed to enable %s\n",
- __func__,
- on_demand_supply_name[w->shift]);
- break;
- case SND_SOC_DAPM_POST_PMD:
- if (atomic_read(&supply->ref) == 0) {
- dev_err(codec->dev, "%s: %s supply has been disabled.\n",
- __func__, on_demand_supply_name[w->shift]);
- goto out;
- }
- if (atomic_dec_return(&supply->ref) == 0)
- ret = regulator_disable(supply->supply);
- if (ret)
- dev_err(codec->dev, "%s: Failed to disable %s\n",
- __func__,
- on_demand_supply_name[w->shift]);
- break;
- default:
- break;
- }
-out:
- return ret;
-}
-
-static int msm8x16_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
- int enable)
-{
- struct msm_asoc_mach_data *pdata = NULL;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
- if (enable) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
- if (pdata->mclk_freq == MCLK_RATE_12P288MHZ)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x00);
- else if (pdata->mclk_freq == MCLK_RATE_9P6MHZ)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x01);
- } else {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x00);
-
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: event = %d\n", __func__, event);
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- msm8x16_wcd_codec_enable_clock_block(codec, 1);
- if (!(strcmp(w->name, "EAR CP"))) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x80, 0x80);
- msm8x16_wcd_boost_mode_sequence(codec, EAR_PMU);
- } else if (get_codec_version(msm8x16_wcd) == DIANGU) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x80, 0x80);
- } else {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0xC0, 0xC0);
- }
- break;
- case SND_SOC_DAPM_POST_PMU:
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- break;
- case SND_SOC_DAPM_POST_PMD:
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- if (!(strcmp(w->name, "EAR CP"))) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x80, 0x00);
- if (msm8x16_wcd->boost_option != BOOST_ALWAYS) {
- dev_err(codec->dev,
- "%s: boost_option:%d, tear down ear\n",
- __func__, msm8x16_wcd->boost_option);
- msm8x16_wcd_boost_mode_sequence(codec, EAR_PMD);
- }
- /*
- * Reset pa select bit from ear to hph after ear pa
- * is disabled and HPH DAC disable to reduce ear
- * turn off pop and avoid HPH pop in concurrency
- */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x00);
- } else {
- if (get_codec_version(msm8x16_wcd) < DIANGU)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x40, 0x00);
- if (msm8x16_wcd->rx_bias_count == 0)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x80, 0x00);
- dev_err(codec->dev, "%s: rx_bias_count = %d\n",
- __func__, msm8x16_wcd->rx_bias_count);
- }
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_ear_pa_boost_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- ucontrol->value.integer.value[0] =
- (msm8x16_wcd->ear_pa_boost_set ? 1 : 0);
- dev_err(codec->dev, "%s: msm8x16_wcd->ear_pa_boost_set = %d\n",
- __func__, msm8x16_wcd->ear_pa_boost_set);
- return 0;
-}
-
-static int msm8x16_wcd_ear_pa_boost_set(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd =
- snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
- msm8x16_wcd->ear_pa_boost_set =
- (ucontrol->value.integer.value[0] ? true : false);
- return 0;
-}
-
-static int msm8x16_wcd_pa_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 ear_pa_gain;
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
- ear_pa_gain = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL);
-
- ear_pa_gain = (ear_pa_gain >> 5) & 0x1;
-
- if (ear_pa_gain == 0x00) {
- ucontrol->value.integer.value[0] = 0;
- } else if (ear_pa_gain == 0x01) {
- ucontrol->value.integer.value[0] = 1;
- } else {
- dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
- __func__, ear_pa_gain);
- return -EINVAL;
- }
-
- ucontrol->value.integer.value[0] = ear_pa_gain;
- dev_err(codec->dev, "%s: ear_pa_gain = 0x%x\n",
- __func__, ear_pa_gain);
- return 0;
-}
-
-static int msm8x16_wcd_loopback_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm_asoc_mach_data *pdata = NULL;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- return pdata->lb_mode;
-}
-
-static int msm8x16_wcd_loopback_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm_asoc_mach_data *pdata = NULL;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 0:
- pdata->lb_mode = false;
- break;
- case 1:
- pdata->lb_mode = true;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int msm8x16_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 ear_pa_gain;
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 0:
- ear_pa_gain = 0x00;
- break;
- case 1:
- ear_pa_gain = 0x20;
- break;
- default:
- return -EINVAL;
- }
-
- snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
- 0x20, ear_pa_gain);
- return 0;
-}
-
-static int msm8x16_wcd_hph_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (msm8x16_wcd->hph_mode == NORMAL_MODE) {
- ucontrol->value.integer.value[0] = 0;
- } else if (msm8x16_wcd->hph_mode == HD2_MODE) {
- ucontrol->value.integer.value[0] = 1;
- } else {
- dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n",
- __func__, msm8x16_wcd->hph_mode);
- }
-
- dev_err(codec->dev, "%s: msm8x16_wcd->hph_mode = %d\n", __func__,
- msm8x16_wcd->hph_mode);
- return 0;
-}
-
-static int msm8x16_wcd_hph_mode_set(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 0:
- msm8x16_wcd->hph_mode = NORMAL_MODE;
- break;
- case 1:
- if (get_codec_version(msm8x16_wcd) >= DIANGU)
- msm8x16_wcd->hph_mode = HD2_MODE;
- break;
- default:
- msm8x16_wcd->hph_mode = NORMAL_MODE;
- break;
- }
- dev_err(codec->dev, "%s: msm8x16_wcd->hph_mode_set = %d\n",
- __func__, msm8x16_wcd->hph_mode);
- return 0;
-}
-
-static int msm8x16_wcd_boost_option_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (msm8x16_wcd->boost_option == BOOST_SWITCH) {
- ucontrol->value.integer.value[0] = 0;
- } else if (msm8x16_wcd->boost_option == BOOST_ALWAYS) {
- ucontrol->value.integer.value[0] = 1;
- } else if (msm8x16_wcd->boost_option == BYPASS_ALWAYS) {
- ucontrol->value.integer.value[0] = 2;
- } else if (msm8x16_wcd->boost_option == BOOST_ON_FOREVER) {
- ucontrol->value.integer.value[0] = 3;
- } else {
- dev_err(codec->dev, "%s: ERROR: Unsupported Boost option= %d\n",
- __func__, msm8x16_wcd->boost_option);
- return -EINVAL;
- }
-
- dev_err(codec->dev, "%s: msm8x16_wcd->boost_option = %d\n", __func__,
- msm8x16_wcd->boost_option);
- return 0;
-}
-
-static int msm8x16_wcd_boost_option_set(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 0:
- msm8x16_wcd->boost_option = BOOST_SWITCH;
- break;
- case 1:
- msm8x16_wcd->boost_option = BOOST_ALWAYS;
- break;
- case 2:
- msm8x16_wcd->boost_option = BYPASS_ALWAYS;
- msm8x16_wcd_bypass_on(codec);
- break;
- case 3:
- msm8x16_wcd->boost_option = BOOST_ON_FOREVER;
- msm8x16_wcd_boost_on(codec);
- break;
- default:
- pr_err("%s: invalid boost option: %d\n", __func__,
- msm8x16_wcd->boost_option);
- return -EINVAL;
- }
- dev_err(codec->dev, "%s: msm8x16_wcd->boost_option_set = %d\n",
- __func__, msm8x16_wcd->boost_option);
- return 0;
-}
-
-static int msm8x16_wcd_ext_spk_boost_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (msm8x16_wcd->ext_spk_boost_set == false)
- ucontrol->value.integer.value[0] = 0;
- else
- ucontrol->value.integer.value[0] = 1;
-
- dev_err(codec->dev, "%s: msm8x16_wcd->ext_spk_boost_set = %d\n",
- __func__, msm8x16_wcd->ext_spk_boost_set);
- return 0;
-}
-
-static int msm8x16_wcd_ext_spk_boost_set(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 0:
- msm8x16_wcd->ext_spk_boost_set = false;
- break;
- case 1:
- msm8x16_wcd->ext_spk_boost_set = true;
- break;
- default:
- return -EINVAL;
- }
- dev_err(codec->dev, "%s: msm8x16_wcd->spk_boost_set = %d\n",
- __func__, msm8x16_wcd->spk_boost_set);
- return 0;
-}
-static int msm8x16_wcd_get_iir_enable_audio_mixer(
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- int iir_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->reg;
- int band_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->shift;
-
- ucontrol->value.integer.value[0] =
- (snd_soc_read_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
- (1 << band_idx)) != 0;
-
- dev_err(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
- iir_idx, band_idx,
- (uint32_t)ucontrol->value.integer.value[0]);
- return 0;
-}
-
-static int msm8x16_wcd_put_iir_enable_audio_mixer(
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- int iir_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->reg;
- int band_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->shift;
- int value = ucontrol->value.integer.value[0];
-
- /* Mask first 5 bits, 6-8 are reserved */
- snd_soc_update_bits_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx),
- (1 << band_idx), (value << band_idx));
-
- dev_err(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
- iir_idx, band_idx,
- ((snd_soc_read_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
- (1 << band_idx)) != 0));
-
- return 0;
-}
-static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
- int iir_idx, int band_idx,
- int coeff_idx)
-{
- uint32_t value = 0;
-
- /* Address does not automatically update if reading */
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
- ((band_idx * BAND_MAX + coeff_idx)
- * sizeof(uint32_t)) & 0x7F);
-
- value |= snd_soc_read_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx));
-
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
- ((band_idx * BAND_MAX + coeff_idx)
- * sizeof(uint32_t) + 1) & 0x7F);
-
- value |= (snd_soc_read_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
-
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
- ((band_idx * BAND_MAX + coeff_idx)
- * sizeof(uint32_t) + 2) & 0x7F);
-
- value |= (snd_soc_read_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
-
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
- ((band_idx * BAND_MAX + coeff_idx)
- * sizeof(uint32_t) + 3) & 0x7F);
-
- /* Mask bits top 2 bits since they are reserved */
- value |= ((snd_soc_read_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL
- + 64 * iir_idx)) & 0x3f) << 24);
-
- return value;
-
-}
-
-static int msm8x16_wcd_get_iir_band_audio_mixer(
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- int iir_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->reg;
- int band_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->shift;
-
- ucontrol->value.integer.value[0] =
- get_iir_band_coeff(codec, iir_idx, band_idx, 0);
- ucontrol->value.integer.value[1] =
- get_iir_band_coeff(codec, iir_idx, band_idx, 1);
- ucontrol->value.integer.value[2] =
- get_iir_band_coeff(codec, iir_idx, band_idx, 2);
- ucontrol->value.integer.value[3] =
- get_iir_band_coeff(codec, iir_idx, band_idx, 3);
- ucontrol->value.integer.value[4] =
- get_iir_band_coeff(codec, iir_idx, band_idx, 4);
-
- dev_err(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
- "%s: IIR #%d band #%d b1 = 0x%x\n"
- "%s: IIR #%d band #%d b2 = 0x%x\n"
- "%s: IIR #%d band #%d a1 = 0x%x\n"
- "%s: IIR #%d band #%d a2 = 0x%x\n",
- __func__, iir_idx, band_idx,
- (uint32_t)ucontrol->value.integer.value[0],
- __func__, iir_idx, band_idx,
- (uint32_t)ucontrol->value.integer.value[1],
- __func__, iir_idx, band_idx,
- (uint32_t)ucontrol->value.integer.value[2],
- __func__, iir_idx, band_idx,
- (uint32_t)ucontrol->value.integer.value[3],
- __func__, iir_idx, band_idx,
- (uint32_t)ucontrol->value.integer.value[4]);
- return 0;
-}
-
-static void set_iir_band_coeff(struct snd_soc_codec *codec,
- int iir_idx, int band_idx,
- uint32_t value)
-{
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
- (value & 0xFF));
-
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
- (value >> 8) & 0xFF);
-
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
- (value >> 16) & 0xFF);
-
- /* Mask top 2 bits, 7-8 are reserved */
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
- (value >> 24) & 0x3F);
-
-}
-
-static int msm8x16_wcd_put_iir_band_audio_mixer(
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- int iir_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->reg;
- int band_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->shift;
-
- /* Mask top bit it is reserved */
- /* Updates addr automatically for each B2 write */
- snd_soc_write_wrapper(codec,
- (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
- (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
-
-
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[0]);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[1]);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[2]);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[3]);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[4]);
-
- dev_err(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
- "%s: IIR #%d band #%d b1 = 0x%x\n"
- "%s: IIR #%d band #%d b2 = 0x%x\n"
- "%s: IIR #%d band #%d a1 = 0x%x\n"
- "%s: IIR #%d band #%d a2 = 0x%x\n",
- __func__, iir_idx, band_idx,
- get_iir_band_coeff(codec, iir_idx, band_idx, 0),
- __func__, iir_idx, band_idx,
- get_iir_band_coeff(codec, iir_idx, band_idx, 1),
- __func__, iir_idx, band_idx,
- get_iir_band_coeff(codec, iir_idx, band_idx, 2),
- __func__, iir_idx, band_idx,
- get_iir_band_coeff(codec, iir_idx, band_idx, 3),
- __func__, iir_idx, band_idx,
- get_iir_band_coeff(codec, iir_idx, band_idx, 4));
- return 0;
-}
-
-static int msm8x16_wcd_compander_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- int comp_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->reg;
- int rx_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->shift;
-
- dev_err(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n",
- __func__, comp_idx, rx_idx,
- msm8x16_wcd->comp_enabled[rx_idx]);
-
- ucontrol->value.integer.value[0] = msm8x16_wcd->comp_enabled[rx_idx];
-
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- return 0;
-}
-
-static int msm8x16_wcd_compander_set(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- int comp_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->reg;
- int rx_idx = ((struct soc_multi_mixer_control *)
- kcontrol->private_value)->shift;
- int value = ucontrol->value.integer.value[0];
-
- dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- if (get_codec_version(msm8x16_wcd) >= DIANGU) {
- if (!value)
- msm8x16_wcd->comp_enabled[rx_idx] = 0;
- else
- msm8x16_wcd->comp_enabled[rx_idx] = comp_idx;
- }
-
- dev_err(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n",
- __func__, comp_idx, rx_idx,
- msm8x16_wcd->comp_enabled[rx_idx]);
-
- return 0;
-}
-
-static const char * const msm8x16_wcd_loopback_mode_ctrl_text[] = {
- "DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_loopback_mode_ctl_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_loopback_mode_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_ear_pa_boost_ctrl_text[] = {
- "DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_ear_pa_boost_ctl_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ear_pa_boost_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_ear_pa_gain_text[] = {
- "POS_1P5_DB", "POS_6_DB"};
-static const struct soc_enum msm8x16_wcd_ear_pa_gain_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ear_pa_gain_text),
-};
-
-static const char * const msm8x16_wcd_boost_option_ctrl_text[] = {
- "BOOST_SWITCH", "BOOST_ALWAYS", "BYPASS_ALWAYS",
- "BOOST_ON_FOREVER"};
-static const struct soc_enum msm8x16_wcd_boost_option_ctl_enum[] = {
- SOC_ENUM_SINGLE_EXT(4, msm8x16_wcd_boost_option_ctrl_text),
-};
-static const char * const msm8x16_wcd_spk_boost_ctrl_text[] = {
- "DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_spk_boost_ctl_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_spk_boost_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_ext_spk_boost_ctrl_text[] = {
- "DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_ext_spk_boost_ctl_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ext_spk_boost_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_hph_mode_ctrl_text[] = {
- "NORMAL", "HD2"};
-static const struct soc_enum msm8x16_wcd_hph_mode_ctl_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm8x16_wcd_hph_mode_ctrl_text),
- msm8x16_wcd_hph_mode_ctrl_text),
-};
-
-/*cut of frequency for high pass filter*/
-static const char * const cf_text[] = {
- "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
-};
-
-static const struct soc_enum cf_dec1_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX1_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec2_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX2_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_rxmix1_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX1_B4_CTL, 0, 3, cf_text);
-
-static const struct soc_enum cf_rxmix2_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX2_B4_CTL, 0, 3, cf_text);
-
-static const struct soc_enum cf_rxmix3_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX3_B4_CTL, 0, 3, cf_text);
-
-static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = {
-
- SOC_ENUM_EXT("RX HPH Mode", msm8x16_wcd_hph_mode_ctl_enum[0],
- msm8x16_wcd_hph_mode_get, msm8x16_wcd_hph_mode_set),
-
- SOC_ENUM_EXT("Boost Option", msm8x16_wcd_boost_option_ctl_enum[0],
- msm8x16_wcd_boost_option_get, msm8x16_wcd_boost_option_set),
-
- SOC_ENUM_EXT("EAR PA Boost", msm8x16_wcd_ear_pa_boost_ctl_enum[0],
- msm8x16_wcd_ear_pa_boost_get, msm8x16_wcd_ear_pa_boost_set),
-
- SOC_ENUM_EXT("EAR PA Gain", msm8x16_wcd_ear_pa_gain_enum[0],
- msm8x16_wcd_pa_gain_get, msm8x16_wcd_pa_gain_put),
-
- SOC_ENUM_EXT("Ext Spk Boost", msm8x16_wcd_ext_spk_boost_ctl_enum[0],
- msm8x16_wcd_ext_spk_boost_get, msm8x16_wcd_ext_spk_boost_set),
-
- SOC_ENUM_EXT("LOOPBACK Mode", msm8x16_wcd_loopback_mode_ctl_enum[0],
- msm8x16_wcd_loopback_mode_get, msm8x16_wcd_loopback_mode_put),
-
- SOC_SINGLE_TLV("ADC1 Volume", MSM89XX_PMIC_ANALOG_TX_1_EN, 3,
- 8, 0, analog_gain),
- SOC_SINGLE_TLV("ADC2 Volume", MSM89XX_PMIC_ANALOG_TX_2_EN, 3,
- 8, 0, analog_gain),
- SOC_SINGLE_TLV("ADC3 Volume", MSM89XX_PMIC_ANALOG_TX_3_EN, 3,
- 8, 0, analog_gain),
-
- SOC_SINGLE_SX_TLV("RX1 Digital Volume",
- MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX2 Digital Volume",
- MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX3 Digital Volume",
- MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
- 0, -84, 40, digital_gain),
-
- SOC_SINGLE_SX_TLV("DEC1 Volume",
- MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("DEC2 Volume",
- MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
- 0, -84, 40, digital_gain),
-
- SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
- MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
- MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
- MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR1 INP4 Volume",
- MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR2 INP1 Volume",
- MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL,
- 0, -84, 40, digital_gain),
-
- SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
- SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
-
- SOC_SINGLE("TX1 HPF Switch",
- MSM89XX_CDC_CORE_TX1_MUX_CTL, 3, 1, 0),
- SOC_SINGLE("TX2 HPF Switch",
- MSM89XX_CDC_CORE_TX2_MUX_CTL, 3, 1, 0),
-
- SOC_SINGLE("RX1 HPF Switch",
- MSM89XX_CDC_CORE_RX1_B5_CTL, 2, 1, 0),
- SOC_SINGLE("RX2 HPF Switch",
- MSM89XX_CDC_CORE_RX2_B5_CTL, 2, 1, 0),
- SOC_SINGLE("RX3 HPF Switch",
- MSM89XX_CDC_CORE_RX3_B5_CTL, 2, 1, 0),
-
- SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
- SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
- SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
-
- SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
- SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
- msm8x16_wcd_get_iir_enable_audio_mixer,
- msm8x16_wcd_put_iir_enable_audio_mixer),
-
- SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
- SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
- msm8x16_wcd_get_iir_band_audio_mixer,
- msm8x16_wcd_put_iir_band_audio_mixer),
-
- SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM89XX_RX1, 1, 0,
- msm8x16_wcd_compander_get, msm8x16_wcd_compander_set),
-
- SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM89XX_RX2, 1, 0,
- msm8x16_wcd_compander_get, msm8x16_wcd_compander_set),
-};
-
-static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int ret;
- uint32_t zl, zr;
- bool hphr;
- struct soc_multi_mixer_control *mc;
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *priv = snd_soc_codec_get_drvdata(codec);
-
- mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
-
- hphr = mc->shift;
- ret = wcd_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
- if (ret)
- pr_err("%s: Failed to get mbhc imped", __func__);
- pr_err("%s: zl %u, zr %u\n", __func__, zl, zr);
- ucontrol->value.integer.value[0] = hphr ? zr : zl;
-
- return 0;
-}
-
-static const struct snd_kcontrol_new impedance_detect_controls[] = {
- SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
- tombak_hph_impedance_get, NULL),
- SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
- tombak_hph_impedance_get, NULL),
-};
-
-static int tombak_get_hph_type(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8x16_wcd_priv *priv = snd_soc_codec_get_drvdata(codec);
- struct wcd_mbhc *mbhc;
-
- if (!priv) {
- pr_err("%s: msm8x16-wcd private data is NULL\n",
- __func__);
- return -EINVAL;
- }
-
- mbhc = &priv->mbhc;
- if (!mbhc) {
- pr_err("%s: mbhc not initialized\n", __func__);
- return -EINVAL;
- }
-
- ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
- pr_err("%s: hph_type = %u\n", __func__, mbhc->hph_type);
-
- return 0;
-}
-
-static const struct snd_kcontrol_new hph_type_detect_controls[] = {
- SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
- tombak_get_hph_type, NULL),
-};
-
-static const char * const rx_mix1_text[] = {
- "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
-};
-
-static const char * const rx_mix2_text[] = {
- "ZERO", "IIR1", "IIR2"
-};
-
-static const char * const dec_mux_text[] = {
- "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
-};
-
-static const char * const dec3_mux_text[] = {
- "ZERO", "DMIC3"
-};
-
-static const char * const dec4_mux_text[] = {
- "ZERO", "DMIC4"
-};
-
-static const char * const adc2_mux_text[] = {
- "ZERO", "INP2", "INP3"
-};
-
-static const char * const ext_spk_text[] = {
- "Off", "On"
-};
-
-static const char * const wsa_spk_text[] = {
- "ZERO", "WSA"
-};
-
-static const char * const rdac2_mux_text[] = {
- "ZERO", "RX2", "RX1"
-};
-
-static const char * const iir_inp1_text[] = {
- "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
-};
-
-static const struct soc_enum adc2_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
-
-static const struct soc_enum ext_spk_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(ext_spk_text), ext_spk_text);
-
-static const struct soc_enum wsa_spk_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(wsa_spk_text), wsa_spk_text);
-
-/* RX1 MIX1 */
-static const struct soc_enum rx_mix1_inp1_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
- 0, 6, rx_mix1_text);
-
-static const struct soc_enum rx_mix1_inp2_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
- 3, 6, rx_mix1_text);
-
-static const struct soc_enum rx_mix1_inp3_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B2_CTL,
- 0, 6, rx_mix1_text);
-
-/* RX1 MIX2 */
-static const struct soc_enum rx_mix2_inp1_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B3_CTL,
- 0, 3, rx_mix2_text);
-
-/* RX2 MIX1 */
-static const struct soc_enum rx2_mix1_inp1_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
- 0, 6, rx_mix1_text);
-
-static const struct soc_enum rx2_mix1_inp2_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
- 3, 6, rx_mix1_text);
-
-static const struct soc_enum rx2_mix1_inp3_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
- 0, 6, rx_mix1_text);
-
-/* RX2 MIX2 */
-static const struct soc_enum rx2_mix2_inp1_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B3_CTL,
- 0, 3, rx_mix2_text);
-
-/* RX3 MIX1 */
-static const struct soc_enum rx3_mix1_inp1_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
- 0, 6, rx_mix1_text);
-
-static const struct soc_enum rx3_mix1_inp2_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
- 3, 6, rx_mix1_text);
-
-static const struct soc_enum rx3_mix1_inp3_chain_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
- 0, 6, rx_mix1_text);
-
-/* DEC */
-static const struct soc_enum dec1_mux_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
- 0, 6, dec_mux_text);
-
-static const struct soc_enum dec2_mux_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
- 3, 6, dec_mux_text);
-
-static const struct soc_enum dec3_mux_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX3_MUX_CTL, 0,
- ARRAY_SIZE(dec3_mux_text), dec3_mux_text);
-
-static const struct soc_enum dec4_mux_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX4_MUX_CTL, 0,
- ARRAY_SIZE(dec4_mux_text), dec4_mux_text);
-
-static const struct soc_enum rdac2_mux_enum =
- SOC_ENUM_SINGLE(MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL,
- 0, 3, rdac2_mux_text);
-
-static const struct soc_enum iir1_inp1_mux_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL,
- 0, 6, iir_inp1_text);
-
-static const struct soc_enum iir2_inp1_mux_enum =
- SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL,
- 0, 6, iir_inp1_text);
-
-static const struct snd_kcontrol_new ext_spk_mux =
- SOC_DAPM_ENUM("Ext Spk Switch Mux", ext_spk_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp1_mux =
- SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp2_mux =
- SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp3_mux =
- SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
- SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
- SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp3_mux =
- SOC_DAPM_ENUM("RX2 MIX1 INP3 Mux", rx2_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
- SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
- SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp3_mux =
- SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
- SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
- SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new tx_adc2_mux =
- SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
-
-static int msm8x16_wcd_put_dec_enum(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 *w = wlist->widgets[0];
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int dec_mux, decimator;
- char *dec_name = NULL;
- char *widget_name = NULL;
- char *temp;
- u16 tx_mux_ctl_reg;
- u8 adc_dmic_sel = 0x0;
- int ret = 0;
- char *dec_num;
-
- if (ucontrol->value.enumerated.item[0] > e->items) {
- dev_err(codec->dev, "%s: Invalid enum value: %d\n",
- __func__, ucontrol->value.enumerated.item[0]);
- return -EINVAL;
- }
- dec_mux = ucontrol->value.enumerated.item[0];
-
- widget_name = kstrndup(w->name, 15, GFP_KERNEL);
- if (!widget_name) {
- dev_err(codec->dev, "%s: failed to copy string\n",
- __func__);
- return -ENOMEM;
- }
- temp = widget_name;
-
- dec_name = strsep(&widget_name, " ");
- widget_name = temp;
- if (!dec_name) {
- dev_err(codec->dev, "%s: Invalid decimator = %s\n",
- __func__, w->name);
- ret = -EINVAL;
- goto out;
- }
-
- dec_num = strpbrk(dec_name, "12");
- if (dec_num == NULL) {
- dev_err(codec->dev, "%s: Invalid DEC selected\n", __func__);
- ret = -EINVAL;
- goto out;
- }
-
- ret = kstrtouint(dec_num, 10, &decimator);
- if (ret < 0) {
- dev_err(codec->dev, "%s: Invalid decimator = %s\n",
- __func__, dec_name);
- ret = -EINVAL;
- goto out;
- }
-
- dev_err(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
- , __func__, w->name, decimator, dec_mux);
-
- switch (decimator) {
- case 1:
- case 2:
- if ((dec_mux == 4) || (dec_mux == 5))
- adc_dmic_sel = 0x1;
- else
- adc_dmic_sel = 0x0;
- break;
- default:
- dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
- __func__, decimator);
- ret = -EINVAL;
- goto out;
- }
-
- tx_mux_ctl_reg =
- MSM89XX_CDC_CORE_TX1_MUX_CTL + 32 * (decimator - 1);
-
- snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
-
- ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
-out:
- kfree(widget_name);
- return ret;
-}
-
-#define MSM89XX_DEC_ENUM(xname, xenum) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_enum_double, \
- .get = snd_soc_dapm_get_enum_double, \
- .put = msm8x16_wcd_put_dec_enum, \
- .private_value = (unsigned long)&xenum }
-
-static const struct snd_kcontrol_new dec1_mux =
- MSM89XX_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
-
-static const struct snd_kcontrol_new dec2_mux =
- MSM89XX_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
-
-static const struct snd_kcontrol_new dec3_mux =
- SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
-
-static const struct snd_kcontrol_new dec4_mux =
- SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
-
-static const struct snd_kcontrol_new rdac2_mux =
- SOC_DAPM_ENUM("RDAC2 MUX Mux", rdac2_mux_enum);
-
-static const struct snd_kcontrol_new iir1_inp1_mux =
- SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
-
-static const char * const ear_text[] = {
- "ZERO", "Switch",
-};
-
-static const struct soc_enum ear_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(ear_text), ear_text);
-
-static const struct snd_kcontrol_new ear_pa_mux[] = {
- SOC_DAPM_ENUM("EAR_S", ear_enum)
-};
-
-static const struct snd_kcontrol_new wsa_spk_mux[] = {
- SOC_DAPM_ENUM("WSA Spk Switch", wsa_spk_enum)
-};
-
-static const struct snd_kcontrol_new iir2_inp1_mux =
- SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
-
-static const char * const hph_text[] = {
- "ZERO", "Switch",
-};
-
-static const struct soc_enum hph_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
-
-static const struct snd_kcontrol_new hphl_mux[] = {
- SOC_DAPM_ENUM("HPHL", hph_enum)
-};
-
-static const struct snd_kcontrol_new hphr_mux[] = {
- SOC_DAPM_ENUM("HPHR", hph_enum)
-};
-
-static const struct snd_kcontrol_new spkr_mux[] = {
- SOC_DAPM_ENUM("SPK", hph_enum)
-};
-
-static const char * const lo_text[] = {
- "ZERO", "Switch",
-};
-
-static const struct soc_enum lo_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
-
-static const struct snd_kcontrol_new lo_mux[] = {
- SOC_DAPM_ENUM("LINE_OUT", lo_enum)
-};
-
-static void msm8x16_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
- int enable)
-{
- struct msm8x16_wcd_priv *wcd8x16 = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s %d\n", __func__, enable);
-
- if (enable) {
- wcd8x16->adc_count++;
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
- 0x20, 0x20);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x10, 0x10);
- } else {
- wcd8x16->adc_count--;
- if (!wcd8x16->adc_count) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x10, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
- 0x20, 0x0);
- }
- }
-}
-
-static int msm8x16_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- u16 adc_reg;
- u8 init_bit_shift;
-
- dev_err(codec->dev, "%s %d\n", __func__, event);
-
- adc_reg = MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2;
-
- if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
- init_bit_shift = 5;
- else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
- (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
- init_bit_shift = 4;
- else {
- dev_err(codec->dev, "%s: Error, invalid adc register\n",
- __func__);
- return -EINVAL;
- }
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- msm8x16_wcd_codec_enable_adc_block(codec, 1);
- if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x02);
- /*
- * Add delay of 10 ms to give sufficient time for the voltage
- * to shoot up and settle so that the txfe init does not
- * happen when the input voltage is changing too much.
- */
- usleep_range(10000, 10010);
- snd_soc_update_bits_wrapper(codec,
- adc_reg, 1 << init_bit_shift,
- 1 << init_bit_shift);
- if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
- 0x03, 0x00);
- else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
- (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
- 0x03, 0x00);
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- break;
- case SND_SOC_DAPM_POST_PMU:
- /*
- * Add delay of 12 ms before deasserting the init
- * to reduce the tx pop
- */
- usleep_range(12000, 12010);
- snd_soc_update_bits_wrapper(codec,
- adc_reg, 1 << init_bit_shift, 0x00);
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- break;
- case SND_SOC_DAPM_POST_PMD:
- msm8x16_wcd_codec_enable_adc_block(codec, 0);
- if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x00);
- if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
- 0x03, 0x02);
- else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
- (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
- 0x03, 0x02);
-
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s %d %s\n", __func__, event, w->name);
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x01);
- switch (msm8x16_wcd->boost_option) {
- case BOOST_SWITCH:
- if (!msm8x16_wcd->spk_boost_set)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
- 0x10, 0x10);
- break;
- case BOOST_ALWAYS:
- case BOOST_ON_FOREVER:
- break;
- case BYPASS_ALWAYS:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
- 0x10, 0x10);
- break;
- default:
- pr_err("%s: invalid boost option: %d\n", __func__,
- msm8x16_wcd->boost_option);
- break;
- }
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0xE0);
- if (get_codec_version(msm8x16_wcd) != TOMBAK_1_0)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x01);
- break;
- case SND_SOC_DAPM_POST_PMU:
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- switch (msm8x16_wcd->boost_option) {
- case BOOST_SWITCH:
- if (msm8x16_wcd->spk_boost_set)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
- 0xEF, 0xEF);
- else
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
- 0x10, 0x00);
- break;
- case BOOST_ALWAYS:
- case BOOST_ON_FOREVER:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
- 0xEF, 0xEF);
- break;
- case BYPASS_ALWAYS:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
- break;
- default:
- pr_err("%s: invalid boost option: %d\n", __func__,
- msm8x16_wcd->boost_option);
- break;
- }
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
- snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x80);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x01);
- msm8x16_wcd->mute_mask |= SPKR_PA_DISABLE;
- /*
- * Add 1 ms sleep for the mute to take effect
- */
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x10);
- if (get_codec_version(msm8x16_wcd) < CAJON_2_0)
- msm8x16_wcd_boost_mode_sequence(codec, SPK_PMD);
- snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x00);
- switch (msm8x16_wcd->boost_option) {
- case BOOST_SWITCH:
- if (msm8x16_wcd->spk_boost_set)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
- 0xEF, 0x69);
- break;
- case BOOST_ALWAYS:
- case BOOST_ON_FOREVER:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
- 0xEF, 0x69);
- break;
- case BYPASS_ALWAYS:
- break;
- default:
- pr_err("%s: invalid boost option: %d\n", __func__,
- msm8x16_wcd->boost_option);
- break;
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0x00);
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
- if (get_codec_version(msm8x16_wcd) != TOMBAK_1_0)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
- if (get_codec_version(msm8x16_wcd) >= CAJON_2_0)
- msm8x16_wcd_boost_mode_sequence(codec, SPK_PMD);
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_dig_clk(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- struct msm_asoc_mach_data *pdata = NULL;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
-
- dev_err(codec->dev, "%s event %d w->name %s\n", __func__,
- event, w->name);
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- msm8x16_wcd_codec_enable_clock_block(codec, 1);
- snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x80);
- msm8x16_wcd_boost_mode_sequence(codec, SPK_PMU);
- break;
- case SND_SOC_DAPM_POST_PMD:
- if (msm8x16_wcd->rx_bias_count == 0)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x80, 0x00);
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- u8 dmic_clk_en;
- u16 dmic_clk_reg;
- s32 *dmic_clk_cnt;
- unsigned int dmic;
- int ret;
- char *dec_num = strpbrk(w->name, "12");
-
- if (dec_num == NULL) {
- dev_err(codec->dev, "%s: Invalid DMIC\n", __func__);
- return -EINVAL;
- }
-
- ret = kstrtouint(dec_num, 10, &dmic);
- if (ret < 0) {
- dev_err(codec->dev,
- "%s: Invalid DMIC line on the codec\n", __func__);
- return -EINVAL;
- }
-
- switch (dmic) {
- case 1:
- case 2:
- dmic_clk_en = 0x01;
- dmic_clk_cnt = &(msm8x16_wcd->dmic_1_2_clk_cnt);
- dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL;
- dev_err(codec->dev,
- "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
- __func__, event, dmic, *dmic_clk_cnt);
- break;
- default:
- dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
- return -EINVAL;
- }
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- (*dmic_clk_cnt)++;
- if (*dmic_clk_cnt == 1) {
- snd_soc_update_bits_wrapper(codec, dmic_clk_reg,
- 0x0E, 0x02);
- snd_soc_update_bits_wrapper(codec, dmic_clk_reg,
- dmic_clk_en, dmic_clk_en);
- }
- if (dmic == 1)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_TX1_DMIC_CTL, 0x07, 0x01);
- if (dmic == 2)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_TX2_DMIC_CTL, 0x07, 0x01);
- break;
- case SND_SOC_DAPM_POST_PMD:
- (*dmic_clk_cnt)--;
- if (*dmic_clk_cnt == 0)
- snd_soc_update_bits_wrapper(codec, dmic_clk_reg,
- dmic_clk_en, 0);
- break;
- }
- return 0;
-}
-
-static bool msm8x16_wcd_use_mb(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (get_codec_version(msm8x16_wcd) < CAJON)
- return true;
- else
- return false;
-}
-
-static void msm8x16_wcd_set_auto_zeroing(struct snd_soc_codec *codec,
- bool enable)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (get_codec_version(msm8x16_wcd) < CONGA) {
- if (enable)
- /*
- * Set autozeroing for special headset detection and
- * buttons to work.
- */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN,
- 0x18, 0x10);
- else
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN,
- 0x18, 0x00);
-
- } else {
- pr_err("%s: Auto Zeroing is not required from CONGA\n",
- __func__);
- }
-}
-
-static void msm8x16_trim_btn_reg(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if (get_codec_version(msm8x16_wcd) == TOMBAK_1_0) {
- pr_err("%s: This device needs to be trimmed\n", __func__);
- /*
- * Calculate the trim value for each device used
- * till is comes in production by hardware team
- */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SEC_ACCESS,
- 0xA5, 0xA5);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_TRIM_CTRL2,
- 0xFF, 0x30);
- } else {
- pr_err("%s: This device is trimmed at ATE\n", __func__);
- }
-}
-static int msm8x16_wcd_enable_ext_mb_source(struct wcd_mbhc *mbhc,
- bool turn_on)
-{
- int ret = 0;
- static int count;
- struct snd_soc_codec *codec = mbhc->codec;
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-
- dev_err(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
- count);
- if (turn_on) {
- if (!count) {
- ret = snd_soc_dapm_force_enable_pin(dapm,
- "MICBIAS_REGULATOR");
- snd_soc_dapm_sync(dapm);
- }
- count++;
- } else {
- if (count > 0)
- count--;
- if (!count) {
- ret = snd_soc_dapm_disable_pin(dapm,
- "MICBIAS_REGULATOR");
- snd_soc_dapm_sync(dapm);
- }
- }
-
- if (ret)
- dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
- __func__, turn_on ? "enable" : "disabled");
- else
- dev_err(codec->dev, "%s: %s external micbias source\n",
- __func__, turn_on ? "Enabled" : "Disabled");
-
- return ret;
-}
-
-static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd =
- snd_soc_codec_get_drvdata(codec);
- u16 micb_int_reg;
- char *internal1_text = "Internal1";
- char *internal2_text = "Internal2";
- char *internal3_text = "Internal3";
- char *external2_text = "External2";
- char *external_text = "External";
- bool micbias2;
-
- dev_err(codec->dev, "%s %d\n", __func__, event);
- switch (w->reg) {
- case MSM89XX_PMIC_ANALOG_MICB_1_EN:
- case MSM89XX_PMIC_ANALOG_MICB_2_EN:
- micb_int_reg = MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS;
- break;
- default:
- dev_err(codec->dev,
- "%s: Error, invalid micbias register 0x%x\n",
- __func__, w->reg);
- return -EINVAL;
- }
-
- micbias2 = (snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_2_EN) & 0x80);
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- if (strnstr(w->name, internal1_text, strlen(w->name))) {
- if (get_codec_version(msm8x16_wcd) >= CAJON)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
- 0x02, 0x02);
- snd_soc_update_bits_wrapper(codec,
- micb_int_reg, 0x80, 0x80);
- } else if (strnstr(w->name, internal2_text, strlen(w->name))) {
- snd_soc_update_bits_wrapper(codec,
- micb_int_reg, 0x10, 0x10);
- snd_soc_update_bits_wrapper(codec,
- w->reg, 0x60, 0x00);
- } else if (strnstr(w->name, internal3_text, strlen(w->name))) {
- snd_soc_update_bits_wrapper(codec,
- micb_int_reg, 0x2, 0x2);
- /*
- * update MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2
- * for external bias only, not for external2.
- */
- } else if (!strnstr(w->name, external2_text, strlen(w->name)) &&
- strnstr(w->name, external_text,
- strlen(w->name))) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
- 0x02, 0x02);
- }
- if (!strnstr(w->name, external_text, strlen(w->name)))
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_EN, 0x05, 0x04);
- if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
- msm8x16_wcd_configure_cap(codec, true, micbias2);
-
- break;
- case SND_SOC_DAPM_POST_PMU:
- if (get_codec_version(msm8x16_wcd) <= TOMBAK_2_0)
- usleep_range(20000, 20100);
- if (strnstr(w->name, internal1_text, strlen(w->name))) {
- snd_soc_update_bits_wrapper(codec,
- micb_int_reg, 0x40, 0x40);
- } else if (strnstr(w->name, internal2_text, strlen(w->name))) {
- snd_soc_update_bits_wrapper(codec,
- micb_int_reg, 0x08, 0x08);
- msm8x16_notifier_call(codec,
- WCD_EVENT_POST_MICBIAS_2_ON);
- } else if (strnstr(w->name, internal3_text, 30)) {
- snd_soc_update_bits_wrapper(codec,
- micb_int_reg, 0x01, 0x01);
- } else if (strnstr(w->name, external2_text, strlen(w->name))) {
- msm8x16_notifier_call(codec,
- WCD_EVENT_POST_MICBIAS_2_ON);
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- if (strnstr(w->name, internal1_text, strlen(w->name))) {
- snd_soc_update_bits_wrapper(codec,
- micb_int_reg, 0xC0, 0x40);
- } else if (strnstr(w->name, internal2_text, strlen(w->name))) {
- msm8x16_notifier_call(codec,
- WCD_EVENT_POST_MICBIAS_2_OFF);
- } else if (strnstr(w->name, internal3_text, 30)) {
- snd_soc_update_bits_wrapper(codec,
- micb_int_reg, 0x2, 0x0);
- } else if (strnstr(w->name, external2_text, strlen(w->name))) {
- /*
- * send micbias turn off event to mbhc driver and then
- * break, as no need to set MICB_1_EN register.
- */
- msm8x16_notifier_call(codec,
- WCD_EVENT_POST_MICBIAS_2_OFF);
- break;
- }
- if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
- msm8x16_wcd_configure_cap(codec, false, micbias2);
- break;
- }
- return 0;
-}
-
-static void tx_hpf_corner_freq_callback(struct work_struct *work)
-{
- struct delayed_work *hpf_delayed_work;
- struct hpf_work *hpf_work;
- struct msm8x16_wcd_priv *msm8x16_wcd;
- struct snd_soc_codec *codec;
- u16 tx_mux_ctl_reg;
- u8 hpf_cut_of_freq;
-
- hpf_delayed_work = to_delayed_work(work);
- hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
- msm8x16_wcd = hpf_work->msm8x16_wcd;
- codec = hpf_work->msm8x16_wcd->codec;
- hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
-
- tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
- (hpf_work->decimator - 1) * 32;
-
- dev_err(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
- __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV, 0xFF, 0x51);
-
- snd_soc_update_bits_wrapper(codec,
- tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
-}
-
-
-#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
-#define CF_MIN_3DB_4HZ 0x0
-#define CF_MIN_3DB_75HZ 0x1
-#define CF_MIN_3DB_150HZ 0x2
-
-static int msm8x16_wcd_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- int value = 0, reg;
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- if (w->shift == 0)
- reg = MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL;
- else if (w->shift == 1)
- reg = MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL;
- value = snd_soc_read_wrapper(codec, reg);
- snd_soc_write_wrapper(codec, reg, value);
- break;
- default:
- pr_err("%s: event = %d not expected\n", __func__, event);
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm_asoc_mach_data *pdata = NULL;
- unsigned int decimator;
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- char *dec_name = NULL;
- char *widget_name = NULL;
- char *temp;
- int ret = 0, i;
- u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
- u8 dec_hpf_cut_of_freq;
- int offset;
- char *dec_num;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
- dev_err(codec->dev, "%s %d\n", __func__, event);
-
- widget_name = kstrndup(w->name, 15, GFP_KERNEL);
- if (!widget_name)
- return -ENOMEM;
- temp = widget_name;
-
- dec_name = strsep(&widget_name, " ");
- widget_name = temp;
- if (!dec_name) {
- dev_err(codec->dev,
- "%s: Invalid decimator = %s\n", __func__, w->name);
- ret = -EINVAL;
- goto out;
- }
-
- dec_num = strpbrk(dec_name, "1234");
- if (dec_num == NULL) {
- dev_err(codec->dev, "%s: Invalid Decimator\n", __func__);
- ret = -EINVAL;
- goto out;
- }
-
- ret = kstrtouint(dec_num, 10, &decimator);
- if (ret < 0) {
- dev_err(codec->dev,
- "%s: Invalid decimator = %s\n", __func__, dec_name);
- ret = -EINVAL;
- goto out;
- }
-
- dev_err(codec->dev,
- "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
- w->name, dec_name, decimator);
-
- if (w->reg == MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL) {
- dec_reset_reg = MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL;
- offset = 0;
- } else {
- dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
- ret = -EINVAL;
- goto out;
- }
-
- tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
- 32 * (decimator - 1);
- tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
- 32 * (decimator - 1);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- if (decimator == 3 || decimator == 4) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL,
- 0xFF, 0x5);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_TX1_DMIC_CTL +
- (decimator - 1) * 0x20, 0x7, 0x2);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_TX1_DMIC_CTL +
- (decimator - 1) * 0x20, 0x7, 0x2);
- }
- /* Enableable TX digital mute */
- snd_soc_update_bits_wrapper(codec, tx_vol_ctl_reg, 0x01, 0x01);
- for (i = 0; i < NUM_DECIMATORS; i++) {
- if (decimator == i + 1)
- msm8x16_wcd->dec_active[i] = true;
- }
-
- dec_hpf_cut_of_freq =
- snd_soc_read_wrapper(codec, tx_mux_ctl_reg);
-
- dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
-
- tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
- dec_hpf_cut_of_freq;
-
- if (dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ) {
-
- /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
- snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x30,
- CF_MIN_3DB_150HZ << 4);
- }
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV,
- 0xFF, 0x42);
-
- break;
- case SND_SOC_DAPM_POST_PMU:
- /* enable HPF */
- snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x08, 0x00);
-
- if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
- CF_MIN_3DB_150HZ) {
-
- schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
- msecs_to_jiffies(300));
- }
- /* apply the digital gain after the decimator is enabled*/
- if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
- snd_soc_write_wrapper(codec,
- tx_digital_gain_reg[w->shift + offset],
- snd_soc_read_wrapper(codec,
- tx_digital_gain_reg[w->shift + offset])
- );
- if (pdata->lb_mode) {
- pr_err("%s: loopback mode unmute the DEC\n",
- __func__);
- snd_soc_update_bits_wrapper(codec,
- tx_vol_ctl_reg, 0x01, 0x00);
- }
- break;
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits_wrapper(codec, tx_vol_ctl_reg, 0x01, 0x01);
- msleep(20);
- snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x08, 0x08);
- cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
- break;
- case SND_SOC_DAPM_POST_PMD:
- snd_soc_update_bits_wrapper(codec,
- dec_reset_reg, 1 << w->shift, 1 << w->shift);
- snd_soc_update_bits_wrapper(codec,
- dec_reset_reg, 1 << w->shift, 0x0);
- snd_soc_update_bits_wrapper(codec,
- tx_mux_ctl_reg, 0x08, 0x08);
- snd_soc_update_bits_wrapper(codec,
- tx_mux_ctl_reg, 0x30,
- (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
- snd_soc_update_bits_wrapper(codec,
- tx_vol_ctl_reg, 0x01, 0x00);
- for (i = 0; i < NUM_DECIMATORS; i++) {
- if (decimator == i + 1)
- msm8x16_wcd->dec_active[i] = false;
- }
- if (decimator == 3 || decimator == 4) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL,
- 0xFF, 0x0);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_TX1_DMIC_CTL +
- (decimator - 1) * 0x20, 0x7, 0x0);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_TX1_DMIC_CTL +
- (decimator - 1) * 0x20, 0x7, 0x0);
- }
- break;
- }
-out:
- kfree(widget_name);
- return ret;
-}
-
-static int msm89xx_wcd_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
-
- if (!msm8x16_wcd->ext_spk_boost_set) {
- dev_err(codec->dev, "%s: ext_boost not supported/disabled\n",
- __func__);
- return 0;
- }
- dev_err(codec->dev, "%s: %s %d\n", __func__, w->name, event);
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- if (msm8x16_wcd->spkdrv_reg) {
- ret = regulator_enable(msm8x16_wcd->spkdrv_reg);
- if (ret)
- dev_err(codec->dev,
- "%s Failed to enable spkdrv reg %s\n",
- __func__, MSM89XX_VDD_SPKDRV_NAME);
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- if (msm8x16_wcd->spkdrv_reg) {
- ret = regulator_disable(msm8x16_wcd->spkdrv_reg);
- if (ret)
- dev_err(codec->dev,
- "%s: Failed to disable spkdrv_reg %s\n",
- __func__, MSM89XX_VDD_SPKDRV_NAME);
- }
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_config_compander(struct snd_soc_codec *codec,
- int interp_n, int event)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: event %d shift %d, enabled %d\n",
- __func__, event, interp_n,
- msm8x16_wcd->comp_enabled[interp_n]);
-
- /* compander is not enabled */
- if (!msm8x16_wcd->comp_enabled[interp_n])
- return 0;
-
- switch (msm8x16_wcd->comp_enabled[interp_n]) {
- case COMPANDER_1:
- if (SND_SOC_DAPM_EVENT_ON(event)) {
- /* Enable Compander Clock */
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_COMP0_B1_CTL,
- 1 << interp_n, 1 << interp_n);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50);
- /* add sleep for compander to settle */
- usleep_range(1000, 1100);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0);
-
- /* Enable Compander GPIO */
- if (msm8x16_wcd->codec_hph_comp_gpio)
- msm8x16_wcd->codec_hph_comp_gpio(1);
- } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
- /* Disable Compander GPIO */
- if (msm8x16_wcd->codec_hph_comp_gpio)
- msm8x16_wcd->codec_hph_comp_gpio(0);
-
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_COMP0_B1_CTL,
- 1 << interp_n, 0);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00);
- }
- break;
- default:
- dev_err(codec->dev, "%s: Invalid compander %d\n", __func__,
- msm8x16_wcd->comp_enabled[interp_n]);
- break;
- };
-
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol,
- int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s %d %s\n", __func__, event, w->name);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- msm8x16_wcd_codec_config_compander(codec, w->shift, event);
- /* apply the digital gain after the interpolator is enabled*/
- if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
- snd_soc_write_wrapper(codec,
- rx_digital_gain_reg[w->shift],
- snd_soc_read_wrapper(codec,
- rx_digital_gain_reg[w->shift])
- );
- break;
- case SND_SOC_DAPM_POST_PMD:
- msm8x16_wcd_codec_config_compander(codec, w->shift, event);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
- 1 << w->shift, 1 << w->shift);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
- 1 << w->shift, 0x0);
- /*
- * disable the mute enabled during the PMD of this device
- */
- if ((w->shift == 0) &&
- (msm8x16_wcd->mute_mask & HPHL_PA_DISABLE)) {
- pr_err("disabling HPHL mute\n");
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
- if (get_codec_version(msm8x16_wcd) >= CAJON)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
- 0xF0, 0x20);
- msm8x16_wcd->mute_mask &= ~(HPHL_PA_DISABLE);
- } else if ((w->shift == 1) &&
- (msm8x16_wcd->mute_mask & HPHR_PA_DISABLE)) {
- pr_err("disabling HPHR mute\n");
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
- if (get_codec_version(msm8x16_wcd) >= CAJON)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
- 0xF0, 0x20);
- msm8x16_wcd->mute_mask &= ~(HPHR_PA_DISABLE);
- } else if ((w->shift == 2) &&
- (msm8x16_wcd->mute_mask & SPKR_PA_DISABLE)) {
- pr_err("disabling SPKR mute\n");
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
- msm8x16_wcd->mute_mask &= ~(SPKR_PA_DISABLE);
- } else if ((w->shift == 0) &&
- (msm8x16_wcd->mute_mask & EAR_PA_DISABLE)) {
- pr_err("disabling EAR mute\n");
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
- msm8x16_wcd->mute_mask &= ~(EAR_PA_DISABLE);
- }
- }
- return 0;
-}
-
-
-/* The register address is the same as other codec so it can use resmgr */
-static int msm8x16_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s %d\n", __func__, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- msm8x16_wcd->rx_bias_count++;
- if (msm8x16_wcd->rx_bias_count == 1) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
- 0x80, 0x80);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
- 0x01, 0x01);
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- msm8x16_wcd->rx_bias_count--;
- if (msm8x16_wcd->rx_bias_count == 0) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
- 0x01, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
- 0x80, 0x00);
- }
- break;
- }
- dev_err(codec->dev, "%s rx_bias_count = %d\n",
- __func__, msm8x16_wcd->rx_bias_count);
- return 0;
-}
-
-static uint32_t wcd_get_impedance_value(uint32_t imped)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(wcd_imped_val) - 1; i++) {
- if (imped >= wcd_imped_val[i] &&
- imped < wcd_imped_val[i + 1])
- break;
- }
-
- pr_err("%s: selected impedance value = %d\n",
- __func__, wcd_imped_val[i]);
- return wcd_imped_val[i];
-}
-
-void wcd_imped_config(struct snd_soc_codec *codec,
- uint32_t imped, bool set_gain)
-{
- uint32_t value;
- int codec_version;
- struct msm8x16_wcd_priv *msm8x16_wcd =
- snd_soc_codec_get_drvdata(codec);
-
- value = wcd_get_impedance_value(imped);
-
- if (value < wcd_imped_val[0]) {
- pr_err("%s, detected impedance is less than 4 Ohm\n",
- __func__);
- return;
- }
- if (value >= wcd_imped_val[ARRAY_SIZE(wcd_imped_val) - 1]) {
- pr_err("%s, invalid imped, greater than 48 Ohm\n = %d\n",
- __func__, value);
- return;
- }
-
- codec_version = get_codec_version(msm8x16_wcd);
-
- if (set_gain) {
- switch (codec_version) {
- case TOMBAK_1_0:
- case TOMBAK_2_0:
- case CONGA:
- /*
- * For 32Ohm load and higher loads, Set 0x19E
- * bit 5 to 1 (POS_6_DB_DI). For loads lower
- * than 32Ohm (such as 16Ohm load), Set 0x19E
- * bit 5 to 0 (POS_1P5_DB_DI)
- */
- if (value >= 32)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
- 0x20, 0x20);
- else
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
- 0x20, 0x00);
- break;
- case CAJON:
- case CAJON_2_0:
- case DIANGU:
- if (value >= 13) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
- 0x20, 0x20);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_NCP_VCTRL,
- 0x07, 0x07);
- } else {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
- 0x20, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_NCP_VCTRL,
- 0x07, 0x04);
- }
- break;
- }
- } else {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
- 0x20, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_NCP_VCTRL,
- 0x07, 0x04);
- }
-
- pr_err("%s: Exit\n", __func__);
-}
-
-static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- uint32_t impedl, impedr;
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event);
- ret = wcd_mbhc_get_impedance(&msm8x16_wcd->mbhc,
- &impedl, &impedr);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- if (get_codec_version(msm8x16_wcd) > CAJON)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
- 0x08, 0x08);
- if (get_codec_version(msm8x16_wcd) == CAJON ||
- get_codec_version(msm8x16_wcd) == CAJON_2_0) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST,
- 0x80, 0x80);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST,
- 0x80, 0x80);
- }
- if (get_codec_version(msm8x16_wcd) > CAJON)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
- 0x08, 0x00);
- if (msm8x16_wcd->hph_mode == HD2_MODE) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x80);
- }
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02);
- if (!ret)
- wcd_imped_config(codec, impedl, true);
- else
- dev_err(codec->dev, "Failed to get mbhc impedance %d\n",
- ret);
- break;
- case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x00);
- break;
- case SND_SOC_DAPM_POST_PMD:
- wcd_imped_config(codec, impedl, false);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00);
- if (msm8x16_wcd->hph_mode == HD2_MODE) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x00);
- }
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_lo_dac_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);
-
- dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x20);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x80);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40);
- break;
- case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x80);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x40);
- break;
- case SND_SOC_DAPM_POST_PMD:
- usleep_range(20000, 20100);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_hphr_dac_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);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- if (msm8x16_wcd->hph_mode == HD2_MODE) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x80);
- }
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01);
- break;
- case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x00);
- break;
- case SND_SOC_DAPM_POST_PMD:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00);
- if (msm8x16_wcd->hph_mode == HD2_MODE) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x00);
- }
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_hph_pa_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);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- if (w->shift == 5)
- msm8x16_notifier_call(codec,
- WCD_EVENT_PRE_HPHL_PA_ON);
- else if (w->shift == 4)
- msm8x16_notifier_call(codec,
- WCD_EVENT_PRE_HPHR_PA_ON);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x20, 0x20);
- break;
-
- case SND_SOC_DAPM_POST_PMU:
- usleep_range(7000, 7100);
- if (w->shift == 5) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
- } else if (w->shift == 4) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
- }
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- if (w->shift == 5) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01);
- msleep(20);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x00);
- msm8x16_wcd->mute_mask |= HPHL_PA_DISABLE;
- msm8x16_notifier_call(codec,
- WCD_EVENT_PRE_HPHL_PA_OFF);
- } else if (w->shift == 4) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x01);
- msleep(20);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x00);
- msm8x16_wcd->mute_mask |= HPHR_PA_DISABLE;
- msm8x16_notifier_call(codec,
- WCD_EVENT_PRE_HPHR_PA_OFF);
- }
- if (get_codec_version(msm8x16_wcd) >= CAJON) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
- 0xF0, 0x30);
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- if (w->shift == 5) {
- clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK,
- &msm8x16_wcd->mbhc.hph_pa_dac_state);
- msm8x16_notifier_call(codec,
- WCD_EVENT_POST_HPHL_PA_OFF);
- } else if (w->shift == 4) {
- clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK,
- &msm8x16_wcd->mbhc.hph_pa_dac_state);
- msm8x16_notifier_call(codec,
- WCD_EVENT_POST_HPHR_PA_OFF);
- }
- usleep_range(4000, 4100);
- usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-
- dev_err(codec->dev,
- "%s: sleep 10 ms after %s PA disable.\n", __func__,
- w->name);
- usleep_range(10000, 10100);
- break;
- }
- return 0;
-}
-
-static const struct snd_soc_dapm_route audio_map[] = {
- {"RX_I2S_CLK", NULL, "CDC_CONN"},
- {"I2S RX1", NULL, "RX_I2S_CLK"},
- {"I2S RX2", NULL, "RX_I2S_CLK"},
- {"I2S RX3", NULL, "RX_I2S_CLK"},
-
- {"I2S TX1", NULL, "TX_I2S_CLK"},
- {"I2S TX2", NULL, "TX_I2S_CLK"},
- {"AIF2 VI", NULL, "TX_I2S_CLK"},
-
- {"I2S TX1", NULL, "DEC1 MUX"},
- {"I2S TX2", NULL, "DEC2 MUX"},
- {"AIF2 VI", NULL, "DEC3 MUX"},
- {"AIF2 VI", NULL, "DEC4 MUX"},
-
- /* RDAC Connections */
- {"HPHR DAC", NULL, "RDAC2 MUX"},
- {"RDAC2 MUX", "RX1", "RX1 CHAIN"},
- {"RDAC2 MUX", "RX2", "RX2 CHAIN"},
-
- /* WSA */
- {"WSA_SPK OUT", NULL, "WSA Spk Switch"},
- {"WSA Spk Switch", "WSA", "EAR PA"},
-
- /* Earpiece (RX MIX1) */
- {"EAR", NULL, "EAR_S"},
- {"EAR_S", "Switch", "EAR PA"},
- {"EAR PA", NULL, "RX_BIAS"},
- {"EAR PA", NULL, "HPHL DAC"},
- {"EAR PA", NULL, "HPHR DAC"},
- {"EAR PA", NULL, "EAR CP"},
-
- /* Headset (RX MIX1 and RX MIX2) */
- {"HEADPHONE", NULL, "HPHL PA"},
- {"HEADPHONE", NULL, "HPHR PA"},
-
- {"Ext Spk", NULL, "Ext Spk Switch"},
- {"Ext Spk Switch", "On", "HPHL PA"},
- {"Ext Spk Switch", "On", "HPHR PA"},
-
- {"HPHL PA", NULL, "HPHL"},
- {"HPHR PA", NULL, "HPHR"},
- {"HPHL", "Switch", "HPHL DAC"},
- {"HPHR", "Switch", "HPHR DAC"},
- {"HPHL PA", NULL, "CP"},
- {"HPHL PA", NULL, "RX_BIAS"},
- {"HPHR PA", NULL, "CP"},
- {"HPHR PA", NULL, "RX_BIAS"},
- {"HPHL DAC", NULL, "RX1 CHAIN"},
-
- {"SPK_OUT", NULL, "SPK PA"},
- {"SPK PA", NULL, "SPK_RX_BIAS"},
- {"SPK PA", NULL, "SPK"},
- {"SPK", "Switch", "SPK DAC"},
- {"SPK DAC", NULL, "RX3 CHAIN"},
- {"SPK DAC", NULL, "VDD_SPKDRV"},
-
- /* lineout */
- {"LINEOUT", NULL, "LINEOUT PA"},
- {"LINEOUT PA", NULL, "SPK_RX_BIAS"},
- {"LINEOUT PA", NULL, "LINE_OUT"},
- {"LINE_OUT", "Switch", "LINEOUT DAC"},
- {"LINEOUT DAC", NULL, "RX3 CHAIN"},
-
- /* lineout to WSA */
- {"WSA_SPK OUT", NULL, "LINEOUT PA"},
-
- {"RX1 CHAIN", NULL, "RX1 CLK"},
- {"RX2 CHAIN", NULL, "RX2 CLK"},
- {"RX3 CHAIN", NULL, "RX3 CLK"},
- {"RX1 CHAIN", NULL, "RX1 MIX2"},
- {"RX2 CHAIN", NULL, "RX2 MIX2"},
- {"RX3 CHAIN", NULL, "RX3 MIX1"},
-
- {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
- {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
- {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
- {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
- {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
- {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
- {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
- {"RX1 MIX2", NULL, "RX1 MIX1"},
- {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
- {"RX2 MIX2", NULL, "RX2 MIX1"},
- {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
-
- {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
- {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
- {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
- {"RX1 MIX1 INP1", "IIR1", "IIR1"},
- {"RX1 MIX1 INP1", "IIR2", "IIR2"},
- {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
- {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
- {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
- {"RX1 MIX1 INP2", "IIR1", "IIR1"},
- {"RX1 MIX1 INP2", "IIR2", "IIR2"},
- {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
- {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
- {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
-
- {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
- {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
- {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
- {"RX2 MIX1 INP1", "IIR1", "IIR1"},
- {"RX2 MIX1 INP1", "IIR2", "IIR2"},
- {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
- {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
- {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
- {"RX2 MIX1 INP2", "IIR1", "IIR1"},
- {"RX2 MIX1 INP2", "IIR2", "IIR2"},
-
- {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
- {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
- {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
- {"RX3 MIX1 INP1", "IIR1", "IIR1"},
- {"RX3 MIX1 INP1", "IIR2", "IIR2"},
- {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
- {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
- {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
- {"RX3 MIX1 INP2", "IIR1", "IIR1"},
- {"RX3 MIX1 INP2", "IIR2", "IIR2"},
-
- {"RX1 MIX2 INP1", "IIR1", "IIR1"},
- {"RX2 MIX2 INP1", "IIR1", "IIR1"},
- {"RX1 MIX2 INP1", "IIR2", "IIR2"},
- {"RX2 MIX2 INP1", "IIR2", "IIR2"},
-
- /* Decimator Inputs */
- {"DEC1 MUX", "DMIC1", "DMIC1"},
- {"DEC1 MUX", "DMIC2", "DMIC2"},
- {"DEC1 MUX", "ADC1", "ADC1"},
- {"DEC1 MUX", "ADC2", "ADC2"},
- {"DEC1 MUX", "ADC3", "ADC3"},
- {"DEC1 MUX", NULL, "CDC_CONN"},
-
- {"DEC2 MUX", "DMIC1", "DMIC1"},
- {"DEC2 MUX", "DMIC2", "DMIC2"},
- {"DEC2 MUX", "ADC1", "ADC1"},
- {"DEC2 MUX", "ADC2", "ADC2"},
- {"DEC2 MUX", "ADC3", "ADC3"},
- {"DEC2 MUX", NULL, "CDC_CONN"},
-
- {"DEC3 MUX", "DMIC3", "DMIC3"},
- {"DEC4 MUX", "DMIC4", "DMIC4"},
- {"DEC3 MUX", NULL, "CDC_CONN"},
- {"DEC4 MUX", NULL, "CDC_CONN"},
- /* ADC Connections */
- {"ADC2", NULL, "ADC2 MUX"},
- {"ADC3", NULL, "ADC2 MUX"},
- {"ADC2 MUX", "INP2", "ADC2_INP2"},
- {"ADC2 MUX", "INP3", "ADC2_INP3"},
-
- {"ADC1", NULL, "AMIC1"},
- {"ADC2_INP2", NULL, "AMIC2"},
- {"ADC2_INP3", NULL, "AMIC3"},
-
- /* TODO: Fix this */
- {"IIR1", NULL, "IIR1 INP1 MUX"},
- {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
- {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
- {"IIR2", NULL, "IIR2 INP1 MUX"},
- {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
- {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
- {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
- {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
- {"MIC BIAS External", NULL, "INT_LDO_H"},
- {"MIC BIAS External2", NULL, "INT_LDO_H"},
- {"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
- {"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
- {"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
- {"MIC BIAS External2", NULL, "MICBIAS_REGULATOR"},
-};
-
-static int msm8x16_wcd_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd =
- snd_soc_codec_get_drvdata(dai->codec);
-
- dev_err(dai->codec->dev, "%s(): substream = %s stream = %d\n",
- __func__,
- substream->name, substream->stream);
- /*
- * If status_mask is BU_DOWN it means SSR is not complete.
- * So retun error.
- */
- if (test_bit(BUS_DOWN, &msm8x16_wcd->status_mask)) {
- dev_err(dai->codec->dev, "Error, Device is not up post SSR\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static void msm8x16_wcd_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- dev_err(dai->codec->dev,
- "%s(): substream = %s stream = %d\n", __func__,
- substream->name, substream->stream);
-}
-
-int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec,
- int mclk_enable, bool dapm)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
- __func__, mclk_enable, dapm);
- if (mclk_enable) {
- msm8x16_wcd->int_mclk0_enabled = true;
- msm8x16_wcd_codec_enable_clock_block(codec, 1);
- } else {
- if (!msm8x16_wcd->int_mclk0_enabled) {
- dev_err(codec->dev, "Error, MCLK already diabled\n");
- return -EINVAL;
- }
- msm8x16_wcd->int_mclk0_enabled = false;
- msm8x16_wcd_codec_enable_clock_block(codec, 0);
- }
- return 0;
-}
-
-static int msm8x16_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
- int clk_id, unsigned int freq, int dir)
-{
- dev_err(dai->codec->dev, "%s\n", __func__);
- return 0;
-}
-
-static int msm8x16_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
- dev_err(dai->codec->dev, "%s\n", __func__);
- return 0;
-}
-
-static int msm8x16_wcd_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
-
-{
- dev_err(dai->codec->dev, "%s\n", __func__);
- return 0;
-}
-
-static int msm8x16_wcd_get_channel_map(struct snd_soc_dai *dai,
- unsigned int *tx_num, unsigned int *tx_slot,
- unsigned int *rx_num, unsigned int *rx_slot)
-
-{
- dev_err(dai->codec->dev, "%s\n", __func__);
- return 0;
-}
-
-static int msm8x16_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
- u8 rx_fs_rate_reg_val, u32 sample_rate)
-{
- snd_soc_update_bits_wrapper(dai->codec,
- MSM89XX_CDC_CORE_RX1_B5_CTL, 0xF0, rx_fs_rate_reg_val);
- snd_soc_update_bits_wrapper(dai->codec,
- MSM89XX_CDC_CORE_RX2_B5_CTL, 0xF0, rx_fs_rate_reg_val);
- return 0;
-}
-
-static int msm8x16_wcd_set_decimator_rate(struct snd_soc_dai *dai,
- u8 tx_fs_rate_reg_val, u32 sample_rate)
-{
- return 0;
-}
-
-static int msm8x16_wcd_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- u8 tx_fs_rate, rx_fs_rate, rx_clk_fs_rate;
- int ret;
-
- dev_err(dai->codec->dev,
- "%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
- __func__, dai->name, dai->id, params_rate(params),
- params_channels(params), params_format(params));
-
- switch (params_rate(params)) {
- case 8000:
- tx_fs_rate = 0x00;
- rx_fs_rate = 0x00;
- rx_clk_fs_rate = 0x00;
- break;
- case 16000:
- tx_fs_rate = 0x20;
- rx_fs_rate = 0x20;
- rx_clk_fs_rate = 0x01;
- break;
- case 32000:
- tx_fs_rate = 0x40;
- rx_fs_rate = 0x40;
- rx_clk_fs_rate = 0x02;
- break;
- case 48000:
- tx_fs_rate = 0x60;
- rx_fs_rate = 0x60;
- rx_clk_fs_rate = 0x03;
- break;
- case 96000:
- tx_fs_rate = 0x80;
- rx_fs_rate = 0x80;
- rx_clk_fs_rate = 0x04;
- break;
- case 192000:
- tx_fs_rate = 0xA0;
- rx_fs_rate = 0xA0;
- rx_clk_fs_rate = 0x05;
- break;
- default:
- dev_err(dai->codec->dev,
- "%s: Invalid sampling rate %d\n", __func__,
- params_rate(params));
- return -EINVAL;
- }
-
- snd_soc_update_bits_wrapper(dai->codec,
- MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x0F, rx_clk_fs_rate);
-
- switch (substream->stream) {
- case SNDRV_PCM_STREAM_CAPTURE:
- ret = msm8x16_wcd_set_decimator_rate(dai, tx_fs_rate,
- params_rate(params));
- if (ret < 0) {
- dev_err(dai->codec->dev,
- "%s: set decimator rate failed %d\n", __func__,
- ret);
- return ret;
- }
- break;
- case SNDRV_PCM_STREAM_PLAYBACK:
- ret = msm8x16_wcd_set_interpolator_rate(dai, rx_fs_rate,
- params_rate(params));
- if (ret < 0) {
- dev_err(dai->codec->dev,
- "%s: set decimator rate failed %d\n", __func__,
- ret);
- return ret;
- }
- break;
- default:
- dev_err(dai->codec->dev,
- "%s: Invalid stream type %d\n", __func__,
- substream->stream);
- return -EINVAL;
- }
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- snd_soc_update_bits_wrapper(dai->codec,
- MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x20);
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- snd_soc_update_bits_wrapper(dai->codec,
- MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x00);
- break;
- default:
- dev_err(dai->codec->dev, "%s: wrong format selected\n",
- __func__);
- return -EINVAL;
- }
-
- return 0;
-}
-
-int msm8x16_wcd_digital_mute(struct snd_soc_dai *dai, int mute)
-{
- struct snd_soc_codec *codec = NULL;
- u16 tx_vol_ctl_reg = 0;
- u8 decimator = 0, i;
- struct msm8x16_wcd_priv *msm8x16_wcd;
-
- pr_err("%s: Digital Mute val = %d\n", __func__, mute);
-
- if (!dai || !dai->codec) {
- pr_err("%s: Invalid params\n", __func__);
- return -EINVAL;
- }
- codec = dai->codec;
- msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- if ((dai->id != AIF1_CAP) && (dai->id != AIF2_VIFEED)) {
- dev_err(codec->dev, "%s: Not capture use case skip\n",
- __func__);
- return 0;
- }
-
- mute = (mute) ? 1 : 0;
- if (!mute) {
- /*
- * 15 ms is an emperical value for the mute time
- * that was arrived by checking the pop level
- * to be inaudible
- */
- usleep_range(15000, 15010);
- }
-
- for (i = 0; i < NUM_DECIMATORS; i++) {
- if (msm8x16_wcd->dec_active[i])
- decimator = i + 1;
- if (decimator && decimator <= NUM_DECIMATORS) {
- pr_err("%s: Mute = %d Decimator = %d", __func__,
- mute, decimator);
- tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
- 32 * (decimator - 1);
- snd_soc_update_bits_wrapper(codec,
- tx_vol_ctl_reg, 0x01, mute);
- }
- decimator = 0;
- }
- return 0;
-}
-
-static struct snd_soc_dai_ops msm8x16_wcd_dai_ops = {
- .startup = msm8x16_wcd_startup,
- .shutdown = msm8x16_wcd_shutdown,
- .hw_params = msm8x16_wcd_hw_params,
- .set_sysclk = msm8x16_wcd_set_dai_sysclk,
- .set_fmt = msm8x16_wcd_set_dai_fmt,
- .set_channel_map = msm8x16_wcd_set_channel_map,
- .get_channel_map = msm8x16_wcd_get_channel_map,
- .digital_mute = msm8x16_wcd_digital_mute,
-};
-
-static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[] = {
- {
- .name = "msm8x16_wcd_i2s_rx1",
- .id = AIF1_PB,
- .playback = {
- .stream_name = "AIF1 Playback",
- .rates = MSM89XX_RATES,
- .formats = MSM89XX_FORMATS,
- .rate_max = 192000,
- .rate_min = 8000,
- .channels_min = 1,
- .channels_max = 3,
- },
- .ops = &msm8x16_wcd_dai_ops,
- },
- {
- .name = "msm8x16_wcd_i2s_tx1",
- .id = AIF1_CAP,
- .capture = {
- .stream_name = "AIF1 Capture",
- .rates = MSM89XX_RATES,
- .formats = MSM89XX_FORMATS,
- .rate_max = 192000,
- .rate_min = 8000,
- .channels_min = 1,
- .channels_max = 4,
- },
- .ops = &msm8x16_wcd_dai_ops,
- },
- {
- .name = "cajon_vifeedback",
- .id = AIF2_VIFEED,
- .capture = {
- .stream_name = "VIfeed",
- .rates = MSM89XX_RATES,
- .formats = MSM89XX_FORMATS,
- .rate_max = 48000,
- .rate_min = 48000,
- .channels_min = 2,
- .channels_max = 2,
- },
- .ops = &msm8x16_wcd_dai_ops,
- },
-};
-
-static int msm8x16_wcd_codec_enable_rx_chain(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- dev_err(codec->dev,
- "%s: PMU:Sleeping 20ms after disabling mute\n",
- __func__);
- break;
- case SND_SOC_DAPM_POST_PMD:
- dev_err(codec->dev,
- "%s: PMD:Sleeping 20ms after disabling mute\n",
- __func__);
- snd_soc_update_bits_wrapper(codec, w->reg,
- 1 << w->shift, 0x00);
- msleep(20);
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
- dev_err(codec->dev, "%s: %d %s\n", __func__, event, w->name);
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
- break;
- case SND_SOC_DAPM_POST_PMD:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
- break;
- }
-
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_spk_ext_pa(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- dev_err(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- dev_err(codec->dev,
- "%s: enable external speaker PA\n", __func__);
- if (msm8x16_wcd->codec_spk_ext_pa_cb)
- msm8x16_wcd->codec_spk_ext_pa_cb(codec, 1);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- dev_err(codec->dev,
- "%s: enable external speaker PA\n", __func__);
- if (msm8x16_wcd->codec_spk_ext_pa_cb)
- msm8x16_wcd->codec_spk_ext_pa_cb(codec, 0);
- break;
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- dev_err(codec->dev,
- "%s: Sleeping 20ms after select EAR PA\n",
- __func__);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x80);
- if (get_codec_version(msm8x16_wcd) < CONGA)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x2A);
- break;
- case SND_SOC_DAPM_POST_PMU:
- dev_err(codec->dev,
- "%s: Sleeping 20ms after enabling EAR PA\n",
- __func__);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x40, 0x40);
- usleep_range(7000, 7100);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01);
- msleep(20);
- msm8x16_wcd->mute_mask |= EAR_PA_DISABLE;
- if (msm8x16_wcd->boost_option == BOOST_ALWAYS) {
- dev_err(codec->dev,
- "%s: boost_option:%d, tear down ear\n",
- __func__, msm8x16_wcd->boost_option);
- msm8x16_wcd_boost_mode_sequence(codec, EAR_PMD);
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- dev_err(codec->dev,
- "%s: Sleeping 7ms after disabling EAR PA\n",
- __func__);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x40, 0x00);
- usleep_range(7000, 7100);
- if (get_codec_version(msm8x16_wcd) < CONGA)
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x16);
- break;
- }
- return 0;
-}
-
-static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = {
- /*RX stuff */
- SND_SOC_DAPM_OUTPUT("EAR"),
- SND_SOC_DAPM_OUTPUT("WSA_SPK OUT"),
-
- SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM,
- 0, 0, NULL, 0, msm8x16_wcd_codec_enable_ear_pa,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0,
- ear_pa_mux),
-
- SND_SOC_DAPM_MUX("WSA Spk Switch", SND_SOC_NOPM, 0, 0,
- wsa_spk_mux),
-
- SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
- SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
- SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
- SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
-
- SND_SOC_DAPM_SPK("Ext Spk", msm8x16_wcd_codec_enable_spk_ext_pa),
-
- SND_SOC_DAPM_OUTPUT("HEADPHONE"),
- SND_SOC_DAPM_PGA_E("HPHL PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
- 5, 0, NULL, 0,
- msm8x16_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0,
- hphl_mux),
-
- SND_SOC_DAPM_MIXER_E("HPHL DAC",
- MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
- 0, msm8x16_wcd_hphl_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_PGA_E("HPHR PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
- 4, 0, NULL, 0,
- msm8x16_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0,
- hphr_mux),
-
- SND_SOC_DAPM_MIXER_E("HPHR DAC",
- MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
- 0, msm8x16_wcd_hphr_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("SPK", SND_SOC_NOPM, 0, 0,
- spkr_mux),
-
- SND_SOC_DAPM_DAC("SPK DAC", NULL,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 7, 0),
-
- SND_SOC_DAPM_MUX("LINE_OUT",
- SND_SOC_NOPM, 0, 0, lo_mux),
-
- SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
- SND_SOC_NOPM, 0, 0, msm8x16_wcd_lo_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- /* Speaker */
- SND_SOC_DAPM_OUTPUT("SPK_OUT"),
-
- /* Lineout */
- SND_SOC_DAPM_OUTPUT("LINEOUT"),
-
- SND_SOC_DAPM_PGA_E("SPK PA", MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
- 6, 0, NULL, 0, msm8x16_wcd_codec_enable_spk_pa,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL,
- 5, 0, NULL, 0, msm8x16_wcd_codec_enable_lo_pa,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
- msm89xx_wcd_codec_enable_vdd_spkr,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("Ext Spk Switch", SND_SOC_NOPM, 0, 0,
- &ext_spk_mux),
-
- SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-
- SND_SOC_DAPM_MIXER_E("RX1 MIX2",
- MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX1, 0, NULL,
- 0, msm8x16_wcd_codec_enable_interpolator,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER_E("RX2 MIX2",
- MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX2, 0, NULL,
- 0, msm8x16_wcd_codec_enable_interpolator,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER_E("RX3 MIX1",
- MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX3, 0, NULL,
- 0, msm8x16_wcd_codec_enable_interpolator,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 1, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 2, 0, msm8x16_wcd_codec_enable_dig_clk, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER_E("RX1 CHAIN", MSM89XX_CDC_CORE_RX1_B6_CTL, 0, 0,
- NULL, 0,
- msm8x16_wcd_codec_enable_rx_chain,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER_E("RX2 CHAIN", MSM89XX_CDC_CORE_RX2_B6_CTL, 0, 0,
- NULL, 0,
- msm8x16_wcd_codec_enable_rx_chain,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER_E("RX3 CHAIN", MSM89XX_CDC_CORE_RX3_B6_CTL, 0, 0,
- NULL, 0,
- msm8x16_wcd_codec_enable_rx_chain,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
- &rx_mix1_inp3_mux),
-
- SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx2_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx2_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
- &rx2_mix1_inp3_mux),
-
- SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx3_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx3_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
- &rx3_mix1_inp3_mux),
-
- SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
- &rx1_mix2_inp1_mux),
- SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
- &rx2_mix2_inp1_mux),
-
- SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
- ON_DEMAND_MICBIAS, 0,
- msm8x16_wcd_codec_enable_on_demand_supply,
- SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_SUPPLY("CP", MSM89XX_PMIC_ANALOG_NCP_EN, 0, 0,
- msm8x16_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_SUPPLY("EAR CP", MSM89XX_PMIC_ANALOG_NCP_EN, 4, 0,
- msm8x16_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_SUPPLY_S("RX_BIAS", 1, SND_SOC_NOPM,
- 0, 0, msm8x16_wcd_codec_enable_rx_bias,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_SUPPLY_S("SPK_RX_BIAS", 1, SND_SOC_NOPM, 0, 0,
- msm8x16_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- /* TX */
-
- SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, MSM89XX_CDC_CORE_CLK_OTHR_CTL,
- 2, 0, NULL, 0),
-
-
- SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
- MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
- msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
- MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
- msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
- MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
- msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM89XX_PMIC_ANALOG_TX_1_EN, 7, 0,
- msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC2_INP2",
- NULL, MSM89XX_PMIC_ANALOG_TX_2_EN, 7, 0,
- msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC2_INP3",
- NULL, MSM89XX_PMIC_ANALOG_TX_3_EN, 7, 0,
- msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
-
- SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
- &tx_adc2_mux),
-
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
- MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
- msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS External2",
- MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
- msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
-
-
- SND_SOC_DAPM_INPUT("AMIC3"),
-
- SND_SOC_DAPM_MUX_E("DEC1 MUX",
- MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0, 0,
- &dec1_mux, msm8x16_wcd_codec_enable_dec,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX_E("DEC2 MUX",
- MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 1, 0,
- &dec2_mux, msm8x16_wcd_codec_enable_dec,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX_E("DEC3 MUX",
- MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 2, 0,
- &dec3_mux, msm8x16_wcd_codec_enable_dec,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX_E("DEC4 MUX",
- MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 3, 0,
- &dec4_mux, msm8x16_wcd_codec_enable_dec,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
-
- SND_SOC_DAPM_INPUT("AMIC2"),
-
- SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
- 0, 0),
- SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
- 0, 0),
- SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
- 0, 0),
-
- SND_SOC_DAPM_AIF_OUT("AIF2 VI", "VIfeed", 0, SND_SOC_NOPM,
- 0, 0),
- /* Digital Mic Inputs */
- SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
- msm8x16_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
- msm8x16_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_INPUT("DMIC3"),
-
- SND_SOC_DAPM_INPUT("DMIC4"),
-
- /* Sidetone */
- SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
- SND_SOC_DAPM_PGA_E("IIR1", MSM89XX_CDC_CORE_CLK_SD_CTL, 0, 0, NULL, 0,
- msm8x16_wcd_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
- SND_SOC_DAPM_PGA_E("IIR2", MSM89XX_CDC_CORE_CLK_SD_CTL, 1, 0, NULL, 0,
- msm8x16_wcd_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("RX_I2S_CLK",
- MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 4, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("TX_I2S_CLK",
- MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 4, 0,
- NULL, 0),
-};
-
-static const struct msm8x16_wcd_reg_mask_val msm8x16_wcd_reg_defaults[] = {
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
-};
-
-static const struct msm8x16_wcd_reg_mask_val msm8x16_wcd_reg_defaults_2_0[] = {
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, 0x5F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, 0x88),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
-};
-
-static const struct msm8x16_wcd_reg_mask_val msm8909_wcd_reg_defaults[] = {
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE, 0x0A),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
-};
-
-static const struct msm8x16_wcd_reg_mask_val cajon_wcd_reg_defaults[] = {
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
-};
-
-static const struct msm8x16_wcd_reg_mask_val cajon2p0_wcd_reg_defaults[] = {
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_EAR_STATUS, 0x10),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BYPASS_MODE, 0x18),
- MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
- MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
-};
-
-static void msm8x16_wcd_update_reg_defaults(struct snd_soc_codec *codec)
-{
- u32 i, version;
- struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
- version = get_codec_version(msm8x16_wcd);
- if (version == TOMBAK_1_0) {
- for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_reg_defaults); i++)
- snd_soc_write_wrapper(codec,
- msm8x16_wcd_reg_defaults[i].reg,
- msm8x16_wcd_reg_defaults[i].val);
- } else if (version == TOMBAK_2_0) {
- for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_reg_defaults_2_0); i++)
- snd_soc_write_wrapper(codec,
- msm8x16_wcd_reg_defaults_2_0[i].reg,
- msm8x16_wcd_reg_defaults_2_0[i].val);
- } else if (version == CONGA) {
- for (i = 0; i < ARRAY_SIZE(msm8909_wcd_reg_defaults); i++)
- snd_soc_write_wrapper(codec,
- msm8909_wcd_reg_defaults[i].reg,
- msm8909_wcd_reg_defaults[i].val);
- } else if (version == CAJON) {
- for (i = 0; i < ARRAY_SIZE(cajon_wcd_reg_defaults); i++)
- snd_soc_write_wrapper(codec,
- cajon_wcd_reg_defaults[i].reg,
- cajon_wcd_reg_defaults[i].val);
- } else if (version == CAJON_2_0 || version == DIANGU) {
- for (i = 0; i < ARRAY_SIZE(cajon2p0_wcd_reg_defaults); i++)
- snd_soc_write_wrapper(codec,
- cajon2p0_wcd_reg_defaults[i].reg,
- cajon2p0_wcd_reg_defaults[i].val);
- }
-}
-
-static const struct msm8x16_wcd_reg_mask_val
- msm8x16_wcd_codec_reg_init_val[] = {
-
- /* Initialize current threshold to 350MA
- * number of wait and run cycles to 4096
- */
- {MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0xFF, 0x12},
- {MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT, 0xFF, 0xFF},
-};
-
-static void msm8x16_wcd_codec_init_reg(struct snd_soc_codec *codec)
-{
- u32 i;
-
- for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_codec_reg_init_val); i++)
- snd_soc_update_bits_wrapper(codec,
- msm8x16_wcd_codec_reg_init_val[i].reg,
- msm8x16_wcd_codec_reg_init_val[i].mask,
- msm8x16_wcd_codec_reg_init_val[i].val);
-}
-
-static int msm8x16_wcd_bringup(struct snd_soc_codec *codec)
-{
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
- 0xA5);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x01);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SEC_ACCESS,
- 0xA5);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x01);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
- 0xA5);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x00);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SEC_ACCESS,
- 0xA5);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00);
- return 0;
-}
-
-static struct regulator *wcd8x16_wcd_codec_find_regulator(
- const struct msm8x16_wcd *msm8x16,
- const char *name)
-{
- int i;
-
- for (i = 0; i < msm8x16->num_of_supplies; i++) {
- if (msm8x16->supplies[i].supply &&
- !strcmp(msm8x16->supplies[i].supply, name))
- return msm8x16->supplies[i].consumer;
- }
-
- dev_err(msm8x16->dev, "Error: regulator not found:%s\n"
- , name);
- return NULL;
-}
-
-static int msm8x16_wcd_device_down(struct snd_soc_codec *codec)
-{
- struct msm_asoc_mach_data *pdata = NULL;
- struct msm8x16_wcd_priv *msm8x16_wcd_priv =
- snd_soc_codec_get_drvdata(codec);
- int i;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
- dev_err(codec->dev, "%s: device down!\n", __func__);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_TX_1_EN, 0x3);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_TX_2_EN, 0x3);
- if (msm8x16_wcd_priv->boost_option == BOOST_ON_FOREVER) {
- if ((snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL)
- & 0x80) == 0) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL,
- 0x0C, 0x0C);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
- 0x84, 0x84);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
- 0x10, 0x10);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
- 0x1F, 0x1F);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
- 0x90, 0x90);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
- 0xFF, 0xFF);
- usleep_range(20, 21);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
- 0xFF, 0xFF);
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
- 0xE9, 0xE9);
- }
- }
- msm8x16_wcd_boost_off(codec);
- msm8x16_wcd_priv->hph_mode = NORMAL_MODE;
- for (i = 0; i < MSM89XX_RX_MAX; i++)
- msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE;
-
- /* 40ms to allow boost to discharge */
- msleep(40);
- /* Disable PA to avoid pop during codec bring up */
- snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
- 0x30, 0x00);
- snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
- 0x80, 0x00);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x20);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x20);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x12);
- snd_soc_write_wrapper(codec,
- MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
-
- msm8x16_wcd_bringup(codec);
- atomic_set(&pdata->int_mclk0_enabled, false);
- set_bit(BUS_DOWN, &msm8x16_wcd_priv->status_mask);
- snd_soc_card_change_online_state(codec->component.card, 0);
- return 0;
-}
-
-static int msm8x16_wcd_device_up(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd_priv =
- snd_soc_codec_get_drvdata(codec);
- int ret = 0;
-
- dev_err(codec->dev, "%s: device up!\n", __func__);
-
- clear_bit(BUS_DOWN, &msm8x16_wcd_priv->status_mask);
-
- snd_soc_card_change_online_state(codec->component.card, 1);
- /* delay is required to make sure sound card state updated */
- usleep_range(5000, 5100);
-
- msm8x16_wcd_codec_init_reg(codec);
- msm8x16_wcd_update_reg_defaults(codec);
-
- snd_soc_write_wrapper(codec, MSM89XX_PMIC_DIGITAL_INT_EN_SET,
- MSM89XX_PMIC_DIGITAL_INT_EN_SET__POR);
- snd_soc_write_wrapper(codec, MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
- MSM89XX_PMIC_DIGITAL_INT_EN_CLR__POR);
-
- msm8x16_wcd_set_boost_v(codec);
-
- msm8x16_wcd_set_micb_v(codec);
- if (msm8x16_wcd_priv->boost_option == BOOST_ON_FOREVER)
- msm8x16_wcd_boost_on(codec);
- else if (msm8x16_wcd_priv->boost_option == BYPASS_ALWAYS)
- msm8x16_wcd_bypass_on(codec);
-
- msm8x16_wcd_configure_cap(codec, false, false);
- wcd_mbhc_stop(&msm8x16_wcd_priv->mbhc);
- wcd_mbhc_deinit(&msm8x16_wcd_priv->mbhc);
- ret = wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids,
- wcd_mbhc_registers, true);
- if (ret)
- dev_err(codec->dev, "%s: mbhc initialization failed\n",
- __func__);
- else
- wcd_mbhc_start(&msm8x16_wcd_priv->mbhc,
- msm8x16_wcd_priv->mbhc.mbhc_cfg);
-
-
- return 0;
-}
-
-static int adsp_state_callback(struct notifier_block *nb, unsigned long value,
- void *priv)
-{
- bool timedout;
- unsigned long timeout;
-
- if (value == SUBSYS_BEFORE_SHUTDOWN)
- msm8x16_wcd_device_down(registered_codec);
- else if (value == SUBSYS_AFTER_POWERUP) {
-
- dev_err(registered_codec->dev,
- "ADSP is about to power up. bring up codec\n");
-
- if (!q6core_is_adsp_ready()) {
- dev_err(registered_codec->dev,
- "ADSP isn't ready\n");
- timeout = jiffies +
- msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
- while (!(timedout = time_after(jiffies, timeout))) {
- if (!q6core_is_adsp_ready()) {
- dev_err(registered_codec->dev,
- "ADSP isn't ready\n");
- } else {
- dev_err(registered_codec->dev,
- "ADSP is ready\n");
- break;
- }
- }
- } else {
- dev_err(registered_codec->dev,
- "%s: DSP is ready\n", __func__);
- }
-
- msm8x16_wcd_device_up(registered_codec);
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block adsp_state_notifier_block = {
- .notifier_call = adsp_state_callback,
- .priority = -INT_MAX,
-};
-
-int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec,
- struct wcd_mbhc_config *mbhc_cfg)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd_priv =
- snd_soc_codec_get_drvdata(codec);
-
- return wcd_mbhc_start(&msm8x16_wcd_priv->mbhc, mbhc_cfg);
-}
-EXPORT_SYMBOL(msm8x16_wcd_hs_detect);
-
-void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd_priv =
- snd_soc_codec_get_drvdata(codec);
-
- wcd_mbhc_stop(&msm8x16_wcd_priv->mbhc);
-}
-EXPORT_SYMBOL(msm8x16_wcd_hs_detect_exit);
-
-void msm8x16_update_int_spk_boost(bool enable)
-{
- pr_err("%s: enable = %d\n", __func__, enable);
- spkr_boost_en = enable;
-}
-EXPORT_SYMBOL(msm8x16_update_int_spk_boost);
-
-static void msm8x16_wcd_set_micb_v(struct snd_soc_codec *codec)
-{
-
- struct msm8x16_wcd *msm8x16 = codec->control_data;
- struct msm8x16_wcd_pdata *pdata = msm8x16->dev->platform_data;
- u8 reg_val;
-
- reg_val = VOLTAGE_CONVERTER(pdata->micbias.cfilt1_mv, MICBIAS_MIN_VAL,
- MICBIAS_STEP_SIZE);
- dev_err(codec->dev, "cfilt1_mv %d reg_val %x\n",
- (u32)pdata->micbias.cfilt1_mv, reg_val);
- snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_MICB_1_VAL,
- 0xF8, (reg_val << 3));
-}
-
-static void msm8x16_wcd_set_boost_v(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd_priv =
- snd_soc_codec_get_drvdata(codec);
-
- snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE,
- 0x1F, msm8x16_wcd_priv->boost_voltage);
-}
-
-static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec,
- bool micbias1, bool micbias2)
-{
-
- struct msm_asoc_mach_data *pdata = NULL;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
-
- pr_err("\n %s: micbias1 %x micbias2 = %d\n", __func__, micbias1,
- micbias2);
- if (micbias1 && micbias2) {
- if ((pdata->micbias1_cap_mode
- == MICBIAS_EXT_BYP_CAP) ||
- (pdata->micbias2_cap_mode
- == MICBIAS_EXT_BYP_CAP))
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_EN,
- 0x40, (MICBIAS_EXT_BYP_CAP << 6));
- else
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_EN,
- 0x40, (MICBIAS_NO_EXT_BYP_CAP << 6));
- } else if (micbias2) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_EN,
- 0x40, (pdata->micbias2_cap_mode << 6));
- } else if (micbias1) {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_EN,
- 0x40, (pdata->micbias1_cap_mode << 6));
- } else {
- snd_soc_update_bits_wrapper(codec,
- MSM89XX_PMIC_ANALOG_MICB_1_EN,
- 0x40, 0x00);
- }
-}
-
-static int msm89xx_digcodec_probe(struct snd_soc_codec *codec)
-{
- registered_digcodec = codec;
-
- return 0;
-}
-
-
-static int msm89xx_digcodec_remove(struct snd_soc_codec *codec)
-{
- return 0;
-}
-
-static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd_priv;
- int i, ret;
-
- dev_err(codec->dev, "%s()\n", __func__);
-
- msm8x16_wcd_priv = kzalloc(sizeof(struct msm8x16_wcd_priv), GFP_KERNEL);
- if (!msm8x16_wcd_priv)
- return -ENOMEM;
-
- for (i = 0; i < NUM_DECIMATORS; i++) {
- tx_hpf_work[i].msm8x16_wcd = msm8x16_wcd_priv;
- tx_hpf_work[i].decimator = i + 1;
- INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
- tx_hpf_corner_freq_callback);
- }
-
- codec->control_data = dev_get_drvdata(codec->dev);
- snd_soc_codec_set_drvdata(codec, msm8x16_wcd_priv);
- msm8x16_wcd_priv->codec = codec;
-
- msm8x16_wcd_priv->spkdrv_reg =
- wcd8x16_wcd_codec_find_regulator(codec->control_data,
- MSM89XX_VDD_SPKDRV_NAME);
- msm8x16_wcd_priv->pmic_rev = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_REVISION1);
- msm8x16_wcd_priv->codec_version = snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE);
- if (msm8x16_wcd_priv->codec_version == CONGA) {
- dev_err(codec->dev, "%s :Conga REV: %d\n", __func__,
- msm8x16_wcd_priv->codec_version);
- msm8x16_wcd_priv->ext_spk_boost_set = true;
- } else {
- dev_err(codec->dev, "%s :PMIC REV: %d\n", __func__,
- msm8x16_wcd_priv->pmic_rev);
- if (msm8x16_wcd_priv->pmic_rev == TOMBAK_1_0 &&
- msm8x16_wcd_priv->codec_version == CAJON_2_0) {
- msm8x16_wcd_priv->codec_version = DIANGU;
- dev_err(codec->dev, "%s : Diangu detected\n",
- __func__);
- } else if (msm8x16_wcd_priv->pmic_rev == TOMBAK_1_0 &&
- (snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
- & 0x80)) {
- msm8x16_wcd_priv->codec_version = CAJON;
- dev_err(codec->dev, "%s : Cajon detected\n", __func__);
- } else if (msm8x16_wcd_priv->pmic_rev == TOMBAK_2_0 &&
- (snd_soc_read_wrapper(codec,
- MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
- & 0x80)) {
- msm8x16_wcd_priv->codec_version = CAJON_2_0;
- dev_err(codec->dev, "%s : Cajon 2.0 detected\n",
- __func__);
- }
- }
- /*
- * set to default boost option BOOST_SWITCH, user mixer path can change
- * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen.
- */
- msm8x16_wcd_priv->boost_option = BOOST_SWITCH;
- msm8x16_wcd_priv->hph_mode = NORMAL_MODE;
-
- for (i = 0; i < MSM89XX_RX_MAX; i++)
- msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE;
-
- msm8x16_wcd_dt_parse_boost_info(codec);
- msm8x16_wcd_set_boost_v(codec);
-
- snd_soc_add_codec_controls(codec, impedance_detect_controls,
- ARRAY_SIZE(impedance_detect_controls));
- snd_soc_add_codec_controls(codec, hph_type_detect_controls,
- ARRAY_SIZE(hph_type_detect_controls));
-
- msm8x16_wcd_bringup(codec);
- msm8x16_wcd_codec_init_reg(codec);
- msm8x16_wcd_update_reg_defaults(codec);
-
- wcd9xxx_spmi_set_codec(codec);
-
- msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
- wcd8x16_wcd_codec_find_regulator(
- codec->control_data,
- on_demand_supply_name[ON_DEMAND_MICBIAS]);
- atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
-
- BLOCKING_INIT_NOTIFIER_HEAD(&msm8x16_wcd_priv->notifier);
-
- msm8x16_wcd_priv->fw_data = kzalloc(sizeof(*(msm8x16_wcd_priv->fw_data))
- , GFP_KERNEL);
- if (!msm8x16_wcd_priv->fw_data) {
- kfree(msm8x16_wcd_priv);
- return -ENOMEM;
- }
-
- set_bit(WCD9XXX_MBHC_CAL, msm8x16_wcd_priv->fw_data->cal_bit);
- ret = wcd_cal_create_hwdep(msm8x16_wcd_priv->fw_data,
- WCD9XXX_CODEC_HWDEP_NODE, codec);
- if (ret < 0) {
- dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
- kfree(msm8x16_wcd_priv->fw_data);
- kfree(msm8x16_wcd_priv);
- return ret;
- }
-
- wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids,
- wcd_mbhc_registers, true);
-
- msm8x16_wcd_priv->int_mclk0_enabled = false;
- msm8x16_wcd_priv->clock_active = false;
- msm8x16_wcd_priv->config_mode_active = false;
-
- /*Update speaker boost configuration*/
- msm8x16_wcd_priv->spk_boost_set = spkr_boost_en;
- pr_err("%s: speaker boost configured = %d\n",
- __func__, msm8x16_wcd_priv->spk_boost_set);
-
- /* Set initial MICBIAS voltage level */
- msm8x16_wcd_set_micb_v(codec);
-
- /* Set initial cap mode */
- msm8x16_wcd_configure_cap(codec, false, false);
- registered_codec = codec;
- adsp_state_notifier =
- subsys_notif_register_notifier("adsp",
- &adsp_state_notifier_block);
- if (!adsp_state_notifier) {
- dev_err(codec->dev, "Failed to register adsp state notifier\n");
- kfree(msm8x16_wcd_priv->fw_data);
- kfree(msm8x16_wcd_priv);
- registered_codec = NULL;
- return -ENOMEM;
- }
- return 0;
-}
-
-static int msm8x16_wcd_codec_remove(struct snd_soc_codec *codec)
-{
- struct msm8x16_wcd_priv *msm8x16_wcd_priv =
- snd_soc_codec_get_drvdata(codec);
- struct msm8x16_wcd *msm8x16_wcd;
-
- msm8x16_wcd = codec->control_data;
- msm8x16_wcd_priv->spkdrv_reg = NULL;
- msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
- atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
- kfree(msm8x16_wcd_priv->fw_data);
- kfree(msm8x16_wcd_priv);
-
- return 0;
-}
-
-static int msm8x16_wcd_enable_static_supplies_to_optimum(
- struct msm8x16_wcd *msm8x16,
- struct msm8x16_wcd_pdata *pdata)
-{
- int i;
- int ret = 0;
-
- for (i = 0; i < msm8x16->num_of_supplies; i++) {
- if (pdata->regulator[i].ondemand)
- continue;
- if (regulator_count_voltages(msm8x16->supplies[i].consumer) <=
- 0)
- continue;
-
- ret = regulator_set_voltage(msm8x16->supplies[i].consumer,
- pdata->regulator[i].min_uv,
- pdata->regulator[i].max_uv);
- if (ret) {
- dev_err(msm8x16->dev,
- "Setting volt failed for regulator %s err %d\n",
- msm8x16->supplies[i].supply, ret);
- }
-
- ret = regulator_set_load(msm8x16->supplies[i].consumer,
- pdata->regulator[i].optimum_ua);
- dev_err(msm8x16->dev, "Regulator %s set optimum mode\n",
- msm8x16->supplies[i].supply);
- }
-
- return ret;
-}
-
-static int msm8x16_wcd_disable_static_supplies_to_optimum(
- struct msm8x16_wcd *msm8x16,
- struct msm8x16_wcd_pdata *pdata)
-{
- int i;
- int ret = 0;
-
- for (i = 0; i < msm8x16->num_of_supplies; i++) {
- if (pdata->regulator[i].ondemand)
- continue;
- if (regulator_count_voltages(msm8x16->supplies[i].consumer) <=
- 0)
- continue;
- regulator_set_voltage(msm8x16->supplies[i].consumer, 0,
- pdata->regulator[i].max_uv);
- regulator_set_load(msm8x16->supplies[i].consumer, 0);
- dev_err(msm8x16->dev, "Regulator %s set optimum mode\n",
- msm8x16->supplies[i].supply);
- }
-
- return ret;
-}
-
-int msm8x16_wcd_suspend(struct snd_soc_codec *codec)
-{
- struct msm_asoc_mach_data *pdata = NULL;
- struct msm8x16_wcd *msm8x16 = codec->control_data;
- struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
- pr_err("%s: mclk cnt = %d, mclk_enabled = %d\n",
- __func__, atomic_read(&pdata->int_mclk0_rsc_ref),
- atomic_read(&pdata->int_mclk0_enabled));
- if (atomic_read(&pdata->int_mclk0_enabled) == true) {
- cancel_delayed_work_sync(
- &pdata->disable_int_mclk0_work);
- mutex_lock(&pdata->cdc_int_mclk0_mutex);
- pdata->digital_cdc_core_clk.enable = 0;
- afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX,
- &pdata->digital_cdc_core_clk);
- atomic_set(&pdata->int_mclk0_enabled, false);
- mutex_unlock(&pdata->cdc_int_mclk0_mutex);
- }
- msm8x16_wcd_disable_static_supplies_to_optimum(msm8x16, msm8x16_pdata);
- return 0;
-}
-
-int msm8x16_wcd_resume(struct snd_soc_codec *codec)
-{
- struct msm_asoc_mach_data *pdata = NULL;
- struct msm8x16_wcd *msm8x16 = codec->control_data;
- struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data;
-
- pdata = snd_soc_card_get_drvdata(codec->component.card);
- msm8x16_wcd_enable_static_supplies_to_optimum(msm8x16, msm8x16_pdata);
- return 0;
-}
-
-static struct regmap *msm89xx_pmic_cdc_regmap;
-static struct regmap *msm89xx_pmic_cdc_get_regmap(struct device *dev)
-{
- return msm89xx_pmic_cdc_regmap;
-}
-
-static const struct snd_soc_codec_driver soc_codec_dev_msm8x16_wcd = {
- .probe = msm8x16_wcd_codec_probe,
- .remove = msm8x16_wcd_codec_remove,
-
- .suspend = msm8x16_wcd_suspend,
- .resume = msm8x16_wcd_resume,
-
- .controls = msm8x16_wcd_snd_controls,
- .num_controls = ARRAY_SIZE(msm8x16_wcd_snd_controls),
- .dapm_widgets = msm8x16_wcd_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(msm8x16_wcd_dapm_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
- .get_regmap = msm89xx_pmic_cdc_get_regmap,
-};
-
-static int msm8x16_wcd_init_supplies(struct msm8x16_wcd *msm8x16,
- struct msm8x16_wcd_pdata *pdata)
-{
- int ret;
- int i;
-
- msm8x16->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
- ARRAY_SIZE(pdata->regulator),
- GFP_KERNEL);
- if (!msm8x16->supplies) {
- ret = -ENOMEM;
- goto err;
- }
-
- msm8x16->num_of_supplies = 0;
-
- if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
- dev_err(msm8x16->dev, "%s: Array Size out of bound\n",
- __func__);
- ret = -EINVAL;
- goto err;
- }
-
- for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
- if (pdata->regulator[i].name) {
- msm8x16->supplies[i].supply = pdata->regulator[i].name;
- msm8x16->num_of_supplies++;
- }
- }
-
- ret = regulator_bulk_get(msm8x16->dev, msm8x16->num_of_supplies,
- msm8x16->supplies);
- if (ret != 0) {
- dev_err(msm8x16->dev, "Failed to get supplies: err = %d\n",
- ret);
- goto err_supplies;
- }
-
- for (i = 0; i < msm8x16->num_of_supplies; i++) {
- if (regulator_count_voltages(msm8x16->supplies[i].consumer) <=
- 0)
- continue;
-
- ret = regulator_set_voltage(msm8x16->supplies[i].consumer,
- pdata->regulator[i].min_uv,
- pdata->regulator[i].max_uv);
- if (ret) {
- dev_err(msm8x16->dev, "Setting regulator voltage failed for regulator %s err = %d\n",
- msm8x16->supplies[i].supply, ret);
- goto err_get;
- }
-
- ret = regulator_set_load(msm8x16->supplies[i].consumer,
- pdata->regulator[i].optimum_ua);
- if (ret < 0) {
- dev_err(msm8x16->dev, "Setting regulator optimum mode failed for regulator %s err = %d\n",
- msm8x16->supplies[i].supply, ret);
- goto err_get;
- } else {
- ret = 0;
- }
- }
-
- return ret;
-
-err_get:
- regulator_bulk_free(msm8x16->num_of_supplies, msm8x16->supplies);
-err_supplies:
- kfree(msm8x16->supplies);
-err:
- return ret;
-}
-
-static int msm8x16_wcd_enable_static_supplies(struct msm8x16_wcd *msm8x16,
- struct msm8x16_wcd_pdata *pdata)
-{
- int i;
- int ret = 0;
-
- for (i = 0; i < msm8x16->num_of_supplies; i++) {
- if (pdata->regulator[i].ondemand)
- continue;
- ret = regulator_enable(msm8x16->supplies[i].consumer);
- if (ret) {
- dev_err(msm8x16->dev, "Failed to enable %s\n",
- msm8x16->supplies[i].supply);
- break;
- }
- dev_err(msm8x16->dev, "Enabled regulator %s\n",
- msm8x16->supplies[i].supply);
- }
-
- while (ret && --i)
- if (!pdata->regulator[i].ondemand)
- regulator_disable(msm8x16->supplies[i].consumer);
-
- return ret;
-}
-
-
-
-static void msm8x16_wcd_disable_supplies(struct msm8x16_wcd *msm8x16,
- struct msm8x16_wcd_pdata *pdata)
-{
- int i;
-
- regulator_bulk_disable(msm8x16->num_of_supplies,
- msm8x16->supplies);
- for (i = 0; i < msm8x16->num_of_supplies; i++) {
- if (regulator_count_voltages(msm8x16->supplies[i].consumer) <=
- 0)
- continue;
- regulator_set_voltage(msm8x16->supplies[i].consumer, 0,
- pdata->regulator[i].max_uv);
- regulator_set_load(msm8x16->supplies[i].consumer, 0);
- }
- regulator_bulk_free(msm8x16->num_of_supplies, msm8x16->supplies);
- kfree(msm8x16->supplies);
-}
-
-static struct snd_soc_dai_driver msm_codec_dais[] = {
- {
- .name = "msm-codec-rx",
- .playback = { /* Support maximum range */
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- },
- {
- .name = "msm-codec-tx",
- .capture = { /* Support maximum range */
- .stream_name = "Record",
- .channels_min = 1,
- .channels_max = 4,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- },
-};
-
-static struct regmap *msm89xx_codec_regmap;
-static struct regmap *msm89xx_codec_get_regmap(struct device *dev)
-{
- return msm89xx_codec_regmap;
-}
-
-static struct snd_soc_codec_driver soc_msm89xx_codec = {
- .probe = msm89xx_digcodec_probe,
- .remove = msm89xx_digcodec_remove,
- .get_regmap = msm89xx_codec_get_regmap,
-};
-
-static const struct of_device_id msm89xx_codec_of_match[] = {
- { .compatible = "qcom,msm-codec-core",
- .data = "msm_codec"},
- { .compatible = "qcom,pmic-codec-digital",
- .data = "pmic-digital-codec"},
- { .compatible = "qcom,pmic-codec-analog",
- .data = "pmic-analog-codec"},
- {},
-};
-MODULE_DEVICE_TABLE(of, msm89xx_codec_of_match);
-
-static struct msm8x16_wcd *temp_89xx;
-static int msm89xx_codec_probe(struct platform_device *pdev)
-{
- int ret = 0;
- struct msm8x16_wcd *msm8x16 = NULL;
- struct msm8x16_wcd_pdata *pdata;
- int adsp_state;
- static int dev_registered_cnt;
- const struct of_device_id *match;
- const char *addr_prop_name = "qcom,dig-cdc-base-addr";
- u32 dig_cdc_addr;
- char __iomem *dig_base;
-
- adsp_state = apr_get_subsys_state();
- if (adsp_state != APR_SUBSYS_LOADED) {
- dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
- adsp_state);
- return -EPROBE_DEFER;
- }
-
- match = of_match_node(msm89xx_codec_of_match,
- pdev->dev.of_node);
-
- dev_dbg(&pdev->dev, "%s(%d):%s\n",
- __func__, __LINE__, (char *)match->data);
-
- if (!strcmp(match->data, "pmic-digital-codec")) {
- device_init_wakeup(&pdev->dev, true);
-
- if (pdev->dev.of_node) {
- dev_err(&pdev->dev, "%s:Platform data from device tree\n",
- __func__);
- pdata = msm8x16_wcd_populate_dt_pdata(&pdev->dev);
- pdev->dev.platform_data = pdata;
- } else {
- dev_err(&pdev->dev, "%s:Platform data from board file\n",
- __func__);
- pdata = pdev->dev.platform_data;
- }
- if (pdata == NULL) {
- dev_err(&pdev->dev, "%s:Platform data failed to populate\n",
- __func__);
- goto rtn;
- }
- msm8x16 = kzalloc(sizeof(struct msm8x16_wcd), GFP_KERNEL);
- if (msm8x16 == NULL) {
- ret = -ENOMEM;
- goto rtn;
- }
-
- msm8x16->dev = &pdev->dev;
- ret = msm8x16_wcd_init_supplies(msm8x16, pdata);
- if (ret) {
- dev_err(&pdev->dev, "%s: Fail to enable Codec supplies\n",
- __func__);
- goto err_codec;
- }
-
- ret = msm8x16_wcd_enable_static_supplies(msm8x16, pdata);
- if (ret) {
- dev_err(&pdev->dev,
- "%s: Fail to enable Codec pre-reset supplies\n",
- __func__);
- goto err_codec;
- }
- usleep_range(5, 6);
-
- mutex_init(&msm8x16->io_lock);
- dev_set_drvdata(&pdev->dev, msm8x16);
- temp_89xx = msm8x16;
- dev_registered_cnt++;
- } else if (!strcmp(match->data, "pmic-analog-codec")) {
- if (wcd9xxx_spmi_irq_init()) {
- dev_err(&pdev->dev,
- "%s: irq initialization failed\n", __func__);
- } else {
- dev_err(&pdev->dev,
- "%s: irq initialization passed\n", __func__);
- }
- dev_registered_cnt++;
- } else if (!strcmp(match->data, "msm-codec")) {
- ret = of_property_read_u32(pdev->dev.of_node, addr_prop_name,
- &dig_cdc_addr);
- if (ret) {
- dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
- __func__, addr_prop_name);
- dig_cdc_addr = MSM89XX_DIGITAL_CODEC_BASE_ADDR;
- }
- dig_base = ioremap(dig_cdc_addr,
- MSM89XX_DIGITAL_CODEC_REG_SIZE);
- if (dig_base == NULL) {
- dev_err(&pdev->dev, "%s ioremap failed\n", __func__);
- return -ENOMEM;
- }
- msm89xx_codec_regmap =
- devm_regmap_init_mmio_clk(&pdev->dev, NULL,
- dig_base, &msm89xx_cdc_core_regmap_config);
- snd_soc_register_codec(&pdev->dev, &soc_msm89xx_codec,
- msm_codec_dais, ARRAY_SIZE(msm_codec_dais));
- dev_registered_cnt++;
- }
-
- if ((dev_registered_cnt == MAX_MSM89XX_DEVICE) && (!ret)) {
- msm89xx_pmic_cdc_regmap =
- devm_regmap_init_spmi_ext(
- (struct spmi_device *) &pdev->dev.parent,
- &msm89xx_pmic_cdc_regmap_config);
- ret = snd_soc_register_codec(temp_89xx->dev,
- &soc_codec_dev_msm8x16_wcd,
- msm8x16_wcd_i2s_dai,
- ARRAY_SIZE(msm8x16_wcd_i2s_dai));
- if (ret) {
- dev_err(&pdev->dev,
- "%s:snd_soc_register_codec failed with error %d\n",
- __func__, ret);
- goto err_supplies;
- }
- }
- return ret;
-err_supplies:
- msm8x16_wcd_disable_supplies(msm8x16, pdata);
-err_codec:
- kfree(msm8x16);
-rtn:
- return ret;
-}
-
-static int msm89xx_codec_remove(struct platform_device *pdev)
-{
- struct msm8x16_wcd *msm8x16 = dev_get_drvdata(&pdev->dev);
-
- mutex_destroy(&msm8x16->io_lock);
- kfree(msm8x16);
-
- return 0;
-}
-
-static struct platform_driver msm_codec_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = DRV_NAME,
- .of_match_table = of_match_ptr(msm89xx_codec_of_match)
- },
- .probe = msm89xx_codec_probe,
- .remove = msm89xx_codec_remove,
-};
-module_platform_driver(msm_codec_driver);
-
-MODULE_DESCRIPTION("MSM89xx Audio codec driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd.h b/sound/soc/codecs/msm8x16/msm8x16-wcd.h
deleted file mode 100644
index 45ebab2..0000000
--- a/sound/soc/codecs/msm8x16/msm8x16-wcd.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/* 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 MSM8X16_WCD_H
-#define MSM8X16_WCD_H
-
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include <sound/q6afe-v2.h>
-#include "../wcd-mbhc-v2.h"
-#include "../wcdcal-hwdep.h"
-#include "msm8x16_wcd_registers.h"
-
-#define MICBIAS_EXT_BYP_CAP 0x00
-#define MICBIAS_NO_EXT_BYP_CAP 0x01
-
-#define MSM89XX_NUM_IRQ_REGS 2
-#define MAX_REGULATOR 7
-#define MSM89XX_REG_VAL(reg, val) {reg, 0, val}
-#define MSM8X16_TOMBAK_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL 0xFE03B004
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CMD_RCGR 0x0181C09C
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CFG_RCGR 0x0181C0A0
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_M 0x0181C0A4
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_N 0x0181C0A8
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_D 0x0181C0AC
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CBCR 0x0181C0B0
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_AHB_CBCR 0x0181C0B4
-
-#define MSM8X16_CODEC_NAME "msm8x16_wcd_codec"
-
-#define MSM89XX_IS_CDC_CORE_REG(reg) \
- (((reg >= 0x00) && (reg <= 0x3FF)) ? 1 : 0)
-#define MSM89XX_IS_PMIC_CDC_REG(reg) \
- (((reg >= 0xF000) && (reg <= 0xF1FF)) ? 1 : 0)
-/*
- * MCLK activity indicators during suspend and resume call
- */
-#define MCLK_SUS_DIS 1
-#define MCLK_SUS_RSC 2
-#define MCLK_SUS_NO_ACT 3
-
-#define NUM_DECIMATORS 4
-#define MSM89XX_VDD_SPKDRV_NAME "cdc-vdd-spkdrv"
-
-#define DEFAULT_MULTIPLIER 800
-#define DEFAULT_GAIN 9
-#define DEFAULT_OFFSET 100
-
-extern const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE];
-extern const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE];
-extern struct regmap_config msm89xx_cdc_core_regmap_config;
-extern struct regmap_config msm89xx_pmic_cdc_regmap_config;
-
-enum codec_versions {
- TOMBAK_1_0,
- TOMBAK_2_0,
- CONGA,
- CAJON,
- CAJON_2_0,
- DIANGU,
- UNSUPPORTED,
-};
-
-/* Support different hph modes */
-enum {
- NORMAL_MODE = 0,
- HD2_MODE,
-};
-
-/* Codec supports 1 compander */
-enum {
- COMPANDER_NONE = 0,
- COMPANDER_1, /* HPHL/R */
- COMPANDER_MAX,
-};
-
-enum wcd_curr_ref {
- I_h4_UA = 0,
- I_pt5_UA,
- I_14_UA,
- I_l4_UA,
- I_1_UA,
-};
-
-enum wcd_mbhc_imp_det_pin {
- WCD_MBHC_DET_NONE = 0,
- WCD_MBHC_DET_HPHL,
- WCD_MBHC_DET_HPHR,
- WCD_MBHC_DET_BOTH,
-};
-
-
-/* Each micbias can be assigned to one of three cfilters
- * Vbatt_min >= .15V + ldoh_v
- * ldoh_v >= .15v + cfiltx_mv
- * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
- * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
- * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
- * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
- */
-
-struct wcd9xxx_micbias_setting {
- u8 ldoh_v;
- u32 cfilt1_mv; /* in mv */
- u32 cfilt2_mv; /* in mv */
- u32 cfilt3_mv; /* in mv */
- /* Different WCD9xxx series codecs may not
- * have 4 mic biases. If a codec has fewer
- * mic biases, some of these properties will
- * not be used.
- */
- u8 bias1_cfilt_sel;
- u8 bias2_cfilt_sel;
- u8 bias3_cfilt_sel;
- u8 bias4_cfilt_sel;
- u8 bias1_cap_mode;
- u8 bias2_cap_mode;
- u8 bias3_cap_mode;
- u8 bias4_cap_mode;
- bool bias2_is_headset_only;
-};
-
-enum msm8x16_wcd_pid_current {
- MSM89XX_PID_MIC_2P5_UA,
- MSM89XX_PID_MIC_5_UA,
- MSM89XX_PID_MIC_10_UA,
- MSM89XX_PID_MIC_20_UA,
-};
-
-struct msm8x16_wcd_reg_mask_val {
- u16 reg;
- u8 mask;
- u8 val;
-};
-
-enum msm8x16_wcd_mbhc_analog_pwr_cfg {
- MSM89XX_ANALOG_PWR_COLLAPSED = 0,
- MSM89XX_ANALOG_PWR_ON,
- MSM89XX_NUM_ANALOG_PWR_CONFIGS,
-};
-
-/* Number of input and output I2S port */
-enum {
- MSM89XX_RX1 = 0,
- MSM89XX_RX2,
- MSM89XX_RX3,
- MSM89XX_RX_MAX,
-};
-
-enum {
- MSM89XX_TX1 = 0,
- MSM89XX_TX2,
- MSM89XX_TX3,
- MSM89XX_TX4,
- MSM89XX_TX_MAX,
-};
-
-enum {
- /* INTR_REG 0 - Digital Periph */
- MSM89XX_IRQ_SPKR_CNP = 0,
- MSM89XX_IRQ_SPKR_CLIP,
- MSM89XX_IRQ_SPKR_OCP,
- MSM89XX_IRQ_MBHC_INSREM_DET1,
- MSM89XX_IRQ_MBHC_RELEASE,
- MSM89XX_IRQ_MBHC_PRESS,
- MSM89XX_IRQ_MBHC_INSREM_DET,
- MSM89XX_IRQ_MBHC_HS_DET,
- /* INTR_REG 1 - Analog Periph */
- MSM89XX_IRQ_EAR_OCP,
- MSM89XX_IRQ_HPHR_OCP,
- MSM89XX_IRQ_HPHL_OCP,
- MSM89XX_IRQ_EAR_CNP,
- MSM89XX_IRQ_HPHR_CNP,
- MSM89XX_IRQ_HPHL_CNP,
- MSM89XX_NUM_IRQS,
-};
-
-enum {
- ON_DEMAND_MICBIAS = 0,
- ON_DEMAND_SPKDRV,
- ON_DEMAND_SUPPLIES_MAX,
-};
-
-/*
- * The delay list is per codec HW specification.
- * Please add delay in the list in the future instead
- * of magic number
- */
-enum {
- CODEC_DELAY_1_MS = 1000,
- CODEC_DELAY_1_1_MS = 1100,
-};
-
-struct msm8x16_wcd_regulator {
- const char *name;
- int min_uv;
- int max_uv;
- int optimum_ua;
- bool ondemand;
- struct regulator *regulator;
-};
-
-struct on_demand_supply {
- struct regulator *supply;
- atomic_t ref;
-};
-
-struct wcd_imped_i_ref {
- enum wcd_curr_ref curr_ref;
- int min_val;
- int multiplier;
- int gain_adj;
- int offset;
-};
-
-struct msm8x16_wcd_pdata {
- int irq;
- int irq_base;
- int num_irqs;
- int reset_gpio;
- void *msm8x16_wcd_ahb_base_vaddr;
- struct wcd9xxx_micbias_setting micbias;
- struct msm8x16_wcd_regulator regulator[MAX_REGULATOR];
- u32 mclk_rate;
- u32 is_lpass;
-};
-
-enum msm8x16_wcd_micbias_num {
- MSM89XX_MICBIAS1 = 0,
-};
-
-struct msm8x16_wcd {
- struct device *dev;
- struct mutex io_lock;
- u8 version;
-
- int reset_gpio;
- int (*read_dev)(struct snd_soc_codec *codec,
- unsigned short reg);
- int (*write_dev)(struct snd_soc_codec *codec,
- unsigned short reg, u8 val);
-
- u32 num_of_supplies;
- struct regulator_bulk_data *supplies;
-
- u8 idbyte[4];
-
- int num_irqs;
- u32 mclk_rate;
-};
-
-struct msm8x16_wcd_priv {
- struct snd_soc_codec *codec;
- u16 pmic_rev;
- u16 codec_version;
- u32 boost_voltage;
- u32 adc_count;
- u32 rx_bias_count;
- s32 dmic_1_2_clk_cnt;
- u32 mute_mask;
- bool int_mclk0_enabled;
- bool clock_active;
- bool config_mode_active;
- u16 boost_option;
- /* mode to select hd2 */
- u32 hph_mode;
- /* compander used for each rx chain */
- u32 comp_enabled[MSM89XX_RX_MAX];
- bool spk_boost_set;
- bool ear_pa_boost_set;
- bool ext_spk_boost_set;
- bool dec_active[NUM_DECIMATORS];
- struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
- struct regulator *spkdrv_reg;
- /* mbhc module */
- struct wcd_mbhc mbhc;
- /* cal info for codec */
- struct fw_info *fw_data;
- struct blocking_notifier_head notifier;
- int (*codec_spk_ext_pa_cb)(struct snd_soc_codec *codec, int enable);
- int (*codec_hph_comp_gpio)(bool enable);
- unsigned long status_mask;
- struct wcd_imped_i_ref imped_i_ref;
- enum wcd_mbhc_imp_det_pin imped_det_pin;
-};
-
-extern int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
- bool dapm);
-
-extern int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec,
- struct wcd_mbhc_config *mbhc_cfg);
-
-extern void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec);
-
-extern void msm8x16_update_int_spk_boost(bool enable);
-
-extern void msm8x16_wcd_spk_ext_pa_cb(
- int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
- int enable), struct snd_soc_codec *codec);
-
-extern void msm8x16_wcd_hph_comp_cb(
- int (*codec_hph_comp_gpio)(bool enable),
- struct snd_soc_codec *codec);
-void enable_digital_callback(void *flag);
-void disable_digital_callback(void *flag);
-
-#endif
diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c
index cd5e707..abc100f 100644
--- a/sound/soc/codecs/msm_hdmi_codec_rx.c
+++ b/sound/soc/codecs/msm_hdmi_codec_rx.c
@@ -84,6 +84,15 @@
rc = codec_data->ext_disp_ops.get_audio_edid_blk(
codec_data->ext_disp_core_pdev, &edid_blk);
if (rc >= 0) {
+ if (sizeof(ucontrol->value.bytes.data) <
+ (edid_blk.audio_data_blk_size +
+ edid_blk.spk_alloc_data_blk_size)) {
+ dev_err(codec->dev,
+ "%s: Not enough memory to copy EDID data\n",
+ __func__);
+ return -ENOMEM;
+ }
+
memcpy(ucontrol->value.bytes.data,
edid_blk.audio_data_blk,
edid_blk.audio_data_blk_size);
diff --git a/sound/soc/codecs/msm_sdw/Kconfig b/sound/soc/codecs/msm_sdw/Kconfig
new file mode 100644
index 0000000..abd7c8c
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/Kconfig
@@ -0,0 +1,6 @@
+config SND_SOC_MSM_SDW
+ tristate "MSM Internal soundwire codec"
+ help
+ MSM-based soundwire codec core driver
+ supported along with internal digital
+ codec core.
diff --git a/sound/soc/codecs/msm_sdw/Makefile b/sound/soc/codecs/msm_sdw/Makefile
new file mode 100644
index 0000000..64e932b
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/Makefile
@@ -0,0 +1,3 @@
+snd-soc-msm-sdw-objs := msm_sdw_cdc.o msm_sdw_regmap.o msm-sdw-tables.o msm_sdw_cdc_utils.o
+obj-$(CONFIG_SND_SOC_MSM_SDW) += snd-soc-msm-sdw.o
+ccflags-y += -I$(srctree)/sound/soc/msm
diff --git a/sound/soc/codecs/msm_sdw/msm-sdw-tables.c b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
new file mode 100644
index 0000000..4cbdb72
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
@@ -0,0 +1,222 @@
+/* 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 "msm_sdw.h"
+
+const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER] = {
+ [MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 0xa,
+ [MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 0xa,
+ [MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 0xa,
+ [MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 0xa,
+ [MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 0xa,
+ [MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 0xa,
+ [MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 0xa,
+ [MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 0xa,
+ [MSM_SDW_COMPANDER7_CTL0] = 0xb,
+ [MSM_SDW_COMPANDER7_CTL1] = 0xb,
+ [MSM_SDW_COMPANDER7_CTL2] = 0xb,
+ [MSM_SDW_COMPANDER7_CTL3] = 0xb,
+ [MSM_SDW_COMPANDER7_CTL4] = 0xb,
+ [MSM_SDW_COMPANDER7_CTL5] = 0xb,
+ [MSM_SDW_COMPANDER7_CTL6] = 0xb,
+ [MSM_SDW_COMPANDER7_CTL7] = 0xb,
+ [MSM_SDW_COMPANDER8_CTL0] = 0xb,
+ [MSM_SDW_COMPANDER8_CTL1] = 0xb,
+ [MSM_SDW_COMPANDER8_CTL2] = 0xb,
+ [MSM_SDW_COMPANDER8_CTL3] = 0xb,
+ [MSM_SDW_COMPANDER8_CTL4] = 0xb,
+ [MSM_SDW_COMPANDER8_CTL5] = 0xb,
+ [MSM_SDW_COMPANDER8_CTL6] = 0xb,
+ [MSM_SDW_COMPANDER8_CTL7] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_CTL] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_CFG0] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_CFG1] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_CFG2] = 0xb,
+ [MSM_SDW_RX7_RX_VOL_CTL] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_MIX_CTL] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_MIX_CFG] = 0xb,
+ [MSM_SDW_RX7_RX_VOL_MIX_CTL] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_SEC0] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_SEC1] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_SEC2] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_SEC3] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_SEC5] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_SEC6] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_SEC7] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 0xb,
+ [MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_CTL] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_CFG0] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_CFG1] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_CFG2] = 0xb,
+ [MSM_SDW_RX8_RX_VOL_CTL] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_MIX_CTL] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_MIX_CFG] = 0xb,
+ [MSM_SDW_RX8_RX_VOL_MIX_CTL] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_SEC0] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_SEC1] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_SEC2] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_SEC3] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_SEC5] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_SEC6] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_SEC7] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 0xb,
+ [MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 0xb,
+ [MSM_SDW_BOOST0_BOOST_PATH_CTL] = 0xc,
+ [MSM_SDW_BOOST0_BOOST_CTL] = 0xc,
+ [MSM_SDW_BOOST0_BOOST_CFG1] = 0xc,
+ [MSM_SDW_BOOST0_BOOST_CFG2] = 0xc,
+ [MSM_SDW_BOOST1_BOOST_PATH_CTL] = 0xc,
+ [MSM_SDW_BOOST1_BOOST_CTL] = 0xc,
+ [MSM_SDW_BOOST1_BOOST_CFG1] = 0xc,
+ [MSM_SDW_BOOST1_BOOST_CFG2] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_RD_DATA_0] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_RD_DATA_1] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_RD_DATA_2] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_RD_DATA_3] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 0xc,
+ [MSM_SDW_AHB_BRIDGE_ACCESS_STATUS] = 0xc,
+ [MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 0xd,
+ [MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 0xd,
+ [MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 0xd,
+ [MSM_SDW_TOP_TOP_CFG0] = 0xd,
+ [MSM_SDW_TOP_TOP_CFG1] = 0xd,
+ [MSM_SDW_TOP_RX_I2S_CTL] = 0xd,
+ [MSM_SDW_TOP_TX_I2S_CTL] = 0xd,
+ [MSM_SDW_TOP_I2S_CLK] = 0xd,
+ [MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 0xd,
+ [MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 0xd,
+ [MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 0xd,
+ [MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 0xd,
+ [MSM_SDW_TOP_FREQ_MCLK] = 0xd,
+ [MSM_SDW_TOP_DEBUG_BUS_SEL] = 0xd,
+ [MSM_SDW_TOP_DEBUG_EN] = 0xd,
+ [MSM_SDW_TOP_I2S_RESET] = 0xd,
+ [MSM_SDW_TOP_BLOCKS_RESET] = 0xd,
+};
+
+const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER] = {
+ [MSM_SDW_PAGE_REGISTER] = 1,
+ [MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 1,
+ [MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 1,
+ [MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 1,
+ [MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 1,
+ [MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 1,
+ [MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 1,
+ [MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 1,
+ [MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 1,
+ [MSM_SDW_COMPANDER7_CTL0] = 1,
+ [MSM_SDW_COMPANDER7_CTL1] = 1,
+ [MSM_SDW_COMPANDER7_CTL2] = 1,
+ [MSM_SDW_COMPANDER7_CTL3] = 1,
+ [MSM_SDW_COMPANDER7_CTL4] = 1,
+ [MSM_SDW_COMPANDER7_CTL5] = 1,
+ [MSM_SDW_COMPANDER7_CTL6] = 1,
+ [MSM_SDW_COMPANDER7_CTL7] = 1,
+ [MSM_SDW_COMPANDER8_CTL0] = 1,
+ [MSM_SDW_COMPANDER8_CTL1] = 1,
+ [MSM_SDW_COMPANDER8_CTL2] = 1,
+ [MSM_SDW_COMPANDER8_CTL3] = 1,
+ [MSM_SDW_COMPANDER8_CTL4] = 1,
+ [MSM_SDW_COMPANDER8_CTL5] = 1,
+ [MSM_SDW_COMPANDER8_CTL6] = 1,
+ [MSM_SDW_COMPANDER8_CTL7] = 1,
+ [MSM_SDW_RX7_RX_PATH_CTL] = 1,
+ [MSM_SDW_RX7_RX_PATH_CFG0] = 1,
+ [MSM_SDW_RX7_RX_PATH_CFG1] = 1,
+ [MSM_SDW_RX7_RX_PATH_CFG2] = 1,
+ [MSM_SDW_RX7_RX_VOL_CTL] = 1,
+ [MSM_SDW_RX7_RX_PATH_MIX_CTL] = 1,
+ [MSM_SDW_RX7_RX_PATH_MIX_CFG] = 1,
+ [MSM_SDW_RX7_RX_VOL_MIX_CTL] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC0] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC1] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC2] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC3] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC5] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC6] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC7] = 1,
+ [MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 1,
+ [MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 1,
+ [MSM_SDW_RX8_RX_PATH_CTL] = 1,
+ [MSM_SDW_RX8_RX_PATH_CFG0] = 1,
+ [MSM_SDW_RX8_RX_PATH_CFG1] = 1,
+ [MSM_SDW_RX8_RX_PATH_CFG2] = 1,
+ [MSM_SDW_RX8_RX_VOL_CTL] = 1,
+ [MSM_SDW_RX8_RX_PATH_MIX_CTL] = 1,
+ [MSM_SDW_RX8_RX_PATH_MIX_CFG] = 1,
+ [MSM_SDW_RX8_RX_VOL_MIX_CTL] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC0] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC1] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC2] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC3] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC5] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC6] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC7] = 1,
+ [MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 1,
+ [MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 1,
+ [MSM_SDW_BOOST0_BOOST_PATH_CTL] = 1,
+ [MSM_SDW_BOOST0_BOOST_CTL] = 1,
+ [MSM_SDW_BOOST0_BOOST_CFG1] = 1,
+ [MSM_SDW_BOOST0_BOOST_CFG2] = 1,
+ [MSM_SDW_BOOST1_BOOST_PATH_CTL] = 1,
+ [MSM_SDW_BOOST1_BOOST_CTL] = 1,
+ [MSM_SDW_BOOST1_BOOST_CFG1] = 1,
+ [MSM_SDW_BOOST1_BOOST_CFG2] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_DATA_0] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_DATA_1] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_DATA_2] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_DATA_3] = 1,
+ [MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 1,
+ [MSM_SDW_AHB_BRIDGE_ACCESS_STATUS] = 1,
+ [MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 1,
+ [MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 1,
+ [MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 1,
+ [MSM_SDW_TOP_TOP_CFG0] = 1,
+ [MSM_SDW_TOP_TOP_CFG1] = 1,
+ [MSM_SDW_TOP_RX_I2S_CTL] = 1,
+ [MSM_SDW_TOP_TX_I2S_CTL] = 1,
+ [MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 1,
+ [MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 1,
+ [MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 1,
+ [MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 1,
+ [MSM_SDW_TOP_FREQ_MCLK] = 1,
+ [MSM_SDW_TOP_DEBUG_BUS_SEL] = 1,
+ [MSM_SDW_TOP_DEBUG_EN] = 1,
+ [MSM_SDW_TOP_I2S_RESET] = 1,
+ [MSM_SDW_TOP_BLOCKS_RESET] = 1,
+};
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw.h b/sound/soc/codecs/msm_sdw/msm_sdw.h
new file mode 100644
index 0000000..3691e84
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw.h
@@ -0,0 +1,169 @@
+/* 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 MSM_SDW_H
+#define MSM_SDW_H
+
+#include <sound/soc.h>
+#include <sound/q6afe-v2.h>
+#include "msm_sdw_registers.h"
+
+#define MSM_SDW_MAX_REGISTER 0x400
+
+extern const struct regmap_config msm_sdw_regmap_config;
+extern const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER];
+extern const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER];
+
+enum {
+ MSM_SDW_RX4 = 0,
+ MSM_SDW_RX5,
+ MSM_SDW_RX_MAX,
+};
+
+enum {
+ MSM_SDW_TX0 = 0,
+ MSM_SDW_TX1,
+ MSM_SDW_TX_MAX,
+};
+
+enum {
+ COMP1, /* SPK_L */
+ COMP2, /* SPK_R */
+ COMP_MAX
+};
+
+/*
+ * Structure used to update codec
+ * register defaults after reset
+ */
+struct msm_sdw_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
+/*
+ * Selects compander and smart boost settings
+ * for a given speaker mode
+ */
+enum {
+ SPKR_MODE_DEFAULT,
+ SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */
+};
+
+/* Rx path gain offsets */
+enum {
+ RX_GAIN_OFFSET_M1P5_DB,
+ RX_GAIN_OFFSET_0_DB,
+};
+
+struct msm_sdw_reg_val {
+ unsigned short reg; /* register address */
+ u8 *buf; /* buffer to be written to reg. addr */
+ int bytes; /* number of bytes to be written */
+};
+
+/* Hold instance to soundwire platform device */
+struct msm_sdw_ctrl_data {
+ struct platform_device *sdw_pdev;
+};
+
+struct wcd_sdw_ctrl_platform_data {
+ void *handle; /* holds codec private data */
+ int (*read)(void *handle, int reg);
+ int (*write)(void *handle, int reg, int val);
+ int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
+ int (*clk)(void *handle, bool enable);
+ int (*handle_irq)(void *handle,
+ irqreturn_t (*swrm_irq_handler)(int irq,
+ void *data),
+ void *swrm_handle,
+ int action);
+};
+
+struct msm_sdw_priv {
+ struct device *dev;
+ struct mutex io_lock;
+
+ int (*read_dev)(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+ int bytes, void *dest);
+ int (*write_dev)(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+ int bytes, void *src);
+ int (*multi_reg_write)(struct msm_sdw_priv *msm_sdw, const void *data,
+ size_t count);
+ struct snd_soc_codec *codec;
+ struct device_node *sdw_gpio_p; /* used by pinctrl API */
+ /* SoundWire data structure */
+ struct msm_sdw_ctrl_data *sdw_ctrl_data;
+ int nr;
+
+ /* compander */
+ int comp_enabled[COMP_MAX];
+ int ear_spkr_gain;
+
+ /* to track the status */
+ unsigned long status_mask;
+
+ struct work_struct msm_sdw_add_child_devices_work;
+ struct wcd_sdw_ctrl_platform_data sdw_plat_data;
+
+ unsigned int vi_feed_value;
+
+ struct mutex sdw_read_lock;
+ struct mutex sdw_write_lock;
+ struct mutex sdw_clk_lock;
+ int sdw_clk_users;
+ int sdw_mclk_users;
+
+ int sdw_irq;
+ int int_mclk1_rsc_ref;
+ bool int_mclk1_enabled;
+ bool sdw_npl_clk_enabled;
+ struct mutex cdc_int_mclk1_mutex;
+ struct mutex sdw_npl_clk_mutex;
+ struct delayed_work disable_int_mclk1_work;
+ struct afe_clk_set sdw_cdc_core_clk;
+ struct afe_clk_set sdw_npl_clk;
+ struct notifier_block service_nb;
+ int (*sdw_cdc_gpio_fn)(bool enable, struct snd_soc_codec *codec);
+ bool dev_up;
+
+ int spkr_gain_offset;
+ int spkr_mode;
+ struct mutex codec_mutex;
+ int rx_4_count;
+ int rx_5_count;
+ u32 mclk_rate;
+ struct regmap *regmap;
+
+ bool prev_pg_valid;
+ u8 prev_pg;
+ u32 sdw_base_addr;
+ char __iomem *sdw_base;
+ u32 version;
+
+ /* Entry for version info */
+ struct snd_info_entry *entry;
+ struct snd_info_entry *version_entry;
+};
+
+extern int msm_sdw_set_spkr_mode(struct snd_soc_codec *codec, int mode);
+extern int msm_sdw_set_spkr_gain_offset(struct snd_soc_codec *codec,
+ int offset);
+extern void msm_sdw_gpio_cb(
+ int (*sdw_cdc_gpio_fn)(bool enable, struct snd_soc_codec *codec),
+ struct snd_soc_codec *codec);
+extern struct regmap *msm_sdw_regmap_init(struct device *dev,
+ const struct regmap_config *config);
+extern int msm_sdw_codec_info_create_codec_entry(
+ struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec);
+#endif
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
new file mode 100644
index 0000000..a118ecc
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -0,0 +1,1948 @@
+/* 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/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/soundwire/swr-wcd.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/q6core.h>
+#include <sound/tlv.h>
+#include "msm_sdw.h"
+#include "msm_sdw_registers.h"
+
+#define MSM_SDW_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define MSM_SDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define MSM_SDW_STRING_LEN 80
+
+#define INT_MCLK1_FREQ 9600000
+#define SDW_NPL_FREQ 153600000
+
+#define MSM_SDW_VERSION_1_0 0x0001
+#define MSM_SDW_VERSION_ENTRY_SIZE 32
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static struct snd_soc_dai_driver msm_sdw_dai[];
+static bool initial_boot = true;
+static bool is_ssr_en;
+static bool skip_irq = true;
+
+static int msm_sdw_config_ear_spkr_gain(struct snd_soc_codec *codec,
+ int event, int gain_reg);
+static int msm_sdw_config_compander(struct snd_soc_codec *, int, int);
+static int msm_sdw_mclk_enable(struct msm_sdw_priv *msm_sdw,
+ int mclk_enable, bool dapm);
+static int msm_int_enable_sdw_cdc_clk(struct msm_sdw_priv *msm_sdw,
+ int enable, bool dapm);
+
+enum {
+ VI_SENSE_1,
+ VI_SENSE_2,
+};
+
+enum {
+ AIF1_SDW_PB = 0,
+ AIF1_SDW_VIFEED,
+ NUM_CODEC_DAIS,
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_spkr_default[] = {
+ {MSM_SDW_COMPANDER7_CTL3, 0x80, 0x80},
+ {MSM_SDW_COMPANDER8_CTL3, 0x80, 0x80},
+ {MSM_SDW_COMPANDER7_CTL7, 0x01, 0x01},
+ {MSM_SDW_COMPANDER8_CTL7, 0x01, 0x01},
+ {MSM_SDW_BOOST0_BOOST_CTL, 0x7C, 0x50},
+ {MSM_SDW_BOOST1_BOOST_CTL, 0x7C, 0x50},
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_spkr_mode1[] = {
+ {MSM_SDW_COMPANDER7_CTL3, 0x80, 0x00},
+ {MSM_SDW_COMPANDER8_CTL3, 0x80, 0x00},
+ {MSM_SDW_COMPANDER7_CTL7, 0x01, 0x00},
+ {MSM_SDW_COMPANDER8_CTL7, 0x01, 0x00},
+ {MSM_SDW_BOOST0_BOOST_CTL, 0x7C, 0x44},
+ {MSM_SDW_BOOST1_BOOST_CTL, 0x7C, 0x44},
+};
+
+/**
+ * msm_sdw_set_spkr_gain_offset - offset the speaker path
+ * gain with the given offset value.
+ *
+ * @codec: codec instance
+ * @offset: Indicates speaker path gain offset value.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_sdw_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset)
+{
+ struct msm_sdw_priv *priv;
+
+ if (!codec) {
+ pr_err("%s: NULL codec pointer!\n", __func__);
+ return -EINVAL;
+ }
+
+ priv = snd_soc_codec_get_drvdata(codec);
+ if (!priv)
+ return -EINVAL;
+
+ priv->spkr_gain_offset = offset;
+ return 0;
+}
+EXPORT_SYMBOL(msm_sdw_set_spkr_gain_offset);
+
+/**
+ * msm_sdw_set_spkr_mode - Configures speaker compander and smartboost
+ * settings based on speaker mode.
+ *
+ * @codec: codec instance
+ * @mode: Indicates speaker configuration mode.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_sdw_set_spkr_mode(struct snd_soc_codec *codec, int mode)
+{
+ struct msm_sdw_priv *priv;
+ int i;
+ const struct msm_sdw_reg_mask_val *regs;
+ int size;
+
+ if (!codec) {
+ pr_err("%s: NULL codec pointer!\n", __func__);
+ return -EINVAL;
+ }
+
+ priv = snd_soc_codec_get_drvdata(codec);
+ if (!priv)
+ return -EINVAL;
+
+ switch (mode) {
+ case SPKR_MODE_1:
+ regs = msm_sdw_spkr_mode1;
+ size = ARRAY_SIZE(msm_sdw_spkr_mode1);
+ break;
+ default:
+ regs = msm_sdw_spkr_default;
+ size = ARRAY_SIZE(msm_sdw_spkr_default);
+ break;
+ }
+
+ priv->spkr_mode = mode;
+ for (i = 0; i < size; i++)
+ snd_soc_update_bits(codec, regs[i].reg,
+ regs[i].mask, regs[i].val);
+ return 0;
+}
+EXPORT_SYMBOL(msm_sdw_set_spkr_mode);
+
+static int msm_enable_sdw_npl_clk(struct msm_sdw_priv *msm_sdw, int enable)
+{
+ int ret = 0;
+
+ dev_dbg(msm_sdw->dev, "%s: enable %d\n", __func__, enable);
+
+ mutex_lock(&msm_sdw->sdw_npl_clk_mutex);
+ if (enable) {
+ if (msm_sdw->sdw_npl_clk_enabled == false) {
+ msm_sdw->sdw_npl_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT4_MI2S_RX,
+ &msm_sdw->sdw_npl_clk);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev,
+ "%s: failed to enable SDW NPL CLK\n",
+ __func__);
+ mutex_unlock(&msm_sdw->sdw_npl_clk_mutex);
+ return ret;
+ }
+ dev_dbg(msm_sdw->dev, "enabled sdw npl clk\n");
+ msm_sdw->sdw_npl_clk_enabled = true;
+ }
+ } else {
+ if (msm_sdw->sdw_npl_clk_enabled == true) {
+ msm_sdw->sdw_npl_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT4_MI2S_RX,
+ &msm_sdw->sdw_npl_clk);
+ if (ret < 0)
+ dev_err(msm_sdw->dev,
+ "%s: failed to disable SDW NPL CLK\n",
+ __func__);
+ msm_sdw->sdw_npl_clk_enabled = false;
+ }
+ }
+ mutex_unlock(&msm_sdw->sdw_npl_clk_mutex);
+ return ret;
+}
+
+static int msm_int_enable_sdw_cdc_clk(struct msm_sdw_priv *msm_sdw,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+ dev_dbg(msm_sdw->dev, "%s: enable %d mclk1 ref counter %d\n",
+ __func__, enable, msm_sdw->int_mclk1_rsc_ref);
+ if (enable) {
+ if (msm_sdw->int_mclk1_rsc_ref == 0) {
+ cancel_delayed_work_sync(
+ &msm_sdw->disable_int_mclk1_work);
+ if (msm_sdw->int_mclk1_enabled == false) {
+ msm_sdw->sdw_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT4_MI2S_RX,
+ &msm_sdw->sdw_cdc_core_clk);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev,
+ "%s: failed to enable SDW MCLK\n",
+ __func__);
+ goto rtn;
+ }
+ dev_dbg(msm_sdw->dev,
+ "enabled sdw codec core mclk\n");
+ msm_sdw->int_mclk1_enabled = true;
+ }
+ }
+ msm_sdw->int_mclk1_rsc_ref++;
+ } else {
+ cancel_delayed_work_sync(&msm_sdw->disable_int_mclk1_work);
+ if (msm_sdw->int_mclk1_rsc_ref > 0) {
+ msm_sdw->int_mclk1_rsc_ref--;
+ dev_dbg(msm_sdw->dev,
+ "%s: decrementing mclk_res_ref %d\n",
+ __func__, msm_sdw->int_mclk1_rsc_ref);
+ }
+ if (msm_sdw->int_mclk1_enabled == true &&
+ msm_sdw->int_mclk1_rsc_ref == 0) {
+ msm_sdw->sdw_cdc_core_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT4_MI2S_RX,
+ &msm_sdw->sdw_cdc_core_clk);
+ if (ret < 0)
+ dev_err(msm_sdw->dev,
+ "%s: failed to disable SDW MCLK\n",
+ __func__);
+ msm_sdw->int_mclk1_enabled = false;
+ }
+ }
+ mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+rtn:
+ return ret;
+}
+EXPORT_SYMBOL(msm_int_enable_sdw_cdc_clk);
+
+static void msm_disable_int_mclk1(struct work_struct *work)
+{
+ struct msm_sdw_priv *msm_sdw = NULL;
+ struct delayed_work *dwork;
+ int ret = 0;
+
+ dwork = to_delayed_work(work);
+ msm_sdw = container_of(dwork, struct msm_sdw_priv,
+ disable_int_mclk1_work);
+ mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+ dev_dbg(msm_sdw->dev, "%s: mclk1_enabled %d mclk1_rsc_ref %d\n",
+ __func__, msm_sdw->int_mclk1_enabled,
+ msm_sdw->int_mclk1_rsc_ref);
+ if (msm_sdw->int_mclk1_enabled == true
+ && msm_sdw->int_mclk1_rsc_ref == 0) {
+ dev_dbg(msm_sdw->dev, "Disable the mclk1\n");
+ msm_sdw->sdw_cdc_core_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT4_MI2S_RX,
+ &msm_sdw->sdw_cdc_core_clk);
+ if (ret < 0)
+ dev_err(msm_sdw->dev,
+ "%s failed to disable the MCLK1\n",
+ __func__);
+ msm_sdw->int_mclk1_enabled = false;
+ }
+ mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+}
+
+static int msm_int_mclk1_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);
+ struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ dev_dbg(msm_sdw->dev, "%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* enable the codec mclk config */
+ msm_int_enable_sdw_cdc_clk(msm_sdw, 1, true);
+ msm_sdw_mclk_enable(msm_sdw, 1, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* disable the codec mclk config */
+ msm_sdw_mclk_enable(msm_sdw, 0, true);
+ msm_int_enable_sdw_cdc_clk(msm_sdw, 0, true);
+ break;
+ default:
+ dev_err(msm_sdw->dev,
+ "%s: invalid DAPM event %d\n", __func__, event);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int msm_sdw_ahb_write_device(struct msm_sdw_priv *msm_sdw,
+ u16 reg, u8 *value)
+{
+ u32 temp = (u32)(*value) & 0x000000FF;
+
+ if (!msm_sdw->dev_up) {
+ dev_err_ratelimited(msm_sdw->dev, "%s: q6 not ready\n",
+ __func__);
+ return 0;
+ }
+
+ iowrite32(temp, msm_sdw->sdw_base + reg);
+ return 0;
+}
+
+static int msm_sdw_ahb_read_device(struct msm_sdw_priv *msm_sdw,
+ u16 reg, u8 *value)
+{
+ u32 temp;
+
+ if (!msm_sdw->dev_up) {
+ dev_err_ratelimited(msm_sdw->dev, "%s: q6 not ready\n",
+ __func__);
+ return 0;
+ }
+
+ temp = ioread32(msm_sdw->sdw_base + reg);
+ *value = (u8)temp;
+ return 0;
+}
+
+static int __msm_sdw_reg_read(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+ int bytes, void *dest)
+{
+ int ret = -EINVAL, i;
+ u8 temp = 0;
+
+ dev_dbg(msm_sdw->dev, "%s reg = %x\n", __func__, reg);
+ mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+ if (msm_sdw->int_mclk1_enabled == false) {
+ msm_sdw->sdw_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT4_MI2S_RX,
+ &msm_sdw->sdw_cdc_core_clk);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev,
+ "%s:failed to enable the INT_MCLK1\n",
+ __func__);
+ goto unlock_exit;
+ }
+ dev_dbg(msm_sdw->dev, "%s:enabled sdw codec core clk\n",
+ __func__);
+ for (i = 0; i < bytes; i++) {
+ ret = msm_sdw_ahb_read_device(
+ msm_sdw, reg + (4 * i), &temp);
+ ((u8 *)dest)[i] = temp;
+ }
+ msm_sdw->int_mclk1_enabled = true;
+ schedule_delayed_work(&msm_sdw->disable_int_mclk1_work, 50);
+ goto unlock_exit;
+ }
+ for (i = 0; i < bytes; i++) {
+ ret = msm_sdw_ahb_read_device(
+ msm_sdw, reg + (4 * i), &temp);
+ ((u8 *)dest)[i] = temp;
+ }
+unlock_exit:
+ mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+ if (ret < 0) {
+ dev_err_ratelimited(msm_sdw->dev,
+ "%s: codec read failed for reg 0x%x\n",
+ __func__, reg);
+ return ret;
+ }
+ dev_dbg(msm_sdw->dev, "Read 0x%02x from 0x%x\n", temp, reg);
+
+ return 0;
+}
+
+static int __msm_sdw_reg_write(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+ int bytes, void *src)
+{
+ int ret = -EINVAL, i;
+
+ mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+ if (msm_sdw->int_mclk1_enabled == false) {
+ msm_sdw->sdw_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(AFE_PORT_ID_INT4_MI2S_RX,
+ &msm_sdw->sdw_cdc_core_clk);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev,
+ "%s: failed to enable the INT_MCLK1\n",
+ __func__);
+ ret = 0;
+ goto unlock_exit;
+ }
+ dev_dbg(msm_sdw->dev, "%s: enabled INT_MCLK1\n", __func__);
+ for (i = 0; i < bytes; i++)
+ ret = msm_sdw_ahb_write_device(msm_sdw, reg + (4 * i),
+ &((u8 *)src)[i]);
+ msm_sdw->int_mclk1_enabled = true;
+ schedule_delayed_work(&msm_sdw->disable_int_mclk1_work, 50);
+ goto unlock_exit;
+ }
+ for (i = 0; i < bytes; i++)
+ ret = msm_sdw_ahb_write_device(msm_sdw, reg + (4 * i),
+ &((u8 *)src)[i]);
+unlock_exit:
+ mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+ dev_dbg(msm_sdw->dev, "Write 0x%x val 0x%02x\n",
+ reg, (u32)(*(u32 *)src));
+
+ return ret;
+}
+
+static int msm_sdw_codec_enable_vi_feedback(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = NULL;
+ struct msm_sdw_priv *msm_sdw_p = NULL;
+ int ret = 0;
+
+ if (!w) {
+ pr_err("%s invalid params\n", __func__);
+ return -EINVAL;
+ }
+ codec = snd_soc_dapm_to_codec(w->dapm);
+ msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
+ __func__, codec->component.num_dai, w->sname);
+
+ dev_dbg(codec->dev, "%s(): w->name %s event %d w->shift %d\n",
+ __func__, w->name, event, w->shift);
+ if (w->shift != AIF1_SDW_VIFEED) {
+ dev_err(codec->dev,
+ "%s:Error in enabling the vi feedback path\n",
+ __func__);
+ ret = -EINVAL;
+ goto out_vi;
+ }
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (test_bit(VI_SENSE_1, &msm_sdw_p->status_mask)) {
+ dev_dbg(codec->dev, "%s: spkr1 enabled\n", __func__);
+ /* Enable V&I sensing */
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+ 0x20);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x0F, 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x0F,
+ 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x10);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x10,
+ 0x10);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+ 0x00);
+ }
+ if (test_bit(VI_SENSE_2, &msm_sdw_p->status_mask)) {
+ dev_dbg(codec->dev, "%s: spkr2 enabled\n", __func__);
+ /* Enable V&I sensing */
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+ 0x20);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+ 0x20);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x0F,
+ 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x0F,
+ 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x10,
+ 0x10);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x10,
+ 0x10);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+ 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+ 0x00);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (test_bit(VI_SENSE_1, &msm_sdw_p->status_mask)) {
+ /* Disable V&I sensing */
+ dev_dbg(codec->dev, "%s: spkr1 disabled\n", __func__);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+ 0x20);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x10,
+ 0x00);
+ }
+ if (test_bit(VI_SENSE_2, &msm_sdw_p->status_mask)) {
+ /* Disable V&I sensing */
+ dev_dbg(codec->dev, "%s: spkr2 disabled\n", __func__);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+ 0x20);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+ 0x20);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x10,
+ 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x10,
+ 0x00);
+ }
+ break;
+ }
+out_vi:
+ return ret;
+}
+
+static int msm_sdwm_handle_irq(void *handle,
+ irqreturn_t (*swrm_irq_handler)(int irq,
+ void *data),
+ void *swrm_handle,
+ int action)
+{
+ struct msm_sdw_priv *msm_sdw;
+ int ret = 0;
+
+ if (!handle) {
+ pr_err("%s: null handle received\n", __func__);
+ return -EINVAL;
+ }
+ msm_sdw = (struct msm_sdw_priv *) handle;
+
+ if (skip_irq)
+ return ret;
+
+ if (action) {
+ ret = request_threaded_irq(msm_sdw->sdw_irq, NULL,
+ swrm_irq_handler,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "swr_master_irq", swrm_handle);
+ if (ret)
+ dev_err(msm_sdw->dev, "%s: Failed to request irq %d\n",
+ __func__, ret);
+ } else
+ free_irq(msm_sdw->sdw_irq, swrm_handle);
+
+ return ret;
+}
+
+static void msm_sdw_codec_hd2_control(struct snd_soc_codec *codec,
+ u16 reg, int event)
+{
+ u16 hd2_scale_reg;
+ u16 hd2_enable_reg = 0;
+
+ if (reg == MSM_SDW_RX7_RX_PATH_CTL) {
+ hd2_scale_reg = MSM_SDW_RX7_RX_PATH_SEC3;
+ hd2_enable_reg = MSM_SDW_RX7_RX_PATH_CFG0;
+ }
+ if (reg == MSM_SDW_RX8_RX_PATH_CTL) {
+ hd2_scale_reg = MSM_SDW_RX8_RX_PATH_SEC3;
+ hd2_enable_reg = MSM_SDW_RX8_RX_PATH_CFG0;
+ }
+
+ if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x10);
+ snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x01);
+ snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04);
+ }
+
+ if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00);
+ snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x00);
+ snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00);
+ }
+}
+
+static int msm_sdw_enable_swr(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct msm_sdw_priv *msm_sdw;
+ int i, ch_cnt;
+
+ msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+ if (!msm_sdw->nr)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (!(strnstr(w->name, "RX4", sizeof("RX4 MIX"))) &&
+ !msm_sdw->rx_4_count)
+ msm_sdw->rx_4_count++;
+ if (!(strnstr(w->name, "RX5", sizeof("RX5 MIX"))) &&
+ !msm_sdw->rx_5_count)
+ msm_sdw->rx_5_count++;
+ ch_cnt = msm_sdw->rx_4_count + msm_sdw->rx_5_count;
+
+ for (i = 0; i < msm_sdw->nr; i++) {
+ swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+ SWR_DEVICE_UP, NULL);
+ swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+ SWR_SET_NUM_RX_CH, &ch_cnt);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (!(strnstr(w->name, "RX4", sizeof("RX4 MIX"))) &&
+ msm_sdw->rx_4_count)
+ msm_sdw->rx_4_count--;
+ if (!(strnstr(w->name, "RX5", sizeof("RX5 MIX"))) &&
+ msm_sdw->rx_5_count)
+ msm_sdw->rx_5_count--;
+ ch_cnt = msm_sdw->rx_4_count + msm_sdw->rx_5_count;
+
+ for (i = 0; i < msm_sdw->nr; i++)
+ swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+ SWR_SET_NUM_RX_CH, &ch_cnt);
+ break;
+ }
+ dev_dbg(msm_sdw->dev, "%s: current swr ch cnt: %d\n",
+ __func__, msm_sdw->rx_4_count + msm_sdw->rx_5_count);
+
+ return 0;
+}
+
+static int msm_sdw_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+ u16 gain_reg;
+ u16 reg;
+ int val;
+ int offset_val = 0;
+
+ dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+ if (!(strcmp(w->name, "RX INT4 INTERP"))) {
+ reg = MSM_SDW_RX7_RX_PATH_CTL;
+ gain_reg = MSM_SDW_RX7_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT5 INTERP"))) {
+ reg = MSM_SDW_RX8_RX_PATH_CTL;
+ gain_reg = MSM_SDW_RX8_RX_VOL_CTL;
+ } else {
+ dev_err(codec->dev, "%s: Interpolator reg not found\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, reg, 0x10, 0x10);
+ msm_sdw_codec_hd2_control(codec, reg, event);
+ snd_soc_update_bits(codec, reg, 1 << 0x5, 1 << 0x5);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ msm_sdw_config_compander(codec, w->shift, event);
+ /* apply gain after int clk is enabled */
+ if ((msm_sdw->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+ (msm_sdw->comp_enabled[COMP1] ||
+ msm_sdw->comp_enabled[COMP2]) &&
+ (gain_reg == MSM_SDW_RX7_RX_VOL_CTL ||
+ gain_reg == MSM_SDW_RX8_RX_VOL_CTL)) {
+ snd_soc_update_bits(codec, MSM_SDW_RX7_RX_PATH_SEC1,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec,
+ MSM_SDW_RX7_RX_PATH_MIX_SEC0,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, MSM_SDW_RX8_RX_PATH_SEC1,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec,
+ MSM_SDW_RX8_RX_PATH_MIX_SEC0,
+ 0x01, 0x01);
+ offset_val = -2;
+ }
+ val = snd_soc_read(codec, gain_reg);
+ val += offset_val;
+ snd_soc_write(codec, gain_reg, val);
+ msm_sdw_config_ear_spkr_gain(codec, event, gain_reg);
+ snd_soc_update_bits(codec, reg, 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, reg, 1 << 0x5, 0 << 0x5);
+ snd_soc_update_bits(codec, reg, 0x40, 0x40);
+ snd_soc_update_bits(codec, reg, 0x40, 0x00);
+ msm_sdw_codec_hd2_control(codec, reg, event);
+ msm_sdw_config_compander(codec, w->shift, event);
+ if ((msm_sdw->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+ (msm_sdw->comp_enabled[COMP1] ||
+ msm_sdw->comp_enabled[COMP2]) &&
+ (gain_reg == MSM_SDW_RX7_RX_VOL_CTL ||
+ gain_reg == MSM_SDW_RX8_RX_VOL_CTL)) {
+ snd_soc_update_bits(codec, MSM_SDW_RX7_RX_PATH_SEC1,
+ 0x01, 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_RX7_RX_PATH_MIX_SEC0,
+ 0x01, 0x00);
+ snd_soc_update_bits(codec, MSM_SDW_RX8_RX_PATH_SEC1,
+ 0x01, 0x00);
+ snd_soc_update_bits(codec,
+ MSM_SDW_RX8_RX_PATH_MIX_SEC0,
+ 0x01, 0x00);
+ offset_val = 2;
+ val = snd_soc_read(codec, gain_reg);
+ val += offset_val;
+ snd_soc_write(codec, gain_reg, val);
+ }
+ msm_sdw_config_ear_spkr_gain(codec, event, gain_reg);
+ break;
+ };
+
+ return 0;
+}
+
+static int msm_sdw_config_ear_spkr_gain(struct snd_soc_codec *codec,
+ int event, int gain_reg)
+{
+ int comp_gain_offset, val;
+ struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+ switch (msm_sdw->spkr_mode) {
+ /* Compander gain in SPKR_MODE1 case is 12 dB */
+ case SPKR_MODE_1:
+ comp_gain_offset = -12;
+ break;
+ /* Default case compander gain is 15 dB */
+ default:
+ comp_gain_offset = -15;
+ break;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Apply ear spkr gain only if compander is enabled */
+ if (msm_sdw->comp_enabled[COMP1] &&
+ (gain_reg == MSM_SDW_RX7_RX_VOL_CTL) &&
+ (msm_sdw->ear_spkr_gain != 0)) {
+ /* For example, val is -8(-12+5-1) for 4dB of gain */
+ val = comp_gain_offset + msm_sdw->ear_spkr_gain - 1;
+ snd_soc_write(codec, gain_reg, val);
+
+ dev_dbg(codec->dev, "%s: RX4 Volume %d dB\n",
+ __func__, val);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * Reset RX4 volume to 0 dB if compander is enabled and
+ * ear_spkr_gain is non-zero.
+ */
+ if (msm_sdw->comp_enabled[COMP1] &&
+ (gain_reg == MSM_SDW_RX7_RX_VOL_CTL) &&
+ (msm_sdw->ear_spkr_gain != 0)) {
+ snd_soc_write(codec, gain_reg, 0x0);
+
+ dev_dbg(codec->dev, "%s: Reset RX4 Volume to 0 dB\n",
+ __func__);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_sdw_codec_spk_boost_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);
+ u16 boost_path_ctl, boost_path_cfg1;
+ u16 reg;
+
+ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+ if (!strcmp(w->name, "RX INT4 CHAIN")) {
+ boost_path_ctl = MSM_SDW_BOOST0_BOOST_PATH_CTL;
+ boost_path_cfg1 = MSM_SDW_RX7_RX_PATH_CFG1;
+ reg = MSM_SDW_RX7_RX_PATH_CTL;
+ } else if (!strcmp(w->name, "RX INT5 CHAIN")) {
+ boost_path_ctl = MSM_SDW_BOOST1_BOOST_PATH_CTL;
+ boost_path_cfg1 = MSM_SDW_RX8_RX_PATH_CFG1;
+ reg = MSM_SDW_RX8_RX_PATH_CTL;
+ } else {
+ dev_err(codec->dev, "%s: boost reg not found\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x10);
+ snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x01);
+ snd_soc_update_bits(codec, reg, 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x00);
+ snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x00);
+ break;
+ };
+
+ return 0;
+}
+
+static int msm_sdw_config_compander(struct snd_soc_codec *codec, int comp,
+ int event)
+{
+ struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+ u16 comp_ctl0_reg, rx_path_cfg0_reg;
+
+ if (comp < COMP1 || comp >= COMP_MAX)
+ return 0;
+
+ dev_dbg(codec->dev, "%s: event %d compander %d, enabled %d\n",
+ __func__, event, comp + 1, msm_sdw->comp_enabled[comp]);
+
+ if (!msm_sdw->comp_enabled[comp])
+ return 0;
+
+ comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 8);
+ rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 20);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ /* Enable Compander Clock */
+ snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x01);
+ snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+ snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+ snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x02);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x04);
+ snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x00);
+ snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+ snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+ snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x00);
+ snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x00);
+ }
+
+ return 0;
+}
+
+static int msm_sdw_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = msm_sdw->comp_enabled[comp];
+ return 0;
+}
+
+static int msm_sdw_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
+ __func__, comp + 1, msm_sdw->comp_enabled[comp], value);
+ msm_sdw->comp_enabled[comp] = value;
+
+ return 0;
+}
+
+static int msm_sdw_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = msm_sdw->ear_spkr_gain;
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_sdw_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+ msm_sdw->ear_spkr_gain = ucontrol->value.integer.value[0];
+
+ dev_dbg(codec->dev, "%s: gain = %d\n", __func__,
+ msm_sdw->ear_spkr_gain);
+
+ return 0;
+}
+
+static int msm_sdw_vi_feed_mixer_get(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_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+ struct msm_sdw_priv *msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = msm_sdw_p->vi_feed_value;
+
+ return 0;
+}
+
+static int msm_sdw_vi_feed_mixer_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 snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+ struct msm_sdw_priv *msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+ struct soc_multi_mixer_control *mixer =
+ ((struct soc_multi_mixer_control *)kcontrol->private_value);
+ u32 dai_id = widget->shift;
+ u32 port_id = mixer->shift;
+ u32 enable = ucontrol->value.integer.value[0];
+
+ dev_dbg(codec->dev, "%s: enable: %d, port_id:%d, dai_id: %d\n",
+ __func__, enable, port_id, dai_id);
+
+ msm_sdw_p->vi_feed_value = ucontrol->value.integer.value[0];
+
+ mutex_lock(&msm_sdw_p->codec_mutex);
+ if (enable) {
+ if (port_id == MSM_SDW_TX0 && !test_bit(VI_SENSE_1,
+ &msm_sdw_p->status_mask))
+ set_bit(VI_SENSE_1, &msm_sdw_p->status_mask);
+ if (port_id == MSM_SDW_TX1 && !test_bit(VI_SENSE_2,
+ &msm_sdw_p->status_mask))
+ set_bit(VI_SENSE_2, &msm_sdw_p->status_mask);
+ } else {
+ if (port_id == MSM_SDW_TX0 && test_bit(VI_SENSE_1,
+ &msm_sdw_p->status_mask))
+ clear_bit(VI_SENSE_1, &msm_sdw_p->status_mask);
+ if (port_id == MSM_SDW_TX1 && test_bit(VI_SENSE_2,
+ &msm_sdw_p->status_mask))
+ clear_bit(VI_SENSE_2, &msm_sdw_p->status_mask);
+ }
+ mutex_unlock(&msm_sdw_p->codec_mutex);
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
+
+ return 0;
+}
+
+static int msm_sdw_mclk_enable(struct msm_sdw_priv *msm_sdw,
+ int mclk_enable, bool dapm)
+{
+ dev_dbg(msm_sdw->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n",
+ __func__, mclk_enable, dapm, msm_sdw->sdw_mclk_users);
+ if (mclk_enable) {
+ msm_sdw->sdw_mclk_users++;
+ if (msm_sdw->sdw_mclk_users == 1) {
+ regmap_update_bits(msm_sdw->regmap,
+ MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL,
+ 0x01, 0x01);
+ regmap_update_bits(msm_sdw->regmap,
+ MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL,
+ 0x01, 0x01);
+ /* 9.6MHz MCLK, set value 0x00 if other frequency */
+ regmap_update_bits(msm_sdw->regmap,
+ MSM_SDW_TOP_FREQ_MCLK, 0x01, 0x01);
+ }
+ } else {
+ msm_sdw->sdw_mclk_users--;
+ if (msm_sdw->sdw_mclk_users == 0) {
+ regmap_update_bits(msm_sdw->regmap,
+ MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL,
+ 0x01, 0x00);
+ regmap_update_bits(msm_sdw->regmap,
+ MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL,
+ 0x01, 0x00);
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(msm_sdw_mclk_enable);
+
+static int msm_sdw_swrm_read(void *handle, int reg)
+{
+ struct msm_sdw_priv *msm_sdw;
+ unsigned short sdw_rd_addr_base;
+ unsigned short sdw_rd_data_base;
+ int val, ret;
+
+ if (!handle) {
+ pr_err("%s: NULL handle\n", __func__);
+ return -EINVAL;
+ }
+ msm_sdw = (struct msm_sdw_priv *)handle;
+
+ dev_dbg(msm_sdw->dev, "%s: Reading soundwire register, 0x%x\n",
+ __func__, reg);
+ sdw_rd_addr_base = MSM_SDW_AHB_BRIDGE_RD_ADDR_0;
+ sdw_rd_data_base = MSM_SDW_AHB_BRIDGE_RD_DATA_0;
+ /* read_lock */
+ mutex_lock(&msm_sdw->sdw_read_lock);
+ ret = regmap_bulk_write(msm_sdw->regmap, sdw_rd_addr_base,
+ (u8 *)®, 4);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev, "%s: RD Addr Failure\n", __func__);
+ goto err;
+ }
+ /* Check for RD value */
+ ret = regmap_bulk_read(msm_sdw->regmap, sdw_rd_data_base,
+ (u8 *)&val, 4);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev, "%s: RD Data Failure\n", __func__);
+ goto err;
+ }
+ ret = val;
+err:
+ /* read_unlock */
+ mutex_unlock(&msm_sdw->sdw_read_lock);
+ return ret;
+}
+
+static int msm_sdw_bulk_write(struct msm_sdw_priv *msm_sdw,
+ struct msm_sdw_reg_val *bulk_reg,
+ size_t len)
+{
+ int i, ret = 0;
+ unsigned short sdw_wr_addr_base;
+ unsigned short sdw_wr_data_base;
+
+ sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+ sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+ for (i = 0; i < len; i += 2) {
+ /* First Write the Data to register */
+ ret = regmap_bulk_write(msm_sdw->regmap,
+ sdw_wr_data_base, bulk_reg[i].buf, 4);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev, "%s: WR Data Failure\n",
+ __func__);
+ break;
+ }
+ /* Next Write Address */
+ ret = regmap_bulk_write(msm_sdw->regmap,
+ sdw_wr_addr_base, bulk_reg[i+1].buf, 4);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev,
+ "%s: WR Addr Failure: 0x%x\n",
+ __func__, (u32)(bulk_reg[i+1].buf[0]));
+ break;
+ }
+ }
+ return ret;
+}
+
+static int msm_sdw_swrm_bulk_write(void *handle, u32 *reg, u32 *val, size_t len)
+{
+ struct msm_sdw_priv *msm_sdw;
+ struct msm_sdw_reg_val *bulk_reg;
+ unsigned short sdw_wr_addr_base;
+ unsigned short sdw_wr_data_base;
+ int i, j, ret;
+
+ if (!handle) {
+ pr_err("%s: NULL handle\n", __func__);
+ return -EINVAL;
+ }
+
+ msm_sdw = (struct msm_sdw_priv *)handle;
+ if (len <= 0) {
+ dev_err(msm_sdw->dev,
+ "%s: Invalid size: %zu\n", __func__, len);
+ return -EINVAL;
+ }
+
+ sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+ sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+ bulk_reg = kzalloc((2 * len * sizeof(struct msm_sdw_reg_val)),
+ GFP_KERNEL);
+ if (!bulk_reg)
+ return -ENOMEM;
+
+ for (i = 0, j = 0; i < (len * 2); i += 2, j++) {
+ bulk_reg[i].reg = sdw_wr_data_base;
+ bulk_reg[i].buf = (u8 *)(&val[j]);
+ bulk_reg[i].bytes = 4;
+ bulk_reg[i+1].reg = sdw_wr_addr_base;
+ bulk_reg[i+1].buf = (u8 *)(®[j]);
+ bulk_reg[i+1].bytes = 4;
+ }
+ mutex_lock(&msm_sdw->sdw_write_lock);
+
+ ret = msm_sdw_bulk_write(msm_sdw, bulk_reg, (len * 2));
+ if (ret)
+ dev_err(msm_sdw->dev, "%s: swrm bulk write failed, ret: %d\n",
+ __func__, ret);
+
+ mutex_unlock(&msm_sdw->sdw_write_lock);
+ kfree(bulk_reg);
+
+ return ret;
+}
+
+static int msm_sdw_swrm_write(void *handle, int reg, int val)
+{
+ struct msm_sdw_priv *msm_sdw;
+ unsigned short sdw_wr_addr_base;
+ unsigned short sdw_wr_data_base;
+ struct msm_sdw_reg_val bulk_reg[2];
+ int ret;
+
+ if (!handle) {
+ pr_err("%s: NULL handle\n", __func__);
+ return -EINVAL;
+ }
+ msm_sdw = (struct msm_sdw_priv *)handle;
+
+ sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+ sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+ /* First Write the Data to register */
+ bulk_reg[0].reg = sdw_wr_data_base;
+ bulk_reg[0].buf = (u8 *)(&val);
+ bulk_reg[0].bytes = 4;
+ bulk_reg[1].reg = sdw_wr_addr_base;
+ bulk_reg[1].buf = (u8 *)(®);
+ bulk_reg[1].bytes = 4;
+
+ mutex_lock(&msm_sdw->sdw_write_lock);
+
+ ret = msm_sdw_bulk_write(msm_sdw, bulk_reg, 2);
+ if (ret < 0)
+ dev_err(msm_sdw->dev, "%s: WR Data Failure\n", __func__);
+
+ mutex_unlock(&msm_sdw->sdw_write_lock);
+ return ret;
+}
+
+static int msm_sdw_swrm_clock(void *handle, bool enable)
+{
+ struct msm_sdw_priv *msm_sdw = (struct msm_sdw_priv *) handle;
+
+ mutex_lock(&msm_sdw->sdw_clk_lock);
+
+ dev_dbg(msm_sdw->dev, "%s: swrm clock %s\n",
+ __func__, (enable ? "enable" : "disable"));
+ if (enable) {
+ msm_sdw->sdw_clk_users++;
+ if (msm_sdw->sdw_clk_users == 1) {
+ msm_int_enable_sdw_cdc_clk(msm_sdw, 1, true);
+ msm_sdw_mclk_enable(msm_sdw, 1, true);
+ regmap_update_bits(msm_sdw->regmap,
+ MSM_SDW_CLK_RST_CTRL_SWR_CONTROL, 0x01, 0x01);
+ msm_enable_sdw_npl_clk(msm_sdw, true);
+ msm_cdc_pinctrl_select_active_state(
+ msm_sdw->sdw_gpio_p);
+ }
+ } else {
+ msm_sdw->sdw_clk_users--;
+ if (msm_sdw->sdw_clk_users == 0) {
+ regmap_update_bits(msm_sdw->regmap,
+ MSM_SDW_CLK_RST_CTRL_SWR_CONTROL,
+ 0x01, 0x00);
+ msm_sdw_mclk_enable(msm_sdw, 0, true);
+ msm_int_enable_sdw_cdc_clk(msm_sdw, 0, true);
+ msm_enable_sdw_npl_clk(msm_sdw, false);
+ msm_cdc_pinctrl_select_sleep_state(msm_sdw->sdw_gpio_p);
+ }
+ }
+ dev_dbg(msm_sdw->dev, "%s: swrm clock users %d\n",
+ __func__, msm_sdw->sdw_clk_users);
+ mutex_unlock(&msm_sdw->sdw_clk_lock);
+ return 0;
+}
+
+static int msm_sdw_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
+ __func__,
+ substream->name, substream->stream);
+ return 0;
+}
+
+static int msm_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ u8 rx_clk_fs_rate, rx_fs_rate;
+
+ dev_dbg(dai->codec->dev,
+ "%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
+ __func__, dai->name, dai->id, params_rate(params),
+ params_channels(params), params_format(params));
+
+ switch (params_rate(params)) {
+ case 8000:
+ rx_clk_fs_rate = 0x00;
+ rx_fs_rate = 0x00;
+ break;
+ case 16000:
+ rx_clk_fs_rate = 0x01;
+ rx_fs_rate = 0x01;
+ break;
+ case 32000:
+ rx_clk_fs_rate = 0x02;
+ rx_fs_rate = 0x03;
+ break;
+ case 48000:
+ rx_clk_fs_rate = 0x03;
+ rx_fs_rate = 0x04;
+ break;
+ case 96000:
+ rx_clk_fs_rate = 0x04;
+ rx_fs_rate = 0x05;
+ break;
+ case 192000:
+ rx_clk_fs_rate = 0x05;
+ rx_fs_rate = 0x06;
+ break;
+ default:
+ dev_err(dai->codec->dev,
+ "%s: Invalid sampling rate %d\n", __func__,
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_TOP_RX_I2S_CTL, 0x1C, (rx_clk_fs_rate << 2));
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_RX7_RX_PATH_CTL, 0x0F, rx_fs_rate);
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_RX8_RX_PATH_CTL, 0x0F, rx_fs_rate);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_TOP_RX_I2S_CTL, 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_TOP_RX_I2S_CTL, 0x20, 0x00);
+ break;
+ default:
+ dev_err(dai->codec->dev, "%s: wrong format selected\n",
+ __func__);
+ return -EINVAL;
+ }
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_TOP_TX_I2S_CTL, 0x20, 0x20);
+
+ return 0;
+}
+
+static void msm_sdw_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ dev_dbg(dai->codec->dev,
+ "%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+}
+
+static ssize_t msm_sdw_codec_version_read(struct snd_info_entry *entry,
+ void *file_private_data,
+ struct file *file,
+ char __user *buf, size_t count,
+ loff_t pos)
+{
+ struct msm_sdw_priv *msm_sdw;
+ char buffer[MSM_SDW_VERSION_ENTRY_SIZE];
+ int len = 0;
+
+ msm_sdw = (struct msm_sdw_priv *) entry->private_data;
+ if (!msm_sdw) {
+ pr_err("%s: msm_sdw priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (msm_sdw->version) {
+ case MSM_SDW_VERSION_1_0:
+ len = snprintf(buffer, sizeof(buffer), "SDW-CDC_1_0\n");
+ break;
+ default:
+ len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+ }
+
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_sdw_codec_info_ops = {
+ .read = msm_sdw_codec_version_read,
+};
+
+/*
+ * msm_sdw_codec_info_create_codec_entry - creates msm_sdw module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates msm_sdw module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_sdw_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec)
+{
+ struct snd_info_entry *version_entry;
+ struct msm_sdw_priv *msm_sdw;
+ struct snd_soc_card *card;
+
+ if (!codec_root || !codec)
+ return -EINVAL;
+
+ msm_sdw = snd_soc_codec_get_drvdata(codec);
+ card = codec->component.card;
+ msm_sdw->entry = snd_register_module_info(codec_root->module,
+ "152c1000.msm-sdw-codec",
+ codec_root);
+ if (!msm_sdw->entry) {
+ dev_err(codec->dev, "%s: failed to create msm_sdw entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry = snd_info_create_card_entry(card->snd_card,
+ "version",
+ msm_sdw->entry);
+ if (!version_entry) {
+ dev_err(codec->dev, "%s: failed to create msm_sdw version entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry->private_data = msm_sdw;
+ version_entry->size = MSM_SDW_VERSION_ENTRY_SIZE;
+ version_entry->content = SNDRV_INFO_CONTENT_DATA;
+ version_entry->c.ops = &msm_sdw_codec_info_ops;
+
+ if (snd_info_register(version_entry) < 0) {
+ snd_info_free_entry(version_entry);
+ return -ENOMEM;
+ }
+ msm_sdw->version_entry = version_entry;
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_sdw_codec_info_create_codec_entry);
+
+static struct snd_soc_dai_ops msm_sdw_dai_ops = {
+ .startup = msm_sdw_startup,
+ .shutdown = msm_sdw_shutdown,
+ .hw_params = msm_sdw_hw_params,
+};
+
+static struct snd_soc_dai_driver msm_sdw_dai[] = {
+ {
+ .name = "msm_sdw_i2s_rx1",
+ .id = AIF1_SDW_PB,
+ .playback = {
+ .stream_name = "AIF1_SDW Playback",
+ .rates = MSM_SDW_RATES,
+ .formats = MSM_SDW_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &msm_sdw_dai_ops,
+ },
+ {
+ .name = "msm_sdw_vifeedback",
+ .id = AIF1_SDW_VIFEED,
+ .capture = {
+ .stream_name = "VIfeed_SDW",
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_max = 8000,
+ .rate_min = 8000,
+ .channels_min = 2,
+ .channels_max = 4,
+ },
+ .ops = &msm_sdw_dai_ops,
+ },
+};
+
+static const char * const rx_mix1_text[] = {
+ "ZERO", "RX4", "RX5"
+};
+
+static const char * const msm_sdw_ear_spkr_pa_gain_text[] = {
+ "G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB",
+ "G_4_DB", "G_5_DB", "G_6_DB"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(msm_sdw_ear_spkr_pa_gain_enum,
+ msm_sdw_ear_spkr_pa_gain_text);
+/* RX4 MIX1 */
+static const struct soc_enum rx4_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(MSM_SDW_TOP_RX7_PATH_INPUT0_MUX,
+ 0, 3, rx_mix1_text);
+
+static const struct soc_enum rx4_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(MSM_SDW_TOP_RX7_PATH_INPUT1_MUX,
+ 0, 3, rx_mix1_text);
+
+/* RX5 MIX1 */
+static const struct soc_enum rx5_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(MSM_SDW_TOP_RX8_PATH_INPUT0_MUX,
+ 0, 3, rx_mix1_text);
+
+static const struct soc_enum rx5_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(MSM_SDW_TOP_RX8_PATH_INPUT1_MUX,
+ 0, 3, rx_mix1_text);
+
+static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new aif1_vi_mixer[] = {
+ SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, MSM_SDW_TX0, 1, 0,
+ msm_sdw_vi_feed_mixer_get, msm_sdw_vi_feed_mixer_put),
+ SOC_SINGLE_EXT("SPKR_VI_2", SND_SOC_NOPM, MSM_SDW_TX1, 1, 0,
+ msm_sdw_vi_feed_mixer_get, msm_sdw_vi_feed_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget msm_sdw_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("I2S RX4", "AIF1_SDW Playback", 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("I2S RX5", "AIF1_SDW Playback", 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT_E("AIF1_SDW VI", "VIfeed_SDW", 0, SND_SOC_NOPM,
+ AIF1_SDW_VIFEED, 0, msm_sdw_codec_enable_vi_feedback,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("AIF1_VI_SDW Mixer", SND_SOC_NOPM, AIF1_SDW_VIFEED,
+ 0, aif1_vi_mixer, ARRAY_SIZE(aif1_vi_mixer)),
+
+ SND_SOC_DAPM_MUX_E("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp1_mux, msm_sdw_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp2_mux, msm_sdw_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx5_mix1_inp1_mux, msm_sdw_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx5_mix1_inp2_mux, msm_sdw_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX5 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER_E("RX INT4 INTERP", SND_SOC_NOPM,
+ COMP1, 0, NULL, 0, msm_sdw_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX INT5 INTERP", SND_SOC_NOPM,
+ COMP2, 0, NULL, 0, msm_sdw_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("RX INT4 CHAIN", SND_SOC_NOPM, 0, 0,
+ NULL, 0, msm_sdw_codec_spk_boost_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX INT5 CHAIN", SND_SOC_NOPM, 0, 0,
+ NULL, 0, msm_sdw_codec_spk_boost_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("VIINPUT_SDW"),
+
+ SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
+ SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
+
+ SND_SOC_DAPM_SUPPLY_S("SDW_CONN", -1, MSM_SDW_TOP_I2S_CLK,
+ 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("INT_MCLK1", -2, SND_SOC_NOPM, 0, 0,
+ msm_int_mclk1_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("SDW_RX_I2S_CLK",
+ MSM_SDW_TOP_RX_I2S_CTL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SDW_TX_I2S_CLK",
+ MSM_SDW_TOP_TX_I2S_CTL, 0, 0, NULL, 0),
+};
+
+static const struct snd_kcontrol_new msm_sdw_snd_controls[] = {
+ SOC_ENUM_EXT("EAR SPKR PA Gain", msm_sdw_ear_spkr_pa_gain_enum,
+ msm_sdw_ear_spkr_pa_gain_get,
+ msm_sdw_ear_spkr_pa_gain_put),
+ SOC_SINGLE_SX_TLV("RX4 Digital Volume", MSM_SDW_RX7_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX5 Digital Volume", MSM_SDW_RX8_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMP1, 1, 0,
+ msm_sdw_get_compander, msm_sdw_set_compander),
+ SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMP2, 1, 0,
+ msm_sdw_get_compander, msm_sdw_set_compander),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+ {"AIF1_SDW VI", NULL, "SDW_TX_I2S_CLK"},
+ {"SDW_TX_I2S_CLK", NULL, "INT_MCLK1"},
+ {"SDW_TX_I2S_CLK", NULL, "SDW_CONN"},
+
+ /* VI Feedback */
+ {"AIF1_VI_SDW Mixer", "SPKR_VI_1", "VIINPUT_SDW"},
+ {"AIF1_VI_SDW Mixer", "SPKR_VI_2", "VIINPUT_SDW"},
+ {"AIF1_SDW VI", NULL, "AIF1_VI_SDW Mixer"},
+
+ {"SDW_RX_I2S_CLK", NULL, "INT_MCLK1"},
+ {"SDW_RX_I2S_CLK", NULL, "SDW_CONN"},
+ {"I2S RX4", NULL, "SDW_RX_I2S_CLK"},
+ {"I2S RX5", NULL, "SDW_RX_I2S_CLK"},
+
+ {"RX4 MIX1 INP1", "RX4", "I2S RX4"},
+ {"RX4 MIX1 INP1", "RX5", "I2S RX5"},
+ {"RX4 MIX1 INP2", "RX4", "I2S RX4"},
+ {"RX4 MIX1 INP2", "RX5", "I2S RX5"},
+ {"RX5 MIX1 INP1", "RX4", "I2S RX4"},
+ {"RX5 MIX1 INP1", "RX5", "I2S RX5"},
+ {"RX5 MIX1 INP2", "RX4", "I2S RX4"},
+ {"RX5 MIX1 INP2", "RX5", "I2S RX5"},
+
+ {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
+ {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
+ {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
+ {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
+
+ {"RX INT4 INTERP", NULL, "RX4 MIX1"},
+ {"RX INT4 CHAIN", NULL, "RX INT4 INTERP"},
+ {"SPK1 OUT", NULL, "RX INT4 CHAIN"},
+
+ {"RX INT5 INTERP", NULL, "RX5 MIX1"},
+ {"RX INT5 CHAIN", NULL, "RX INT5 INTERP"},
+ {"SPK2 OUT", NULL, "RX INT5 CHAIN"},
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_reg_init[] = {
+ {MSM_SDW_BOOST0_BOOST_CFG1, 0x3F, 0x12},
+ {MSM_SDW_BOOST0_BOOST_CFG2, 0x1C, 0x08},
+ {MSM_SDW_COMPANDER7_CTL7, 0x1E, 0x18},
+ {MSM_SDW_BOOST1_BOOST_CFG1, 0x3F, 0x12},
+ {MSM_SDW_BOOST1_BOOST_CFG2, 0x1C, 0x08},
+ {MSM_SDW_COMPANDER8_CTL7, 0x1E, 0x18},
+ {MSM_SDW_BOOST0_BOOST_CTL, 0x70, 0x50},
+ {MSM_SDW_BOOST1_BOOST_CTL, 0x70, 0x50},
+ {MSM_SDW_RX7_RX_PATH_CFG1, 0x08, 0x08},
+ {MSM_SDW_RX8_RX_PATH_CFG1, 0x08, 0x08},
+ {MSM_SDW_TOP_TOP_CFG1, 0x02, 0x02},
+ {MSM_SDW_TOP_TOP_CFG1, 0x01, 0x01},
+ {MSM_SDW_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {MSM_SDW_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {MSM_SDW_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {MSM_SDW_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {MSM_SDW_COMPANDER7_CTL3, 0x80, 0x80},
+ {MSM_SDW_COMPANDER8_CTL3, 0x80, 0x80},
+ {MSM_SDW_COMPANDER7_CTL7, 0x01, 0x01},
+ {MSM_SDW_COMPANDER8_CTL7, 0x01, 0x01},
+ {MSM_SDW_RX7_RX_PATH_CFG0, 0x01, 0x01},
+ {MSM_SDW_RX8_RX_PATH_CFG0, 0x01, 0x01},
+ {MSM_SDW_RX7_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {MSM_SDW_RX8_RX_PATH_MIX_CFG, 0x01, 0x01},
+};
+
+static void msm_sdw_init_reg(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(msm_sdw_reg_init); i++)
+ snd_soc_update_bits(codec,
+ msm_sdw_reg_init[i].reg,
+ msm_sdw_reg_init[i].mask,
+ msm_sdw_reg_init[i].val);
+}
+
+static int msm_sdw_notifier_service_cb(struct notifier_block *nb,
+ unsigned long opcode, void *ptr)
+{
+ int i;
+ struct msm_sdw_priv *msm_sdw = container_of(nb,
+ struct msm_sdw_priv,
+ service_nb);
+
+ pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
+
+ mutex_lock(&msm_sdw->codec_mutex);
+ switch (opcode) {
+ case AUDIO_NOTIFIER_SERVICE_DOWN:
+ msm_sdw->dev_up = false;
+ for (i = 0; i < msm_sdw->nr; i++)
+ swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+ SWR_DEVICE_DOWN, NULL);
+ break;
+ case AUDIO_NOTIFIER_SERVICE_UP:
+ if (initial_boot) {
+ initial_boot = false;
+ break;
+ }
+ msm_sdw->dev_up = true;
+ msm_sdw_init_reg(msm_sdw->codec);
+ regcache_mark_dirty(msm_sdw->regmap);
+ regcache_sync(msm_sdw->regmap);
+ msm_sdw_set_spkr_mode(msm_sdw->codec, msm_sdw->spkr_mode);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&msm_sdw->codec_mutex);
+ return NOTIFY_OK;
+}
+
+static int msm_sdw_codec_probe(struct snd_soc_codec *codec)
+{
+ struct msm_sdw_priv *msm_sdw;
+ int i, ret;
+
+ msm_sdw = snd_soc_codec_get_drvdata(codec);
+ if (!msm_sdw) {
+ pr_err("%s:SDW priv data null\n", __func__);
+ return -EINVAL;
+ }
+ msm_sdw->codec = codec;
+ for (i = 0; i < COMP_MAX; i++)
+ msm_sdw->comp_enabled[i] = 0;
+
+ msm_sdw->spkr_gain_offset = RX_GAIN_OFFSET_0_DB;
+ msm_sdw_init_reg(codec);
+ msm_sdw->version = MSM_SDW_VERSION_1_0;
+
+ if (is_ssr_en) {
+ msm_sdw->service_nb.notifier_call = msm_sdw_notifier_service_cb;
+ ret = audio_notifier_register("msm_sdw",
+ AUDIO_NOTIFIER_ADSP_DOMAIN,
+ &msm_sdw->service_nb);
+ if (ret < 0)
+ dev_err(msm_sdw->dev,
+ "%s: Audio notifier register failed ret = %d\n",
+ __func__, ret);
+ }
+
+ return 0;
+}
+
+static int msm_sdw_codec_remove(struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+static struct regmap *msm_sdw_get_regmap(struct device *dev)
+{
+ struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+
+ return msm_sdw->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_msm_sdw = {
+ .probe = msm_sdw_codec_probe,
+ .remove = msm_sdw_codec_remove,
+ .controls = msm_sdw_snd_controls,
+ .num_controls = ARRAY_SIZE(msm_sdw_snd_controls),
+ .dapm_widgets = msm_sdw_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(msm_sdw_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+ .get_regmap = msm_sdw_get_regmap,
+};
+
+static void msm_sdw_add_child_devices(struct work_struct *work)
+{
+ struct msm_sdw_priv *msm_sdw;
+ struct platform_device *pdev;
+ struct device_node *node;
+ struct msm_sdw_ctrl_data *sdw_ctrl_data = NULL, *temp;
+ int ret, ctrl_num = 0;
+ struct wcd_sdw_ctrl_platform_data *platdata;
+ char plat_dev_name[MSM_SDW_STRING_LEN];
+
+ msm_sdw = container_of(work, struct msm_sdw_priv,
+ msm_sdw_add_child_devices_work);
+ if (!msm_sdw) {
+ pr_err("%s: Memory for msm_sdw does not exist\n",
+ __func__);
+ return;
+ }
+ if (!msm_sdw->dev->of_node) {
+ dev_err(msm_sdw->dev,
+ "%s: DT node for msm_sdw does not exist\n", __func__);
+ return;
+ }
+
+ platdata = &msm_sdw->sdw_plat_data;
+
+ for_each_available_child_of_node(msm_sdw->dev->of_node, node) {
+ if (!strcmp(node->name, "swr_master"))
+ strlcpy(plat_dev_name, "msm_sdw_swr_ctrl",
+ (MSM_SDW_STRING_LEN - 1));
+ else if (strnstr(node->name, "msm_cdc_pinctrl",
+ strlen("msm_cdc_pinctrl")) != NULL)
+ strlcpy(plat_dev_name, node->name,
+ (MSM_SDW_STRING_LEN - 1));
+ else
+ continue;
+
+ pdev = platform_device_alloc(plat_dev_name, -1);
+ if (!pdev) {
+ dev_err(msm_sdw->dev, "%s: pdev memory alloc failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+ pdev->dev.parent = msm_sdw->dev;
+ pdev->dev.of_node = node;
+
+ if (!strcmp(node->name, "swr_master")) {
+ ret = platform_device_add_data(pdev, platdata,
+ sizeof(*platdata));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: cannot add plat data ctrl:%d\n",
+ __func__, ctrl_num);
+ goto fail_pdev_add;
+ }
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Cannot add platform device\n",
+ __func__);
+ goto fail_pdev_add;
+ }
+
+ if (!strcmp(node->name, "swr_master")) {
+ temp = krealloc(sdw_ctrl_data,
+ (ctrl_num + 1) * sizeof(
+ struct msm_sdw_ctrl_data),
+ GFP_KERNEL);
+ if (!temp) {
+ dev_err(&pdev->dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ sdw_ctrl_data = temp;
+ sdw_ctrl_data[ctrl_num].sdw_pdev = pdev;
+ ctrl_num++;
+ dev_dbg(&pdev->dev,
+ "%s: Added soundwire ctrl device(s)\n",
+ __func__);
+ msm_sdw->nr = ctrl_num;
+ msm_sdw->sdw_ctrl_data = sdw_ctrl_data;
+ }
+ }
+
+ return;
+fail_pdev_add:
+ platform_device_put(pdev);
+err:
+ return;
+}
+
+static int msm_sdw_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_sdw_priv *msm_sdw;
+ int adsp_state;
+
+ adsp_state = apr_get_subsys_state();
+ if (adsp_state != APR_SUBSYS_LOADED) {
+ dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
+ adsp_state);
+ return -EPROBE_DEFER;
+ }
+
+ msm_sdw = devm_kzalloc(&pdev->dev, sizeof(struct msm_sdw_priv),
+ GFP_KERNEL);
+ if (!msm_sdw)
+ return -ENOMEM;
+ dev_set_drvdata(&pdev->dev, msm_sdw);
+ msm_sdw->dev_up = true;
+
+ msm_sdw->dev = &pdev->dev;
+ INIT_WORK(&msm_sdw->msm_sdw_add_child_devices_work,
+ msm_sdw_add_child_devices);
+ msm_sdw->sdw_plat_data.handle = (void *) msm_sdw;
+ msm_sdw->sdw_plat_data.read = msm_sdw_swrm_read;
+ msm_sdw->sdw_plat_data.write = msm_sdw_swrm_write;
+ msm_sdw->sdw_plat_data.bulk_write = msm_sdw_swrm_bulk_write;
+ msm_sdw->sdw_plat_data.clk = msm_sdw_swrm_clock;
+ msm_sdw->sdw_plat_data.handle_irq = msm_sdwm_handle_irq;
+ ret = of_property_read_u32(pdev->dev.of_node, "reg",
+ &msm_sdw->sdw_base_addr);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+ __func__, "reg");
+ goto err_sdw_cdc;
+ }
+
+ msm_sdw->sdw_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,cdc-sdw-gpios", 0);
+ msm_sdw->sdw_base = ioremap(msm_sdw->sdw_base_addr,
+ MSM_SDW_MAX_REGISTER);
+ msm_sdw->read_dev = __msm_sdw_reg_read;
+ msm_sdw->write_dev = __msm_sdw_reg_write;
+
+ msm_sdw->regmap = msm_sdw_regmap_init(msm_sdw->dev,
+ &msm_sdw_regmap_config);
+ msm_sdw->sdw_irq = platform_get_irq_byname(pdev, "swr_master_irq");
+ if (msm_sdw->sdw_irq < 0) {
+ dev_err(msm_sdw->dev, "%s() error getting irq handle: %d\n",
+ __func__, msm_sdw->sdw_irq);
+ ret = -ENODEV;
+ goto err_sdw_cdc;
+ }
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_msm_sdw,
+ msm_sdw_dai, ARRAY_SIZE(msm_sdw_dai));
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Codec registration failed, ret = %d\n",
+ __func__, ret);
+ goto err_sdw_cdc;
+ }
+ /* initialize the int_mclk1 */
+ msm_sdw->sdw_cdc_core_clk.clk_set_minor_version =
+ AFE_API_VERSION_I2S_CONFIG;
+ msm_sdw->sdw_cdc_core_clk.clk_id =
+ Q6AFE_LPASS_CLK_ID_INT_MCLK_1;
+ msm_sdw->sdw_cdc_core_clk.clk_freq_in_hz =
+ INT_MCLK1_FREQ;
+ msm_sdw->sdw_cdc_core_clk.clk_attri =
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
+ msm_sdw->sdw_cdc_core_clk.clk_root =
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+ msm_sdw->sdw_cdc_core_clk.enable = 0;
+
+ /* initialize the sdw_npl_clk */
+ msm_sdw->sdw_npl_clk.clk_set_minor_version =
+ AFE_API_VERSION_I2S_CONFIG;
+ msm_sdw->sdw_npl_clk.clk_id =
+ AFE_CLOCK_SET_CLOCK_ID_SWR_NPL_CLK;
+ msm_sdw->sdw_npl_clk.clk_freq_in_hz = SDW_NPL_FREQ;
+ msm_sdw->sdw_npl_clk.clk_attri =
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
+ msm_sdw->sdw_npl_clk.clk_root =
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+ msm_sdw->sdw_npl_clk.enable = 0;
+
+ INIT_DELAYED_WORK(&msm_sdw->disable_int_mclk1_work,
+ msm_disable_int_mclk1);
+ mutex_init(&msm_sdw->cdc_int_mclk1_mutex);
+ mutex_init(&msm_sdw->sdw_npl_clk_mutex);
+ mutex_init(&msm_sdw->io_lock);
+ mutex_init(&msm_sdw->sdw_read_lock);
+ mutex_init(&msm_sdw->sdw_write_lock);
+ mutex_init(&msm_sdw->sdw_clk_lock);
+ mutex_init(&msm_sdw->codec_mutex);
+ schedule_work(&msm_sdw->msm_sdw_add_child_devices_work);
+
+ dev_dbg(&pdev->dev, "%s: msm_sdw driver probe done\n", __func__);
+ return ret;
+
+err_sdw_cdc:
+ devm_kfree(&pdev->dev, msm_sdw);
+ return ret;
+}
+
+static int msm_sdw_remove(struct platform_device *pdev)
+{
+ struct msm_sdw_priv *msm_sdw;
+
+ msm_sdw = dev_get_drvdata(&pdev->dev);
+
+ mutex_destroy(&msm_sdw->io_lock);
+ mutex_destroy(&msm_sdw->sdw_read_lock);
+ mutex_destroy(&msm_sdw->sdw_write_lock);
+ mutex_destroy(&msm_sdw->sdw_clk_lock);
+ mutex_destroy(&msm_sdw->codec_mutex);
+ mutex_destroy(&msm_sdw->cdc_int_mclk1_mutex);
+ devm_kfree(&pdev->dev, msm_sdw);
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_sdw_codec_dt_match[] = {
+ { .compatible = "qcom,msm-sdw-codec", },
+ {}
+};
+
+static struct platform_driver msm_sdw_codec_driver = {
+ .probe = msm_sdw_probe,
+ .remove = msm_sdw_remove,
+ .driver = {
+ .name = "msm_sdw_codec",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_sdw_codec_dt_match,
+ },
+};
+module_platform_driver(msm_sdw_codec_driver);
+
+MODULE_DESCRIPTION("MSM Soundwire Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc_utils.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc_utils.c
new file mode 100644
index 0000000..9a5c85b
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc_utils.c
@@ -0,0 +1,211 @@
+/* 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/regmap.h>
+#include "msm_sdw.h"
+
+#define REG_BYTES 2
+#define VAL_BYTES 1
+/*
+ * Page Register Address that APP Proc uses to
+ * access WCD9335 Codec registers is identified
+ * as 0x00
+ */
+#define PAGE_REG_ADDR 0x00
+
+/*
+ * msm_sdw_page_write:
+ * Retrieve page number from register and
+ * write that page number to the page address.
+ * Called under io_lock acquisition.
+ *
+ * @msm_sdw: pointer to msm_sdw
+ * @reg: Register address from which page number is retrieved
+ *
+ * Returns 0 for success and negative error code for failure.
+ */
+int msm_sdw_page_write(struct msm_sdw_priv *msm_sdw, unsigned short reg)
+{
+ int ret = 0;
+ u8 pg_num, prev_pg_num;
+
+ pg_num = msm_sdw_page_map[reg];
+ if (msm_sdw->prev_pg_valid) {
+ prev_pg_num = msm_sdw->prev_pg;
+ if (prev_pg_num != pg_num) {
+ ret = msm_sdw->write_dev(msm_sdw, PAGE_REG_ADDR, 1,
+ (void *) &pg_num);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev,
+ "page write error, pg_num: 0x%x\n",
+ pg_num);
+ } else {
+ msm_sdw->prev_pg = pg_num;
+ dev_dbg(msm_sdw->dev,
+ "%s: Page 0x%x Write to 0x00\n",
+ __func__, pg_num);
+ }
+ }
+ } else {
+ ret = msm_sdw->write_dev(msm_sdw, PAGE_REG_ADDR, 1,
+ (void *) &pg_num);
+ if (ret < 0) {
+ dev_err(msm_sdw->dev,
+ "page write error, pg_num: 0x%x\n", pg_num);
+ } else {
+ msm_sdw->prev_pg = pg_num;
+ msm_sdw->prev_pg_valid = true;
+ dev_dbg(msm_sdw->dev, "%s: Page 0x%x Write to 0x00\n",
+ __func__, pg_num);
+ }
+ }
+ return ret;
+}
+EXPORT_SYMBOL(msm_sdw_page_write);
+
+static int regmap_bus_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct device *dev = context;
+ struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+ unsigned short c_reg;
+ int ret, i;
+
+ if (!msm_sdw) {
+ dev_err(dev, "%s: msm_sdw is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (!reg || !val) {
+ dev_err(dev, "%s: reg or val is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (reg_size != REG_BYTES) {
+ dev_err(dev, "%s: register size %zd bytes, not supported\n",
+ __func__, reg_size);
+ return -EINVAL;
+ }
+ if (!msm_sdw->dev_up) {
+ dev_dbg_ratelimited(dev, "%s: No read allowed. dev_up = %d\n",
+ __func__, msm_sdw->dev_up);
+ return 0;
+ }
+
+ mutex_lock(&msm_sdw->io_lock);
+ c_reg = *(u16 *)reg;
+ ret = msm_sdw_page_write(msm_sdw, c_reg);
+ if (ret)
+ goto err;
+ ret = msm_sdw->read_dev(msm_sdw, c_reg, val_size, val);
+ if (ret < 0)
+ dev_err(dev, "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n",
+ __func__, ret, c_reg, val_size);
+ else {
+ for (i = 0; i < val_size; i++)
+ dev_dbg(dev, "%s: Read 0x%02x from 0x%x\n",
+ __func__, ((u8 *)val)[i], c_reg + i);
+ }
+err:
+ mutex_unlock(&msm_sdw->io_lock);
+
+ return ret;
+}
+
+static int regmap_bus_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
+{
+ struct device *dev = context;
+ struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+ unsigned short c_reg;
+ int ret, i;
+
+ if (!msm_sdw) {
+ dev_err(dev, "%s: msm_sdw is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (!reg || !val) {
+ dev_err(dev, "%s: reg or val is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (reg_size != REG_BYTES) {
+ dev_err(dev, "%s: register size %zd bytes, not supported\n",
+ __func__, reg_size);
+ return -EINVAL;
+ }
+ if (!msm_sdw->dev_up) {
+ dev_dbg_ratelimited(dev, "%s: No write allowed. dev_up = %d\n",
+ __func__, msm_sdw->dev_up);
+ return 0;
+ }
+
+ mutex_lock(&msm_sdw->io_lock);
+ c_reg = *(u16 *)reg;
+ ret = msm_sdw_page_write(msm_sdw, c_reg);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < val_size; i++)
+ dev_dbg(dev, "Write %02x to 0x%x\n", ((u8 *)val)[i],
+ c_reg + i*4);
+
+ ret = msm_sdw->write_dev(msm_sdw, c_reg, val_size, (void *) val);
+ if (ret < 0)
+ dev_err(dev,
+ "%s: Codec write failed (%d), reg:0x%x, size:%zd\n",
+ __func__, ret, c_reg, val_size);
+
+err:
+ mutex_unlock(&msm_sdw->io_lock);
+ return ret;
+}
+
+static int regmap_bus_write(void *context, const void *data, size_t count)
+{
+ struct device *dev = context;
+ struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+
+ if (!msm_sdw)
+ return -EINVAL;
+
+ WARN_ON(count < REG_BYTES);
+
+ return regmap_bus_gather_write(context, data, REG_BYTES,
+ data + REG_BYTES,
+ count - REG_BYTES);
+
+}
+
+static struct regmap_bus regmap_bus_config = {
+ .write = regmap_bus_write,
+ .gather_write = regmap_bus_gather_write,
+ .read = regmap_bus_read,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+/*
+ * msm_sdw_regmap_init:
+ * Initialize msm_sdw register map
+ *
+ * @dev: pointer to wcd device
+ * @config: pointer to register map config
+ *
+ * Returns pointer to regmap structure for success
+ * or NULL in case of failure.
+ */
+struct regmap *msm_sdw_regmap_init(struct device *dev,
+ const struct regmap_config *config)
+{
+ return devm_regmap_init(dev, ®map_bus_config, dev, config);
+}
+EXPORT_SYMBOL(msm_sdw_regmap_init);
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_registers.h b/sound/soc/codecs/msm_sdw/msm_sdw_registers.h
new file mode 100644
index 0000000..1b7b0b0
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_registers.h
@@ -0,0 +1,126 @@
+/* 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 MSM_SDW_REGISTERS_H
+#define MSM_SDW_REGISTERS_H
+
+#define MSM_SDW_PAGE_REGISTER 0x0000
+
+/* Page-A Registers */
+#define MSM_SDW_TX9_SPKR_PROT_PATH_CTL 0x0308
+#define MSM_SDW_TX9_SPKR_PROT_PATH_CFG0 0x030c
+#define MSM_SDW_TX10_SPKR_PROT_PATH_CTL 0x0318
+#define MSM_SDW_TX10_SPKR_PROT_PATH_CFG0 0x031c
+#define MSM_SDW_TX11_SPKR_PROT_PATH_CTL 0x0328
+#define MSM_SDW_TX11_SPKR_PROT_PATH_CFG0 0x032c
+#define MSM_SDW_TX12_SPKR_PROT_PATH_CTL 0x0338
+#define MSM_SDW_TX12_SPKR_PROT_PATH_CFG0 0x033c
+
+/* Page-B Registers */
+#define MSM_SDW_COMPANDER7_CTL0 0x0024
+#define MSM_SDW_COMPANDER7_CTL1 0x0028
+#define MSM_SDW_COMPANDER7_CTL2 0x002c
+#define MSM_SDW_COMPANDER7_CTL3 0x0030
+#define MSM_SDW_COMPANDER7_CTL4 0x0034
+#define MSM_SDW_COMPANDER7_CTL5 0x0038
+#define MSM_SDW_COMPANDER7_CTL6 0x003c
+#define MSM_SDW_COMPANDER7_CTL7 0x0040
+#define MSM_SDW_COMPANDER8_CTL0 0x0044
+#define MSM_SDW_COMPANDER8_CTL1 0x0048
+#define MSM_SDW_COMPANDER8_CTL2 0x004c
+#define MSM_SDW_COMPANDER8_CTL3 0x0050
+#define MSM_SDW_COMPANDER8_CTL4 0x0054
+#define MSM_SDW_COMPANDER8_CTL5 0x0058
+#define MSM_SDW_COMPANDER8_CTL6 0x005c
+#define MSM_SDW_COMPANDER8_CTL7 0x0060
+#define MSM_SDW_RX7_RX_PATH_CTL 0x01a4
+#define MSM_SDW_RX7_RX_PATH_CFG0 0x01a8
+#define MSM_SDW_RX7_RX_PATH_CFG1 0x01ac
+#define MSM_SDW_RX7_RX_PATH_CFG2 0x01b0
+#define MSM_SDW_RX7_RX_VOL_CTL 0x01b4
+#define MSM_SDW_RX7_RX_PATH_MIX_CTL 0x01b8
+#define MSM_SDW_RX7_RX_PATH_MIX_CFG 0x01bc
+#define MSM_SDW_RX7_RX_VOL_MIX_CTL 0x01c0
+#define MSM_SDW_RX7_RX_PATH_SEC0 0x01c4
+#define MSM_SDW_RX7_RX_PATH_SEC1 0x01c8
+#define MSM_SDW_RX7_RX_PATH_SEC2 0x01cc
+#define MSM_SDW_RX7_RX_PATH_SEC3 0x01d0
+#define MSM_SDW_RX7_RX_PATH_SEC5 0x01d8
+#define MSM_SDW_RX7_RX_PATH_SEC6 0x01dc
+#define MSM_SDW_RX7_RX_PATH_SEC7 0x01e0
+#define MSM_SDW_RX7_RX_PATH_MIX_SEC0 0x01e4
+#define MSM_SDW_RX7_RX_PATH_MIX_SEC1 0x01e8
+#define MSM_SDW_RX8_RX_PATH_CTL 0x0384
+#define MSM_SDW_RX8_RX_PATH_CFG0 0x0388
+#define MSM_SDW_RX8_RX_PATH_CFG1 0x038c
+#define MSM_SDW_RX8_RX_PATH_CFG2 0x0390
+#define MSM_SDW_RX8_RX_VOL_CTL 0x0394
+#define MSM_SDW_RX8_RX_PATH_MIX_CTL 0x0398
+#define MSM_SDW_RX8_RX_PATH_MIX_CFG 0x039c
+#define MSM_SDW_RX8_RX_VOL_MIX_CTL 0x03a0
+#define MSM_SDW_RX8_RX_PATH_SEC0 0x03a4
+#define MSM_SDW_RX8_RX_PATH_SEC1 0x03a8
+#define MSM_SDW_RX8_RX_PATH_SEC2 0x03ac
+#define MSM_SDW_RX8_RX_PATH_SEC3 0x03b0
+#define MSM_SDW_RX8_RX_PATH_SEC5 0x03b8
+#define MSM_SDW_RX8_RX_PATH_SEC6 0x03bc
+#define MSM_SDW_RX8_RX_PATH_SEC7 0x03c0
+#define MSM_SDW_RX8_RX_PATH_MIX_SEC0 0x03c4
+#define MSM_SDW_RX8_RX_PATH_MIX_SEC1 0x03c8
+
+/* Page-C Registers */
+#define MSM_SDW_BOOST0_BOOST_PATH_CTL 0x0064
+#define MSM_SDW_BOOST0_BOOST_CTL 0x0068
+#define MSM_SDW_BOOST0_BOOST_CFG1 0x006c
+#define MSM_SDW_BOOST0_BOOST_CFG2 0x0070
+#define MSM_SDW_BOOST1_BOOST_PATH_CTL 0x0084
+#define MSM_SDW_BOOST1_BOOST_CTL 0x0088
+#define MSM_SDW_BOOST1_BOOST_CFG1 0x008c
+#define MSM_SDW_BOOST1_BOOST_CFG2 0x0090
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_0 0x00a4
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_1 0x00a8
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_2 0x00ac
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_3 0x00b0
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_0 0x00b4
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_1 0x00b8
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_2 0x00bc
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_3 0x00c0
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_0 0x00c4
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_1 0x00c8
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_2 0x00cc
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_3 0x00d0
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_0 0x00d4
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_1 0x00d8
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_2 0x00dc
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_3 0x00e0
+#define MSM_SDW_AHB_BRIDGE_ACCESS_CFG 0x00e4
+#define MSM_SDW_AHB_BRIDGE_ACCESS_STATUS 0x00e8
+
+/* Page-D Registers */
+#define MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL 0x0104
+#define MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL 0x0108
+#define MSM_SDW_CLK_RST_CTRL_SWR_CONTROL 0x010c
+#define MSM_SDW_TOP_TOP_CFG0 0x0204
+#define MSM_SDW_TOP_TOP_CFG1 0x0208
+#define MSM_SDW_TOP_RX_I2S_CTL 0x020c
+#define MSM_SDW_TOP_TX_I2S_CTL 0x0210
+#define MSM_SDW_TOP_I2S_CLK 0x0214
+#define MSM_SDW_TOP_RX7_PATH_INPUT0_MUX 0x0218
+#define MSM_SDW_TOP_RX7_PATH_INPUT1_MUX 0x021c
+#define MSM_SDW_TOP_RX8_PATH_INPUT0_MUX 0x0220
+#define MSM_SDW_TOP_RX8_PATH_INPUT1_MUX 0x0224
+#define MSM_SDW_TOP_FREQ_MCLK 0x0228
+#define MSM_SDW_TOP_DEBUG_BUS_SEL 0x022c
+#define MSM_SDW_TOP_DEBUG_EN 0x0230
+#define MSM_SDW_TOP_I2S_RESET 0x0234
+#define MSM_SDW_TOP_BLOCKS_RESET 0x0238
+
+#endif
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
new file mode 100644
index 0000000..78858f0
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
@@ -0,0 +1,155 @@
+/* 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/regmap.h>
+#include "msm_sdw.h"
+
+static const struct reg_default msm_sdw_defaults[] = {
+ /* Page #10 registers */
+ { MSM_SDW_PAGE_REGISTER, 0x00 },
+ { MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x02 },
+ { MSM_SDW_TX9_SPKR_PROT_PATH_CFG0, 0x00 },
+ { MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x02 },
+ { MSM_SDW_TX10_SPKR_PROT_PATH_CFG0, 0x00 },
+ { MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x02 },
+ { MSM_SDW_TX11_SPKR_PROT_PATH_CFG0, 0x00 },
+ { MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x02 },
+ { MSM_SDW_TX12_SPKR_PROT_PATH_CFG0, 0x00 },
+ /* Page #11 registers */
+ { MSM_SDW_COMPANDER7_CTL0, 0x60 },
+ { MSM_SDW_COMPANDER7_CTL1, 0xdb },
+ { MSM_SDW_COMPANDER7_CTL2, 0xff },
+ { MSM_SDW_COMPANDER7_CTL3, 0x35 },
+ { MSM_SDW_COMPANDER7_CTL4, 0xff },
+ { MSM_SDW_COMPANDER7_CTL5, 0x00 },
+ { MSM_SDW_COMPANDER7_CTL6, 0x01 },
+ { MSM_SDW_COMPANDER8_CTL0, 0x60 },
+ { MSM_SDW_COMPANDER8_CTL1, 0xdb },
+ { MSM_SDW_COMPANDER8_CTL2, 0xff },
+ { MSM_SDW_COMPANDER8_CTL3, 0x35 },
+ { MSM_SDW_COMPANDER8_CTL4, 0xff },
+ { MSM_SDW_COMPANDER8_CTL5, 0x00 },
+ { MSM_SDW_COMPANDER8_CTL6, 0x01 },
+ { MSM_SDW_RX7_RX_PATH_CTL, 0x04 },
+ { MSM_SDW_RX7_RX_PATH_CFG0, 0x00 },
+ { MSM_SDW_RX7_RX_PATH_CFG2, 0x8f },
+ { MSM_SDW_RX7_RX_VOL_CTL, 0x00 },
+ { MSM_SDW_RX7_RX_PATH_MIX_CTL, 0x04 },
+ { MSM_SDW_RX7_RX_VOL_MIX_CTL, 0x00 },
+ { MSM_SDW_RX7_RX_PATH_SEC2, 0x00 },
+ { MSM_SDW_RX7_RX_PATH_SEC3, 0x00 },
+ { MSM_SDW_RX7_RX_PATH_SEC5, 0x00 },
+ { MSM_SDW_RX7_RX_PATH_SEC6, 0x00 },
+ { MSM_SDW_RX7_RX_PATH_SEC7, 0x00 },
+ { MSM_SDW_RX7_RX_PATH_MIX_SEC1, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_CTL, 0x04 },
+ { MSM_SDW_RX8_RX_PATH_CFG0, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_CFG2, 0x8f },
+ { MSM_SDW_RX8_RX_VOL_CTL, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_MIX_CTL, 0x04 },
+ { MSM_SDW_RX8_RX_VOL_MIX_CTL, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_SEC2, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_SEC3, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_SEC5, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_SEC6, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_SEC7, 0x00 },
+ { MSM_SDW_RX8_RX_PATH_MIX_SEC1, 0x00 },
+ /* Page #12 registers */
+ { MSM_SDW_BOOST0_BOOST_PATH_CTL, 0x00 },
+ { MSM_SDW_BOOST0_BOOST_CTL, 0xb2 },
+ { MSM_SDW_BOOST0_BOOST_CFG1, 0x00 },
+ { MSM_SDW_BOOST0_BOOST_CFG2, 0x00 },
+ { MSM_SDW_BOOST1_BOOST_PATH_CTL, 0x00 },
+ { MSM_SDW_BOOST1_BOOST_CTL, 0xb2 },
+ { MSM_SDW_BOOST1_BOOST_CFG1, 0x00 },
+ { MSM_SDW_BOOST1_BOOST_CFG2, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_WR_DATA_0, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_WR_DATA_1, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_WR_DATA_2, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_WR_DATA_3, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_WR_ADDR_0, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_WR_ADDR_1, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_WR_ADDR_2, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_WR_ADDR_3, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_RD_ADDR_0, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_RD_ADDR_1, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_RD_ADDR_2, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_RD_ADDR_3, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_RD_DATA_0, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_RD_DATA_1, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_RD_DATA_2, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_RD_DATA_3, 0x00 },
+ { MSM_SDW_AHB_BRIDGE_ACCESS_CFG, 0x0f },
+ { MSM_SDW_AHB_BRIDGE_ACCESS_STATUS, 0x03 },
+ /* Page #13 registers */
+ { MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL, 0x00 },
+ { MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 },
+ { MSM_SDW_CLK_RST_CTRL_SWR_CONTROL, 0x00 },
+ { MSM_SDW_TOP_TOP_CFG0, 0x00 },
+ { MSM_SDW_TOP_TOP_CFG1, 0x00 },
+ { MSM_SDW_TOP_RX_I2S_CTL, 0x0C },
+ { MSM_SDW_TOP_TX_I2S_CTL, 0x00 },
+ { MSM_SDW_TOP_I2S_CLK, 0x00 },
+ { MSM_SDW_TOP_RX7_PATH_INPUT0_MUX, 0x00 },
+ { MSM_SDW_TOP_RX7_PATH_INPUT1_MUX, 0x00 },
+ { MSM_SDW_TOP_RX8_PATH_INPUT0_MUX, 0x00 },
+ { MSM_SDW_TOP_RX8_PATH_INPUT1_MUX, 0x00 },
+ { MSM_SDW_TOP_FREQ_MCLK, 0x00 },
+ { MSM_SDW_TOP_DEBUG_BUS_SEL, 0x00 },
+ { MSM_SDW_TOP_DEBUG_EN, 0x00 },
+ { MSM_SDW_TOP_I2S_RESET, 0x00 },
+ { MSM_SDW_TOP_BLOCKS_RESET, 0x00 },
+};
+
+static bool msm_sdw_is_readable_register(struct device *dev, unsigned int reg)
+{
+ return msm_sdw_reg_readable[reg];
+}
+
+static bool msm_sdw_is_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MSM_SDW_AHB_BRIDGE_WR_DATA_0:
+ case MSM_SDW_AHB_BRIDGE_WR_DATA_1:
+ case MSM_SDW_AHB_BRIDGE_WR_DATA_2:
+ case MSM_SDW_AHB_BRIDGE_WR_DATA_3:
+ case MSM_SDW_AHB_BRIDGE_WR_ADDR_0:
+ case MSM_SDW_AHB_BRIDGE_WR_ADDR_1:
+ case MSM_SDW_AHB_BRIDGE_WR_ADDR_2:
+ case MSM_SDW_AHB_BRIDGE_WR_ADDR_3:
+ case MSM_SDW_AHB_BRIDGE_RD_DATA_0:
+ case MSM_SDW_AHB_BRIDGE_RD_DATA_1:
+ case MSM_SDW_AHB_BRIDGE_RD_DATA_2:
+ case MSM_SDW_AHB_BRIDGE_RD_DATA_3:
+ case MSM_SDW_AHB_BRIDGE_RD_ADDR_0:
+ case MSM_SDW_AHB_BRIDGE_RD_ADDR_1:
+ case MSM_SDW_AHB_BRIDGE_RD_ADDR_2:
+ case MSM_SDW_AHB_BRIDGE_RD_ADDR_3:
+ case MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL:
+ case MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const struct regmap_config msm_sdw_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .reg_stride = 4,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = msm_sdw_defaults,
+ .num_reg_defaults = ARRAY_SIZE(msm_sdw_defaults),
+ .max_register = MSM_SDW_MAX_REGISTER,
+ .volatile_reg = msm_sdw_is_volatile_register,
+ .readable_reg = msm_sdw_is_readable_register,
+};
diff --git a/sound/soc/codecs/msm8x16/Kconfig b/sound/soc/codecs/sdm660_cdc/Kconfig
similarity index 61%
rename from sound/soc/codecs/msm8x16/Kconfig
rename to sound/soc/codecs/sdm660_cdc/Kconfig
index d225b7a..d370da3 100644
--- a/sound/soc/codecs/msm8x16/Kconfig
+++ b/sound/soc/codecs/sdm660_cdc/Kconfig
@@ -1,3 +1,3 @@
-config SND_SOC_MSM8X16_WCD
+config SND_SOC_SDM660_CDC
tristate "MSM Internal PMIC based codec"
diff --git a/sound/soc/codecs/sdm660_cdc/Makefile b/sound/soc/codecs/sdm660_cdc/Makefile
new file mode 100644
index 0000000..d846fae
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/Makefile
@@ -0,0 +1,2 @@
+snd-soc-sdm660-cdc-objs := msm-analog-cdc.o msm-digital-cdc.o sdm660-regmap.o
+obj-$(CONFIG_SND_SOC_SDM660_CDC) += snd-soc-sdm660-cdc.o sdm660-cdc-irq.o
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
new file mode 100644
index 0000000..3da57df
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -0,0 +1,4651 @@
+/* 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/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <sound/q6afe-v2.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/q6core.h>
+#include "msm-analog-cdc.h"
+#include "sdm660-cdc-irq.h"
+#include "sdm660-cdc-registers.h"
+#include "msm-cdc-common.h"
+#include "../../msm/sdm660-common.h"
+#include "../wcd-mbhc-v2.h"
+
+#define DRV_NAME "pmic_analog_codec"
+#define SDM660_CDC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
+#define SDM660_CDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+#define MSM_DIG_CDC_STRING_LEN 80
+#define MSM_ANLG_CDC_VERSION_ENTRY_SIZE 32
+
+#define CODEC_DT_MAX_PROP_SIZE 40
+#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
+#define BUS_DOWN 1
+
+/*
+ *50 Milliseconds sufficient for DSP bring up in the modem
+ * after Sub System Restart
+ */
+#define ADSP_STATE_READY_TIMEOUT_MS 50
+
+enum {
+ BOOST_SWITCH = 0,
+ BOOST_ALWAYS,
+ BYPASS_ALWAYS,
+ BOOST_ON_FOREVER,
+};
+
+#define EAR_PMD 0
+#define EAR_PMU 1
+#define SPK_PMD 2
+#define SPK_PMU 3
+
+#define MICBIAS_DEFAULT_VAL 1800000
+#define MICBIAS_MIN_VAL 1600000
+#define MICBIAS_STEP_SIZE 50000
+
+#define DEFAULT_BOOST_VOLTAGE 5000
+#define MIN_BOOST_VOLTAGE 4000
+#define MAX_BOOST_VOLTAGE 5550
+#define BOOST_VOLTAGE_STEP 50
+
+#define SDM660_CDC_MBHC_BTN_COARSE_ADJ 100 /* in mV */
+#define SDM660_CDC_MBHC_BTN_FINE_ADJ 12 /* in mV */
+
+#define VOLTAGE_CONVERTER(value, min_value, step_size)\
+ ((value - min_value)/step_size)
+
+enum {
+ RX_MIX1_INP_SEL_ZERO = 0,
+ RX_MIX1_INP_SEL_IIR1,
+ RX_MIX1_INP_SEL_IIR2,
+ RX_MIX1_INP_SEL_RX1,
+ RX_MIX1_INP_SEL_RX2,
+ RX_MIX1_INP_SEL_RX3,
+};
+
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[];
+/* By default enable the internal speaker boost */
+static bool spkr_boost_en = true;
+static bool initial_boot = true;
+static bool is_ssr_en;
+
+static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
+ "cdc-vdd-mic-bias",
+};
+
+static struct wcd_mbhc_register
+ wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x18, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0xC0, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x06, 1, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
+ MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0xF0, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
+ MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0x0C, 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
+ MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL, 0x03, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
+ MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x01,
+ 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
+ MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x02,
+ 1, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
+ MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x08,
+ 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
+ MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x04,
+ 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
+ MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
+ MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT, 0xFF, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x70, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
+ MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0xFF,
+ 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
+ MSM89XX_PMIC_ANALOG_MICB_2_EN, 0xC0, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
+ MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFC, 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
+ MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
+ MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
+ MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x30, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
+ MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT,
+ 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
+ MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", 0, 0, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", 0, 0, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", 0, 0, 0, 0),
+};
+
+/* Multiply gain_adj and offset by 1000 and 100 to avoid float arithmetic */
+static const struct wcd_imped_i_ref imped_i_ref[] = {
+ {I_h4_UA, 8, 800, 9000, 10000},
+ {I_pt5_UA, 10, 100, 990, 4600},
+ {I_14_UA, 17, 14, 1050, 700},
+ {I_l4_UA, 10, 4, 1165, 110},
+ {I_1_UA, 0, 1, 1200, 65},
+};
+
+static const struct wcd_mbhc_intr intr_ids = {
+ .mbhc_sw_intr = MSM89XX_IRQ_MBHC_HS_DET,
+ .mbhc_btn_press_intr = MSM89XX_IRQ_MBHC_PRESS,
+ .mbhc_btn_release_intr = MSM89XX_IRQ_MBHC_RELEASE,
+ .mbhc_hs_ins_intr = MSM89XX_IRQ_MBHC_INSREM_DET1,
+ .mbhc_hs_rem_intr = MSM89XX_IRQ_MBHC_INSREM_DET,
+ .hph_left_ocp = MSM89XX_IRQ_HPHL_OCP,
+ .hph_right_ocp = MSM89XX_IRQ_HPHR_OCP,
+};
+
+static int msm_anlg_cdc_dt_parse_vreg_info(struct device *dev,
+ struct sdm660_cdc_regulator *vreg,
+ const char *vreg_name,
+ bool ondemand);
+static struct sdm660_cdc_pdata *msm_anlg_cdc_populate_dt_pdata(
+ struct device *dev);
+static int msm_anlg_cdc_enable_ext_mb_source(struct wcd_mbhc *wcd_mbhc,
+ bool turn_on);
+static void msm_anlg_cdc_trim_btn_reg(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_micb_v(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_boost_v(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_auto_zeroing(struct snd_soc_codec *codec,
+ bool enable);
+static void msm_anlg_cdc_configure_cap(struct snd_soc_codec *codec,
+ bool micbias1, bool micbias2);
+static bool msm_anlg_cdc_use_mb(struct snd_soc_codec *codec);
+
+static int get_codec_version(struct sdm660_cdc_priv *sdm660_cdc)
+{
+ if (sdm660_cdc->codec_version == DRAX_CDC)
+ return DRAX_CDC;
+ else if (sdm660_cdc->codec_version == DIANGU)
+ return DIANGU;
+ else if (sdm660_cdc->codec_version == CAJON_2_0)
+ return CAJON_2_0;
+ else if (sdm660_cdc->codec_version == CAJON)
+ return CAJON;
+ else if (sdm660_cdc->codec_version == CONGA)
+ return CONGA;
+ else if (sdm660_cdc->pmic_rev == TOMBAK_2_0)
+ return TOMBAK_2_0;
+ else if (sdm660_cdc->pmic_rev == TOMBAK_1_0)
+ return TOMBAK_1_0;
+
+ pr_err("%s: unsupported codec version\n", __func__);
+ return UNSUPPORTED;
+}
+
+static void wcd_mbhc_meas_imped(struct snd_soc_codec *codec,
+ s16 *impedance_l, s16 *impedance_r)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if ((sdm660_cdc->imped_det_pin == WCD_MBHC_DET_BOTH) ||
+ (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL)) {
+ /* Enable ZDET_L_MEAS_EN */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x08, 0x08);
+ /* Wait for 2ms for measurement to complete */
+ usleep_range(2000, 2100);
+ /* Read Left impedance value from Result1 */
+ *impedance_l = snd_soc_read(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+ /* Enable ZDET_R_MEAS_EN */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x08, 0x00);
+ }
+ if ((sdm660_cdc->imped_det_pin == WCD_MBHC_DET_BOTH) ||
+ (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x04, 0x04);
+ /* Wait for 2ms for measurement to complete */
+ usleep_range(2000, 2100);
+ /* Read Right impedance value from Result1 */
+ *impedance_r = snd_soc_read(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x04, 0x00);
+ }
+}
+
+static void msm_anlg_cdc_set_ref_current(struct snd_soc_codec *codec,
+ enum wcd_curr_ref curr_ref)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: curr_ref: %d\n", __func__, curr_ref);
+
+ if (get_codec_version(sdm660_cdc) < CAJON)
+ dev_dbg(codec->dev, "%s: Setting ref current not required\n",
+ __func__);
+
+ sdm660_cdc->imped_i_ref = imped_i_ref[curr_ref];
+
+ switch (curr_ref) {
+ case I_h4_UA:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN,
+ 0x07, 0x01);
+ break;
+ case I_pt5_UA:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN,
+ 0x07, 0x04);
+ break;
+ case I_14_UA:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN,
+ 0x07, 0x03);
+ break;
+ case I_l4_UA:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN,
+ 0x07, 0x01);
+ break;
+ case I_1_UA:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN,
+ 0x07, 0x00);
+ break;
+ default:
+ pr_debug("%s: No ref current set\n", __func__);
+ break;
+ }
+}
+
+static bool msm_anlg_cdc_adj_ref_current(struct snd_soc_codec *codec,
+ s16 *impedance_l, s16 *impedance_r)
+{
+ int i = 2;
+ s16 compare_imp = 0;
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)
+ compare_imp = *impedance_r;
+ else
+ compare_imp = *impedance_l;
+
+ if (get_codec_version(sdm660_cdc) < CAJON) {
+ dev_dbg(codec->dev,
+ "%s: Reference current adjustment not required\n",
+ __func__);
+ return false;
+ }
+
+ while (compare_imp < imped_i_ref[i].min_val) {
+ msm_anlg_cdc_set_ref_current(codec, imped_i_ref[++i].curr_ref);
+ wcd_mbhc_meas_imped(codec, impedance_l, impedance_r);
+ compare_imp = (sdm660_cdc->imped_det_pin ==
+ WCD_MBHC_DET_HPHR) ? *impedance_r : *impedance_l;
+ if (i >= I_1_UA)
+ break;
+ }
+ return true;
+}
+
+void msm_anlg_cdc_spk_ext_pa_cb(
+ int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
+ int enable), struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc;
+
+ if (!codec) {
+ pr_err("%s: NULL codec pointer!\n", __func__);
+ return;
+ }
+
+ sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: Enter\n", __func__);
+ sdm660_cdc->codec_spk_ext_pa_cb = codec_spk_ext_pa;
+}
+
+static void msm_anlg_cdc_compute_impedance(struct snd_soc_codec *codec, s16 l,
+ s16 r, uint32_t *zl, uint32_t *zr,
+ bool high)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+ uint32_t rl = 0, rr = 0;
+ struct wcd_imped_i_ref R = sdm660_cdc->imped_i_ref;
+ int codec_ver = get_codec_version(sdm660_cdc);
+
+ switch (codec_ver) {
+ case TOMBAK_1_0:
+ case TOMBAK_2_0:
+ case CONGA:
+ if (high) {
+ dev_dbg(codec->dev,
+ "%s: This plug has high range impedance\n",
+ __func__);
+ rl = (uint32_t)(((100 * (l * 400 - 200))/96) - 230);
+ rr = (uint32_t)(((100 * (r * 400 - 200))/96) - 230);
+ } else {
+ dev_dbg(codec->dev,
+ "%s: This plug has low range impedance\n",
+ __func__);
+ rl = (uint32_t)(((1000 * (l * 2 - 1))/1165) - (13/10));
+ rr = (uint32_t)(((1000 * (r * 2 - 1))/1165) - (13/10));
+ }
+ break;
+ case CAJON:
+ case CAJON_2_0:
+ case DIANGU:
+ case DRAX_CDC:
+ if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL) {
+ rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
+ (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+ rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
+ - R.offset * R.gain_adj)/(R.gain_adj * 100));
+ } else if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR) {
+ rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
+ - R.offset * R.gain_adj)/(R.gain_adj * 100));
+ rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
+ (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+ } else if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_NONE) {
+ rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
+ (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+ rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
+ (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+ } else {
+ rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
+ - R.offset * R.gain_adj)/(R.gain_adj * 100));
+ rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
+ - R.offset * R.gain_adj)/(R.gain_adj * 100));
+ }
+ break;
+ default:
+ dev_dbg(codec->dev, "%s: No codec mentioned\n", __func__);
+ break;
+ }
+ *zl = rl;
+ *zr = rr;
+}
+
+static struct firmware_cal *msm_anlg_cdc_get_hwdep_fw_cal(
+ struct wcd_mbhc *wcd_mbhc,
+ enum wcd_cal_type type)
+{
+ struct sdm660_cdc_priv *sdm660_cdc;
+ struct firmware_cal *hwdep_cal;
+ struct snd_soc_codec *codec = wcd_mbhc->codec;
+
+ if (!codec) {
+ pr_err("%s: NULL codec pointer\n", __func__);
+ return NULL;
+ }
+ sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+ hwdep_cal = wcdcal_get_fw_cal(sdm660_cdc->fw_data, type);
+ if (!hwdep_cal) {
+ dev_err(codec->dev, "%s: cal not sent by %d\n",
+ __func__, type);
+ return NULL;
+ }
+ return hwdep_cal;
+}
+
+static void wcd9xxx_spmi_irq_control(struct snd_soc_codec *codec,
+ int irq, bool enable)
+{
+ if (enable)
+ wcd9xxx_spmi_enable_irq(irq);
+ else
+ wcd9xxx_spmi_disable_irq(irq);
+}
+
+static void msm_anlg_cdc_mbhc_clk_setup(struct snd_soc_codec *codec,
+ bool enable)
+{
+ if (enable)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x08, 0x08);
+ else
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x08, 0x00);
+}
+
+static int msm_anlg_cdc_mbhc_map_btn_code_to_num(struct snd_soc_codec *codec)
+{
+ int btn_code;
+ int btn;
+
+ btn_code = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+
+ switch (btn_code) {
+ case 0:
+ btn = 0;
+ break;
+ case 1:
+ btn = 1;
+ break;
+ case 3:
+ btn = 2;
+ break;
+ case 7:
+ btn = 3;
+ break;
+ case 15:
+ btn = 4;
+ break;
+ default:
+ btn = -EINVAL;
+ break;
+ };
+
+ return btn;
+}
+
+static bool msm_anlg_cdc_spmi_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
+{
+ if (lock)
+ return wcd9xxx_spmi_lock_sleep();
+ wcd9xxx_spmi_unlock_sleep();
+ return 0;
+}
+
+static bool msm_anlg_cdc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
+{
+ if (micb_num == MIC_BIAS_1)
+ return (snd_soc_read(mbhc->codec,
+ MSM89XX_PMIC_ANALOG_MICB_1_EN) &
+ 0x80);
+ if (micb_num == MIC_BIAS_2)
+ return (snd_soc_read(mbhc->codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN) &
+ 0x80);
+ return false;
+}
+
+static void msm_anlg_cdc_enable_master_bias(struct snd_soc_codec *codec,
+ bool enable)
+{
+ if (enable)
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
+ 0x30, 0x30);
+ else
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
+ 0x30, 0x00);
+}
+
+static void msm_anlg_cdc_mbhc_common_micb_ctrl(struct snd_soc_codec *codec,
+ int event, bool enable)
+{
+ u16 reg;
+ u8 mask;
+ u8 val;
+
+ switch (event) {
+ case MBHC_COMMON_MICB_PRECHARGE:
+ reg = MSM89XX_PMIC_ANALOG_MICB_1_CTL;
+ mask = 0x60;
+ val = (enable ? 0x60 : 0x00);
+ break;
+ case MBHC_COMMON_MICB_SET_VAL:
+ reg = MSM89XX_PMIC_ANALOG_MICB_1_VAL;
+ mask = 0xFF;
+ val = (enable ? 0xC0 : 0x00);
+ break;
+ case MBHC_COMMON_MICB_TAIL_CURR:
+ reg = MSM89XX_PMIC_ANALOG_MICB_1_EN;
+ mask = 0x04;
+ val = (enable ? 0x04 : 0x00);
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: Invalid event received\n", __func__);
+ return;
+ };
+ snd_soc_update_bits(codec, reg, mask, val);
+}
+
+static void msm_anlg_cdc_mbhc_internal_micbias_ctrl(struct snd_soc_codec *codec,
+ int micbias_num,
+ bool enable)
+{
+ if (micbias_num == 1) {
+ if (enable)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
+ 0x10, 0x10);
+ else
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
+ 0x10, 0x00);
+ }
+}
+
+static bool msm_anlg_cdc_mbhc_hph_pa_on_status(struct snd_soc_codec *codec)
+{
+ return (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN) &
+ 0x30) ? true : false;
+}
+
+static void msm_anlg_cdc_mbhc_program_btn_thr(struct snd_soc_codec *codec,
+ s16 *btn_low, s16 *btn_high,
+ int num_btn, bool is_micbias)
+{
+ int i;
+ u32 course, fine, reg_val;
+ u16 reg_addr = MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL;
+ s16 *btn_voltage;
+
+ btn_voltage = ((is_micbias) ? btn_high : btn_low);
+
+ for (i = 0; i < num_btn; i++) {
+ course = (btn_voltage[i] / SDM660_CDC_MBHC_BTN_COARSE_ADJ);
+ fine = ((btn_voltage[i] % SDM660_CDC_MBHC_BTN_COARSE_ADJ) /
+ SDM660_CDC_MBHC_BTN_FINE_ADJ);
+
+ reg_val = (course << 5) | (fine << 2);
+ snd_soc_update_bits(codec, reg_addr, 0xFC, reg_val);
+ dev_dbg(codec->dev,
+ "%s: course: %d fine: %d reg_addr: %x reg_val: %x\n",
+ __func__, course, fine, reg_addr, reg_val);
+ reg_addr++;
+ }
+}
+
+static void msm_anlg_cdc_mbhc_calc_impedance(struct wcd_mbhc *mbhc,
+ uint32_t *zl, uint32_t *zr)
+{
+ struct snd_soc_codec *codec = mbhc->codec;
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+ s16 impedance_l, impedance_r;
+ s16 impedance_l_fixed;
+ s16 reg0, reg1, reg2, reg3, reg4;
+ bool high = false;
+ bool min_range_used = false;
+
+ WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+ reg0 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER);
+ reg1 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL);
+ reg2 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2);
+ reg3 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN);
+ reg4 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL);
+
+ sdm660_cdc->imped_det_pin = WCD_MBHC_DET_BOTH;
+ mbhc->hph_type = WCD_MBHC_HPH_NONE;
+
+ /* disable FSM and micbias and enable pullup*/
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x80, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN,
+ 0xA5, 0x25);
+ /*
+ * Enable legacy electrical detection current sources
+ * and disable fast ramp and enable manual switching
+ * of extra capacitance
+ */
+ dev_dbg(codec->dev, "%s: Setup for impedance det\n", __func__);
+
+ msm_anlg_cdc_set_ref_current(codec, I_h4_UA);
+
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
+ 0x06, 0x02);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER,
+ 0x02, 0x02);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL,
+ 0x02, 0x00);
+
+ dev_dbg(codec->dev, "%s: Start performing impedance detection\n",
+ __func__);
+
+ wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
+
+ if (impedance_l > 2 || impedance_r > 2) {
+ high = true;
+ if (!mbhc->mbhc_cfg->mono_stero_detection) {
+ /* Set ZDET_CHG to 0 to discharge ramp */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x02, 0x00);
+ /* wait 40ms for the discharge ramp to complete */
+ usleep_range(40000, 40100);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+ 0x03, 0x00);
+ sdm660_cdc->imped_det_pin = (impedance_l > 2 &&
+ impedance_r > 2) ?
+ WCD_MBHC_DET_NONE :
+ ((impedance_l > 2) ?
+ WCD_MBHC_DET_HPHR :
+ WCD_MBHC_DET_HPHL);
+ if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_NONE)
+ goto exit;
+ } else {
+ if (get_codec_version(sdm660_cdc) >= CAJON) {
+ if (impedance_l == 63 && impedance_r == 63) {
+ dev_dbg(codec->dev,
+ "%s: HPHL and HPHR are floating\n",
+ __func__);
+ sdm660_cdc->imped_det_pin =
+ WCD_MBHC_DET_NONE;
+ mbhc->hph_type = WCD_MBHC_HPH_NONE;
+ } else if (impedance_l == 63
+ && impedance_r < 63) {
+ dev_dbg(codec->dev,
+ "%s: Mono HS with HPHL floating\n",
+ __func__);
+ sdm660_cdc->imped_det_pin =
+ WCD_MBHC_DET_HPHR;
+ mbhc->hph_type = WCD_MBHC_HPH_MONO;
+ } else if (impedance_r == 63 &&
+ impedance_l < 63) {
+ dev_dbg(codec->dev,
+ "%s: Mono HS with HPHR floating\n",
+ __func__);
+ sdm660_cdc->imped_det_pin =
+ WCD_MBHC_DET_HPHL;
+ mbhc->hph_type = WCD_MBHC_HPH_MONO;
+ } else if (impedance_l > 3 && impedance_r > 3 &&
+ (impedance_l == impedance_r)) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
+ 0x06, 0x06);
+ wcd_mbhc_meas_imped(codec, &impedance_l,
+ &impedance_r);
+ if (impedance_r == impedance_l)
+ dev_dbg(codec->dev,
+ "%s: Mono Headset\n",
+ __func__);
+ sdm660_cdc->imped_det_pin =
+ WCD_MBHC_DET_NONE;
+ mbhc->hph_type =
+ WCD_MBHC_HPH_MONO;
+ } else {
+ dev_dbg(codec->dev,
+ "%s: STEREO headset is found\n",
+ __func__);
+ sdm660_cdc->imped_det_pin =
+ WCD_MBHC_DET_BOTH;
+ mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+ }
+ }
+ }
+ }
+
+ msm_anlg_cdc_set_ref_current(codec, I_pt5_UA);
+ msm_anlg_cdc_set_ref_current(codec, I_14_UA);
+
+ /* Enable RAMP_L , RAMP_R & ZDET_CHG*/
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+ 0x03, 0x03);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x02, 0x02);
+ /* wait for 50msec for the HW to apply ramp on HPHL and HPHR */
+ usleep_range(50000, 50100);
+ /* Enable ZDET_DISCHG_CAP_CTL to add extra capacitance */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x01, 0x01);
+ /* wait for 5msec for the voltage to get stable */
+ usleep_range(5000, 5100);
+
+ wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
+
+ min_range_used = msm_anlg_cdc_adj_ref_current(codec,
+ &impedance_l, &impedance_r);
+ if (!mbhc->mbhc_cfg->mono_stero_detection) {
+ /* Set ZDET_CHG to 0 to discharge ramp */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x02, 0x00);
+ /* wait for 40msec for the capacitor to discharge */
+ usleep_range(40000, 40100);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+ 0x03, 0x00);
+ goto exit;
+ }
+
+ /* we are setting ref current to the minimun range or the measured
+ * value larger than the minimum value, so min_range_used is true.
+ * If the headset is mono headset with either HPHL or HPHR floating
+ * then we have already done the mono stereo detection and do not
+ * need to continue further.
+ */
+
+ if (!min_range_used ||
+ sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL ||
+ sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)
+ goto exit;
+
+
+ /* Disable Set ZDET_CONN_RAMP_L and enable ZDET_CONN_FIXED_L */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+ 0x02, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
+ 0x02, 0x02);
+ /* Set ZDET_CHG to 0 */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x02, 0x00);
+ /* wait for 40msec for the capacitor to discharge */
+ usleep_range(40000, 40100);
+
+ /* Set ZDET_CONN_RAMP_R to 0 */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+ 0x01, 0x00);
+ /* Enable ZDET_L_MEAS_EN */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x08, 0x08);
+ /* wait for 2msec for the HW to compute left inpedance value */
+ usleep_range(2000, 2100);
+ /* Read Left impedance value from Result1 */
+ impedance_l_fixed = snd_soc_read(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+ /* Disable ZDET_L_MEAS_EN */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x08, 0x00);
+ /*
+ * Assume impedance_l is L1, impedance_l_fixed is L2.
+ * If the following condition is met, we can take this
+ * headset as mono one with impedance of L2.
+ * Otherwise, take it as stereo with impedance of L1.
+ * Condition:
+ * abs[(L2-0.5L1)/(L2+0.5L1)] < abs [(L2-L1)/(L2+L1)]
+ */
+ if ((abs(impedance_l_fixed - impedance_l/2) *
+ (impedance_l_fixed + impedance_l)) >=
+ (abs(impedance_l_fixed - impedance_l) *
+ (impedance_l_fixed + impedance_l/2))) {
+ dev_dbg(codec->dev,
+ "%s: STEREO plug type detected\n",
+ __func__);
+ mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+ } else {
+ dev_dbg(codec->dev,
+ "%s: MONO plug type detected\n",
+ __func__);
+ mbhc->hph_type = WCD_MBHC_HPH_MONO;
+ impedance_l = impedance_l_fixed;
+ }
+ /* Enable ZDET_CHG */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x02, 0x02);
+ /* wait for 10msec for the capacitor to charge */
+ usleep_range(10000, 10100);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+ 0x02, 0x02);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
+ 0x02, 0x00);
+ /* Set ZDET_CHG to 0 to discharge HPHL */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+ 0x02, 0x00);
+ /* wait for 40msec for the capacitor to discharge */
+ usleep_range(40000, 40100);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+ 0x02, 0x00);
+
+exit:
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, reg4);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN, reg3);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, reg1);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, reg0);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, reg2);
+ msm_anlg_cdc_compute_impedance(codec, impedance_l, impedance_r,
+ zl, zr, high);
+
+ dev_dbg(codec->dev, "%s: RL %d ohm, RR %d ohm\n", __func__, *zl, *zr);
+ dev_dbg(codec->dev, "%s: Impedance detection completed\n", __func__);
+}
+
+static int msm_anlg_cdc_dig_register_notifier(void *handle,
+ struct notifier_block *nblock,
+ bool enable)
+{
+ struct sdm660_cdc *handle_cdc = handle;
+
+ if (enable)
+ return blocking_notifier_chain_register(&handle_cdc->notifier,
+ nblock);
+ return blocking_notifier_chain_unregister(&handle_cdc->notifier,
+ nblock);
+}
+
+static int msm_anlg_cdc_mbhc_register_notifier(struct wcd_mbhc *wcd_mbhc,
+ struct notifier_block *nblock,
+ bool enable)
+{
+ struct snd_soc_codec *codec = wcd_mbhc->codec;
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (enable)
+ return blocking_notifier_chain_register(
+ &sdm660_cdc->notifier,
+ nblock);
+
+ return blocking_notifier_chain_unregister(&sdm660_cdc->notifier,
+ nblock);
+}
+
+static int msm_anlg_cdc_request_irq(struct snd_soc_codec *codec,
+ int irq, irq_handler_t handler,
+ const char *name, void *data)
+{
+ return wcd9xxx_spmi_request_irq(irq, handler, name, data);
+}
+
+static int msm_anlg_cdc_free_irq(struct snd_soc_codec *codec,
+ int irq, void *data)
+{
+ return wcd9xxx_spmi_free_irq(irq, data);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+ .enable_mb_source = msm_anlg_cdc_enable_ext_mb_source,
+ .trim_btn_reg = msm_anlg_cdc_trim_btn_reg,
+ .compute_impedance = msm_anlg_cdc_mbhc_calc_impedance,
+ .set_micbias_value = msm_anlg_cdc_set_micb_v,
+ .set_auto_zeroing = msm_anlg_cdc_set_auto_zeroing,
+ .get_hwdep_fw_cal = msm_anlg_cdc_get_hwdep_fw_cal,
+ .set_cap_mode = msm_anlg_cdc_configure_cap,
+ .register_notifier = msm_anlg_cdc_mbhc_register_notifier,
+ .request_irq = msm_anlg_cdc_request_irq,
+ .irq_control = wcd9xxx_spmi_irq_control,
+ .free_irq = msm_anlg_cdc_free_irq,
+ .clk_setup = msm_anlg_cdc_mbhc_clk_setup,
+ .map_btn_code_to_num = msm_anlg_cdc_mbhc_map_btn_code_to_num,
+ .lock_sleep = msm_anlg_cdc_spmi_lock_sleep,
+ .micbias_enable_status = msm_anlg_cdc_micb_en_status,
+ .mbhc_bias = msm_anlg_cdc_enable_master_bias,
+ .mbhc_common_micb_ctrl = msm_anlg_cdc_mbhc_common_micb_ctrl,
+ .micb_internal = msm_anlg_cdc_mbhc_internal_micbias_ctrl,
+ .hph_pa_on_status = msm_anlg_cdc_mbhc_hph_pa_on_status,
+ .set_btn_thr = msm_anlg_cdc_mbhc_program_btn_thr,
+ .extn_use_mb = msm_anlg_cdc_use_mb,
+};
+
+static const uint32_t wcd_imped_val[] = {4, 8, 12, 13, 16,
+ 20, 24, 28, 32,
+ 36, 40, 44, 48};
+
+static void msm_anlg_cdc_dig_notifier_call(struct snd_soc_codec *codec,
+ const enum dig_cdc_notify_event event)
+{
+ struct sdm660_cdc *sdm660_cdc = codec->control_data;
+
+ pr_debug("%s: notifier call event %d\n", __func__, event);
+ blocking_notifier_call_chain(&sdm660_cdc->notifier,
+ event, NULL);
+}
+
+static void msm_anlg_cdc_notifier_call(struct snd_soc_codec *codec,
+ const enum wcd_notify_event event)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: notifier call event %d\n", __func__, event);
+ blocking_notifier_call_chain(&sdm660_cdc->notifier, event,
+ &sdm660_cdc->mbhc);
+}
+
+static void msm_anlg_cdc_boost_on(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F, 0x0F);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
+ if (get_codec_version(sdm660_cdc) < CAJON_2_0)
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82);
+ else
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+ 0x69, 0x69);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO,
+ 0x88, 0x88);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+ 0x03, 0x03);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL,
+ 0xE1, 0xE1);
+ if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+ snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x20, 0x20);
+ /* Wait for 1ms after clock ctl enable */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+ 0xDF, 0xDF);
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ } else {
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+ 0x40, 0x00);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x20, 0x20);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+ 0x80, 0x80);
+ /* Wait for 500us after BOOST_EN to happen */
+ usleep_range(500, 510);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+ 0x40, 0x40);
+ /* Wait for 500us after BOOST pulse_skip */
+ usleep_range(500, 510);
+ }
+}
+
+static void msm_anlg_cdc_boost_off(struct snd_soc_codec *codec)
+{
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+ 0xDF, 0x5F);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x20, 0x00);
+}
+
+static void msm_anlg_cdc_bypass_on(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+ 0xA5);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3,
+ 0x07);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x02, 0x02);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x01, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x40, 0x40);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x80, 0x80);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+ 0xDF, 0xDF);
+ } else {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x20, 0x20);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x20, 0x20);
+ }
+}
+
+static void msm_anlg_cdc_bypass_off(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+ 0x80, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x80, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x02, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x40, 0x00);
+ } else {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+ 0x20, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x20, 0x00);
+ }
+}
+
+static void msm_anlg_cdc_boost_mode_sequence(struct snd_soc_codec *codec,
+ int flag)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (flag == EAR_PMU) {
+ switch (sdm660_cdc->boost_option) {
+ case BOOST_SWITCH:
+ if (sdm660_cdc->ear_pa_boost_set) {
+ msm_anlg_cdc_boost_off(codec);
+ msm_anlg_cdc_bypass_on(codec);
+ }
+ break;
+ case BOOST_ALWAYS:
+ msm_anlg_cdc_boost_on(codec);
+ break;
+ case BYPASS_ALWAYS:
+ msm_anlg_cdc_bypass_on(codec);
+ break;
+ case BOOST_ON_FOREVER:
+ msm_anlg_cdc_boost_on(codec);
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: invalid boost option: %d\n", __func__,
+ sdm660_cdc->boost_option);
+ break;
+ }
+ } else if (flag == EAR_PMD) {
+ switch (sdm660_cdc->boost_option) {
+ case BOOST_SWITCH:
+ if (sdm660_cdc->ear_pa_boost_set)
+ msm_anlg_cdc_bypass_off(codec);
+ break;
+ case BOOST_ALWAYS:
+ msm_anlg_cdc_boost_off(codec);
+ /* 80ms for EAR boost to settle down */
+ msleep(80);
+ break;
+ case BYPASS_ALWAYS:
+ /* nothing to do as bypass on always */
+ break;
+ case BOOST_ON_FOREVER:
+ /* nothing to do as boost on forever */
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: invalid boost option: %d\n", __func__,
+ sdm660_cdc->boost_option);
+ break;
+ }
+ } else if (flag == SPK_PMU) {
+ switch (sdm660_cdc->boost_option) {
+ case BOOST_SWITCH:
+ if (sdm660_cdc->spk_boost_set) {
+ msm_anlg_cdc_bypass_off(codec);
+ msm_anlg_cdc_boost_on(codec);
+ }
+ break;
+ case BOOST_ALWAYS:
+ msm_anlg_cdc_boost_on(codec);
+ break;
+ case BYPASS_ALWAYS:
+ msm_anlg_cdc_bypass_on(codec);
+ break;
+ case BOOST_ON_FOREVER:
+ msm_anlg_cdc_boost_on(codec);
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: invalid boost option: %d\n", __func__,
+ sdm660_cdc->boost_option);
+ break;
+ }
+ } else if (flag == SPK_PMD) {
+ switch (sdm660_cdc->boost_option) {
+ case BOOST_SWITCH:
+ if (sdm660_cdc->spk_boost_set) {
+ msm_anlg_cdc_boost_off(codec);
+ /*
+ * Add 40 ms sleep for the spk
+ * boost to settle down
+ */
+ msleep(40);
+ }
+ break;
+ case BOOST_ALWAYS:
+ msm_anlg_cdc_boost_off(codec);
+ /*
+ * Add 40 ms sleep for the spk
+ * boost to settle down
+ */
+ msleep(40);
+ break;
+ case BYPASS_ALWAYS:
+ /* nothing to do as bypass on always */
+ break;
+ case BOOST_ON_FOREVER:
+ /* nothing to do as boost on forever */
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: invalid boost option: %d\n", __func__,
+ sdm660_cdc->boost_option);
+ break;
+ }
+ }
+}
+
+static int msm_anlg_cdc_dt_parse_vreg_info(struct device *dev,
+ struct sdm660_cdc_regulator *vreg, const char *vreg_name,
+ bool ondemand)
+{
+ int len, ret = 0;
+ const __be32 *prop;
+ char prop_name[CODEC_DT_MAX_PROP_SIZE];
+ struct device_node *regnode = NULL;
+ u32 prop_val;
+
+ snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
+ vreg_name);
+ regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+ if (!regnode) {
+ dev_err(dev, "Looking up %s property in node %s failed\n",
+ prop_name, dev->of_node->full_name);
+ return -ENODEV;
+ }
+
+ dev_dbg(dev, "Looking up %s property in node %s\n",
+ prop_name, dev->of_node->full_name);
+
+ vreg->name = vreg_name;
+ vreg->ondemand = ondemand;
+
+ snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+ "qcom,%s-voltage", vreg_name);
+ prop = of_get_property(dev->of_node, prop_name, &len);
+
+ if (!prop || (len != (2 * sizeof(__be32)))) {
+ dev_err(dev, "%s %s property\n",
+ prop ? "invalid format" : "no", prop_name);
+ return -EINVAL;
+ }
+ vreg->min_uv = be32_to_cpup(&prop[0]);
+ vreg->max_uv = be32_to_cpup(&prop[1]);
+
+ snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+ "qcom,%s-current", vreg_name);
+
+ ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+ if (ret) {
+ dev_err(dev, "Looking up %s property in node %s failed",
+ prop_name, dev->of_node->full_name);
+ return -EFAULT;
+ }
+ vreg->optimum_ua = prop_val;
+
+ dev_dbg(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
+ vreg->min_uv, vreg->max_uv, vreg->optimum_ua, vreg->ondemand);
+ return 0;
+}
+
+static void msm_anlg_cdc_dt_parse_boost_info(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ snd_soc_codec_get_drvdata(codec);
+ const char *prop_name = "qcom,cdc-boost-voltage";
+ int boost_voltage, ret;
+
+ ret = of_property_read_u32(codec->dev->of_node, prop_name,
+ &boost_voltage);
+ if (ret) {
+ dev_dbg(codec->dev, "Looking up %s property in node %s failed\n",
+ prop_name, codec->dev->of_node->full_name);
+ boost_voltage = DEFAULT_BOOST_VOLTAGE;
+ }
+ if (boost_voltage < MIN_BOOST_VOLTAGE ||
+ boost_voltage > MAX_BOOST_VOLTAGE) {
+ dev_err(codec->dev,
+ "Incorrect boost voltage. Reverting to default\n");
+ boost_voltage = DEFAULT_BOOST_VOLTAGE;
+ }
+
+ sdm660_cdc_priv->boost_voltage =
+ VOLTAGE_CONVERTER(boost_voltage, MIN_BOOST_VOLTAGE,
+ BOOST_VOLTAGE_STEP);
+ dev_dbg(codec->dev, "Boost voltage value is: %d\n",
+ boost_voltage);
+}
+
+static void msm_anlg_cdc_dt_parse_micbias_info(struct device *dev,
+ struct wcd_micbias_setting *micbias)
+{
+ const char *prop_name = "qcom,cdc-micbias-cfilt-mv";
+ int ret;
+
+ ret = of_property_read_u32(dev->of_node, prop_name,
+ &micbias->cfilt1_mv);
+ if (ret) {
+ dev_dbg(dev, "Looking up %s property in node %s failed",
+ prop_name, dev->of_node->full_name);
+ micbias->cfilt1_mv = MICBIAS_DEFAULT_VAL;
+ }
+}
+
+static struct sdm660_cdc_pdata *msm_anlg_cdc_populate_dt_pdata(
+ struct device *dev)
+{
+ struct sdm660_cdc_pdata *pdata;
+ int ret, static_cnt, ond_cnt, idx, i;
+ const char *name = NULL;
+ const char *static_prop_name = "qcom,cdc-static-supplies";
+ const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
+ if (static_cnt < 0) {
+ dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
+ static_cnt);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* On-demand supply list is an optional property */
+ ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
+ if (ond_cnt < 0)
+ ond_cnt = 0;
+
+ WARN_ON(static_cnt <= 0 || ond_cnt < 0);
+ if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
+ dev_err(dev, "%s: Num of supplies %u > max supported %zd\n",
+ __func__, (static_cnt + ond_cnt),
+ ARRAY_SIZE(pdata->regulator));
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (idx = 0; idx < static_cnt; idx++) {
+ ret = of_property_read_string_index(dev->of_node,
+ static_prop_name, idx,
+ &name);
+ if (ret) {
+ dev_err(dev, "%s: of read string %s idx %d error %d\n",
+ __func__, static_prop_name, idx, ret);
+ goto err;
+ }
+
+ dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
+ name);
+ ret = msm_anlg_cdc_dt_parse_vreg_info(dev,
+ &pdata->regulator[idx],
+ name, false);
+ if (ret) {
+ dev_err(dev, "%s:err parsing vreg for %s idx %d\n",
+ __func__, name, idx);
+ goto err;
+ }
+ }
+
+ for (i = 0; i < ond_cnt; i++, idx++) {
+ ret = of_property_read_string_index(dev->of_node, ond_prop_name,
+ i, &name);
+ if (ret) {
+ dev_err(dev, "%s: err parsing on_demand for %s idx %d\n",
+ __func__, ond_prop_name, i);
+ goto err;
+ }
+
+ dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
+ name);
+ ret = msm_anlg_cdc_dt_parse_vreg_info(dev,
+ &pdata->regulator[idx],
+ name, true);
+ if (ret) {
+ dev_err(dev, "%s: err parsing vreg on_demand for %s idx %d\n",
+ __func__, name, idx);
+ goto err;
+ }
+ }
+ msm_anlg_cdc_dt_parse_micbias_info(dev, &pdata->micbias);
+
+ return pdata;
+err:
+ devm_kfree(dev, pdata);
+ dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
+ __func__, ret);
+ return NULL;
+}
+
+static int msm_anlg_cdc_codec_enable_on_demand_supply(
+ struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int ret = 0;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+ struct on_demand_supply *supply;
+
+ if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
+ dev_err(codec->dev, "%s: error index > MAX Demand supplies",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ dev_dbg(codec->dev, "%s: supply: %s event: %d ref: %d\n",
+ __func__, on_demand_supply_name[w->shift], event,
+ atomic_read(&sdm660_cdc->on_demand_list[w->shift].ref));
+
+ supply = &sdm660_cdc->on_demand_list[w->shift];
+ WARN_ONCE(!supply->supply, "%s isn't defined\n",
+ on_demand_supply_name[w->shift]);
+ if (!supply->supply) {
+ dev_err(codec->dev, "%s: err supply not present ond for %d",
+ __func__, w->shift);
+ goto out;
+ }
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (atomic_inc_return(&supply->ref) == 1)
+ ret = regulator_enable(supply->supply);
+ if (ret)
+ dev_err(codec->dev, "%s: Failed to enable %s\n",
+ __func__,
+ on_demand_supply_name[w->shift]);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (atomic_read(&supply->ref) == 0) {
+ dev_dbg(codec->dev, "%s: %s supply has been disabled.\n",
+ __func__, on_demand_supply_name[w->shift]);
+ goto out;
+ }
+ if (atomic_dec_return(&supply->ref) == 0)
+ ret = regulator_disable(supply->supply);
+ if (ret)
+ dev_err(codec->dev, "%s: Failed to disable %s\n",
+ __func__,
+ on_demand_supply_name[w->shift]);
+ break;
+ default:
+ break;
+ }
+out:
+ return ret;
+}
+
+static int msm_anlg_cdc_codec_enable_clock_block(struct snd_soc_codec *codec,
+ int enable)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ if (enable) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
+ msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
+ } else {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
+ msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_OFF);
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+ if (!(strcmp(w->name, "EAR CP"))) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x80, 0x80);
+ msm_anlg_cdc_boost_mode_sequence(codec, EAR_PMU);
+ } else if (get_codec_version(sdm660_cdc) >= DIANGU) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x80, 0x80);
+ } else {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0xC0, 0xC0);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* Wait for 1ms post powerup of chargepump */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* Wait for 1ms post powerdown of chargepump */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ if (!(strcmp(w->name, "EAR CP"))) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x80, 0x00);
+ if (sdm660_cdc->boost_option != BOOST_ALWAYS) {
+ dev_dbg(codec->dev,
+ "%s: boost_option:%d, tear down ear\n",
+ __func__, sdm660_cdc->boost_option);
+ msm_anlg_cdc_boost_mode_sequence(codec,
+ EAR_PMD);
+ }
+ /*
+ * Reset pa select bit from ear to hph after ear pa
+ * is disabled and HPH DAC disable to reduce ear
+ * turn off pop and avoid HPH pop in concurrency
+ */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x00);
+ } else {
+ if (get_codec_version(sdm660_cdc) < DIANGU)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x40, 0x00);
+ if (sdm660_cdc->rx_bias_count == 0)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x80, 0x00);
+ dev_dbg(codec->dev, "%s: rx_bias_count = %d\n",
+ __func__, sdm660_cdc->rx_bias_count);
+ }
+ break;
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_ear_pa_boost_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] =
+ (sdm660_cdc->ear_pa_boost_set ? 1 : 0);
+ dev_dbg(codec->dev, "%s: sdm660_cdc->ear_pa_boost_set = %d\n",
+ __func__, sdm660_cdc->ear_pa_boost_set);
+ return 0;
+}
+
+static int msm_anlg_cdc_ear_pa_boost_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+ sdm660_cdc->ear_pa_boost_set =
+ (ucontrol->value.integer.value[0] ? true : false);
+ return 0;
+}
+
+static int msm_anlg_cdc_loopback_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct msm_asoc_mach_data *pdata = NULL;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return pdata->lb_mode;
+}
+
+static int msm_anlg_cdc_loopback_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct msm_asoc_mach_data *pdata = NULL;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ pdata->lb_mode = false;
+ break;
+ case 1:
+ pdata->lb_mode = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_anlg_cdc_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (get_codec_version(sdm660_cdc) >= DIANGU) {
+ ear_pa_gain = snd_soc_read(codec,
+ MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC);
+ ear_pa_gain = (ear_pa_gain >> 1) & 0x3;
+
+ if (ear_pa_gain == 0x00) {
+ ucontrol->value.integer.value[0] = 3;
+ } else if (ear_pa_gain == 0x01) {
+ ucontrol->value.integer.value[1] = 2;
+ } else if (ear_pa_gain == 0x02) {
+ ucontrol->value.integer.value[2] = 1;
+ } else if (ear_pa_gain == 0x03) {
+ ucontrol->value.integer.value[3] = 0;
+ } else {
+ dev_err(codec->dev,
+ "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+ __func__, ear_pa_gain);
+ return -EINVAL;
+ }
+ } else {
+ ear_pa_gain = snd_soc_read(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL);
+ ear_pa_gain = (ear_pa_gain >> 5) & 0x1;
+ if (ear_pa_gain == 0x00) {
+ ucontrol->value.integer.value[0] = 0;
+ } else if (ear_pa_gain == 0x01) {
+ ucontrol->value.integer.value[0] = 3;
+ } else {
+ dev_err(codec->dev,
+ "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+ __func__, ear_pa_gain);
+ return -EINVAL;
+ }
+ }
+ ucontrol->value.integer.value[0] = ear_pa_gain;
+ dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+ return 0;
+}
+
+static int msm_anlg_cdc_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ if (get_codec_version(sdm660_cdc) >= DIANGU) {
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ ear_pa_gain = 0x06;
+ break;
+ case 1:
+ ear_pa_gain = 0x04;
+ break;
+ case 2:
+ ear_pa_gain = 0x02;
+ break;
+ case 3:
+ ear_pa_gain = 0x00;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+ 0x06, ear_pa_gain);
+ } else {
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ ear_pa_gain = 0x00;
+ break;
+ case 3:
+ ear_pa_gain = 0x20;
+ break;
+ case 1:
+ case 2:
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x20, ear_pa_gain);
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_hph_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (sdm660_cdc->hph_mode == NORMAL_MODE) {
+ ucontrol->value.integer.value[0] = 0;
+ } else if (sdm660_cdc->hph_mode == HD2_MODE) {
+ ucontrol->value.integer.value[0] = 1;
+ } else {
+ dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n",
+ __func__, sdm660_cdc->hph_mode);
+ }
+
+ dev_dbg(codec->dev, "%s: sdm660_cdc->hph_mode = %d\n", __func__,
+ sdm660_cdc->hph_mode);
+ return 0;
+}
+
+static int msm_anlg_cdc_hph_mode_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ sdm660_cdc->hph_mode = NORMAL_MODE;
+ break;
+ case 1:
+ if (get_codec_version(sdm660_cdc) >= DIANGU)
+ sdm660_cdc->hph_mode = HD2_MODE;
+ break;
+ default:
+ sdm660_cdc->hph_mode = NORMAL_MODE;
+ break;
+ }
+ dev_dbg(codec->dev, "%s: sdm660_cdc->hph_mode_set = %d\n",
+ __func__, sdm660_cdc->hph_mode);
+ return 0;
+}
+
+static int msm_anlg_cdc_boost_option_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (sdm660_cdc->boost_option == BOOST_SWITCH) {
+ ucontrol->value.integer.value[0] = 0;
+ } else if (sdm660_cdc->boost_option == BOOST_ALWAYS) {
+ ucontrol->value.integer.value[0] = 1;
+ } else if (sdm660_cdc->boost_option == BYPASS_ALWAYS) {
+ ucontrol->value.integer.value[0] = 2;
+ } else if (sdm660_cdc->boost_option == BOOST_ON_FOREVER) {
+ ucontrol->value.integer.value[0] = 3;
+ } else {
+ dev_err(codec->dev, "%s: ERROR: Unsupported Boost option= %d\n",
+ __func__, sdm660_cdc->boost_option);
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev, "%s: sdm660_cdc->boost_option = %d\n", __func__,
+ sdm660_cdc->boost_option);
+ return 0;
+}
+
+static int msm_anlg_cdc_boost_option_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ sdm660_cdc->boost_option = BOOST_SWITCH;
+ break;
+ case 1:
+ sdm660_cdc->boost_option = BOOST_ALWAYS;
+ break;
+ case 2:
+ sdm660_cdc->boost_option = BYPASS_ALWAYS;
+ msm_anlg_cdc_bypass_on(codec);
+ break;
+ case 3:
+ sdm660_cdc->boost_option = BOOST_ON_FOREVER;
+ msm_anlg_cdc_boost_on(codec);
+ break;
+ default:
+ pr_err("%s: invalid boost option: %d\n", __func__,
+ sdm660_cdc->boost_option);
+ return -EINVAL;
+ }
+ dev_dbg(codec->dev, "%s: sdm660_cdc->boost_option_set = %d\n",
+ __func__, sdm660_cdc->boost_option);
+ return 0;
+}
+
+static int msm_anlg_cdc_spk_boost_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (sdm660_cdc->spk_boost_set == false) {
+ ucontrol->value.integer.value[0] = 0;
+ } else if (sdm660_cdc->spk_boost_set == true) {
+ ucontrol->value.integer.value[0] = 1;
+ } else {
+ dev_err(codec->dev, "%s: ERROR: Unsupported Speaker Boost = %d\n",
+ __func__, sdm660_cdc->spk_boost_set);
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n", __func__,
+ sdm660_cdc->spk_boost_set);
+ return 0;
+}
+
+static int msm_anlg_cdc_spk_boost_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ sdm660_cdc->spk_boost_set = false;
+ break;
+ case 1:
+ sdm660_cdc->spk_boost_set = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n",
+ __func__, sdm660_cdc->spk_boost_set);
+ return 0;
+}
+
+static int msm_anlg_cdc_ext_spk_boost_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (sdm660_cdc->ext_spk_boost_set == false)
+ ucontrol->value.integer.value[0] = 0;
+ else
+ ucontrol->value.integer.value[0] = 1;
+
+ dev_dbg(codec->dev, "%s: sdm660_cdc->ext_spk_boost_set = %d\n",
+ __func__, sdm660_cdc->ext_spk_boost_set);
+ return 0;
+}
+
+static int msm_anlg_cdc_ext_spk_boost_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ sdm660_cdc->ext_spk_boost_set = false;
+ break;
+ case 1:
+ sdm660_cdc->ext_spk_boost_set = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n",
+ __func__, sdm660_cdc->spk_boost_set);
+ return 0;
+}
+
+
+static const char * const msm_anlg_cdc_loopback_mode_ctrl_text[] = {
+ "DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_loopback_mode_ctl_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_loopback_mode_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ear_pa_boost_ctrl_text[] = {
+ "DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_ear_pa_boost_ctl_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_ear_pa_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ear_pa_gain_text[] = {
+ "POS_1P5_DB", "POS_3_DB", "POS_4P5_DB", "POS_6_DB"};
+static const struct soc_enum msm_anlg_cdc_ear_pa_gain_enum[] = {
+ SOC_ENUM_SINGLE_EXT(4, msm_anlg_cdc_ear_pa_gain_text),
+};
+
+static const char * const msm_anlg_cdc_boost_option_ctrl_text[] = {
+ "BOOST_SWITCH", "BOOST_ALWAYS", "BYPASS_ALWAYS",
+ "BOOST_ON_FOREVER"};
+static const struct soc_enum msm_anlg_cdc_boost_option_ctl_enum[] = {
+ SOC_ENUM_SINGLE_EXT(4, msm_anlg_cdc_boost_option_ctrl_text),
+};
+static const char * const msm_anlg_cdc_spk_boost_ctrl_text[] = {
+ "DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_spk_boost_ctl_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_spk_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ext_spk_boost_ctrl_text[] = {
+ "DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_ext_spk_boost_ctl_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_ext_spk_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_hph_mode_ctrl_text[] = {
+ "NORMAL", "HD2"};
+static const struct soc_enum msm_anlg_cdc_hph_mode_ctl_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm_anlg_cdc_hph_mode_ctrl_text),
+ msm_anlg_cdc_hph_mode_ctrl_text),
+};
+
+/*cut of frequency for high pass filter*/
+static const char * const cf_text[] = {
+ "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+
+static const struct snd_kcontrol_new msm_anlg_cdc_snd_controls[] = {
+
+ SOC_ENUM_EXT("RX HPH Mode", msm_anlg_cdc_hph_mode_ctl_enum[0],
+ msm_anlg_cdc_hph_mode_get, msm_anlg_cdc_hph_mode_set),
+
+ SOC_ENUM_EXT("Boost Option", msm_anlg_cdc_boost_option_ctl_enum[0],
+ msm_anlg_cdc_boost_option_get, msm_anlg_cdc_boost_option_set),
+
+ SOC_ENUM_EXT("EAR PA Boost", msm_anlg_cdc_ear_pa_boost_ctl_enum[0],
+ msm_anlg_cdc_ear_pa_boost_get, msm_anlg_cdc_ear_pa_boost_set),
+
+ SOC_ENUM_EXT("EAR PA Gain", msm_anlg_cdc_ear_pa_gain_enum[0],
+ msm_anlg_cdc_pa_gain_get, msm_anlg_cdc_pa_gain_put),
+
+ SOC_ENUM_EXT("Speaker Boost", msm_anlg_cdc_spk_boost_ctl_enum[0],
+ msm_anlg_cdc_spk_boost_get, msm_anlg_cdc_spk_boost_set),
+
+ SOC_ENUM_EXT("Ext Spk Boost", msm_anlg_cdc_ext_spk_boost_ctl_enum[0],
+ msm_anlg_cdc_ext_spk_boost_get, msm_anlg_cdc_ext_spk_boost_set),
+
+ SOC_ENUM_EXT("LOOPBACK Mode", msm_anlg_cdc_loopback_mode_ctl_enum[0],
+ msm_anlg_cdc_loopback_mode_get, msm_anlg_cdc_loopback_mode_put),
+ SOC_SINGLE_TLV("ADC1 Volume", MSM89XX_PMIC_ANALOG_TX_1_EN, 3,
+ 8, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", MSM89XX_PMIC_ANALOG_TX_2_EN, 3,
+ 8, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", MSM89XX_PMIC_ANALOG_TX_3_EN, 3,
+ 8, 0, analog_gain),
+
+
+};
+
+static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ uint32_t zl, zr;
+ bool hphr;
+ struct soc_multi_mixer_control *mc;
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+
+ hphr = mc->shift;
+ ret = wcd_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
+ if (ret)
+ dev_dbg(codec->dev, "%s: Failed to get mbhc imped", __func__);
+ dev_dbg(codec->dev, "%s: zl %u, zr %u\n", __func__, zl, zr);
+ ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+ SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+ tombak_hph_impedance_get, NULL),
+ SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+ tombak_hph_impedance_get, NULL),
+};
+
+static int tombak_get_hph_type(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sdm660_cdc_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct wcd_mbhc *mbhc;
+
+ if (!priv) {
+ dev_err(codec->dev,
+ "%s: sdm660_cdc-wcd private data is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mbhc = &priv->mbhc;
+ if (!mbhc) {
+ dev_err(codec->dev, "%s: mbhc not initialized\n", __func__);
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
+ dev_dbg(codec->dev, "%s: hph_type = %u\n", __func__, mbhc->hph_type);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+ SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+ tombak_get_hph_type, NULL),
+};
+
+static const char * const rdac2_mux_text[] = {
+ "ZERO", "RX2", "RX1"
+};
+
+static const struct soc_enum rdac2_mux_enum =
+ SOC_ENUM_SINGLE(MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL,
+ 0, 3, rdac2_mux_text);
+
+static const char * const adc2_mux_text[] = {
+ "ZERO", "INP2", "INP3"
+};
+
+static const char * const ext_spk_text[] = {
+ "Off", "On"
+};
+
+static const char * const wsa_spk_text[] = {
+ "ZERO", "WSA"
+};
+
+
+
+static const char * const iir_inp1_text[] = {
+ "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
+};
+
+static const struct soc_enum adc2_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct soc_enum ext_spk_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ ARRAY_SIZE(ext_spk_text), ext_spk_text);
+
+static const struct soc_enum wsa_spk_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ ARRAY_SIZE(wsa_spk_text), wsa_spk_text);
+
+
+
+static const struct snd_kcontrol_new ext_spk_mux =
+ SOC_DAPM_ENUM("Ext Spk Switch Mux", ext_spk_enum);
+
+
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+ SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+
+static const struct snd_kcontrol_new rdac2_mux =
+ SOC_DAPM_ENUM("RDAC2 MUX Mux", rdac2_mux_enum);
+
+static const char * const ear_text[] = {
+ "ZERO", "Switch",
+};
+
+static const struct soc_enum ear_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(ear_text), ear_text);
+
+static const struct snd_kcontrol_new ear_pa_mux[] = {
+ SOC_DAPM_ENUM("EAR_S", ear_enum)
+};
+
+static const struct snd_kcontrol_new wsa_spk_mux[] = {
+ SOC_DAPM_ENUM("WSA Spk Switch", wsa_spk_enum)
+};
+
+
+
+static const char * const hph_text[] = {
+ "ZERO", "Switch",
+};
+
+static const struct soc_enum hph_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new hphl_mux[] = {
+ SOC_DAPM_ENUM("HPHL", hph_enum)
+};
+
+static const struct snd_kcontrol_new hphr_mux[] = {
+ SOC_DAPM_ENUM("HPHR", hph_enum)
+};
+
+static const struct snd_kcontrol_new spkr_mux[] = {
+ SOC_DAPM_ENUM("SPK", hph_enum)
+};
+
+static const char * const lo_text[] = {
+ "ZERO", "Switch",
+};
+
+static const struct soc_enum lo_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new lo_mux[] = {
+ SOC_DAPM_ENUM("LINE_OUT", lo_enum)
+};
+
+static void msm_anlg_cdc_codec_enable_adc_block(struct snd_soc_codec *codec,
+ int enable)
+{
+ struct sdm660_cdc_priv *wcd8x16 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s %d\n", __func__, enable);
+
+ if (enable) {
+ wcd8x16->adc_count++;
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+ 0x20, 0x20);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x10, 0x10);
+ } else {
+ wcd8x16->adc_count--;
+ if (!wcd8x16->adc_count) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x10, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+ 0x20, 0x0);
+ }
+ }
+}
+
+static int msm_anlg_cdc_codec_enable_adc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ u16 adc_reg;
+ u8 init_bit_shift;
+
+ dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+ adc_reg = MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2;
+
+ if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+ init_bit_shift = 5;
+ else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+ (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+ init_bit_shift = 4;
+ else {
+ dev_err(codec->dev, "%s: Error, invalid adc register\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ msm_anlg_cdc_codec_enable_adc_block(codec, 1);
+ if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x02);
+ /*
+ * Add delay of 10 ms to give sufficient time for the voltage
+ * to shoot up and settle so that the txfe init does not
+ * happen when the input voltage is changing too much.
+ */
+ usleep_range(10000, 10010);
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+ 1 << init_bit_shift);
+ if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
+ 0x03, 0x00);
+ else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+ (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
+ 0x03, 0x00);
+ /* Wait for 1ms to allow txfe settling time */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * Add delay of 12 ms before deasserting the init
+ * to reduce the tx pop
+ */
+ usleep_range(12000, 12010);
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+ /* Wait for 1ms to allow txfe settling time post powerup */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ msm_anlg_cdc_codec_enable_adc_block(codec, 0);
+ if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x00);
+ if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
+ 0x03, 0x02);
+ else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+ (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
+ 0x03, 0x02);
+
+ break;
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x01);
+ switch (sdm660_cdc->boost_option) {
+ case BOOST_SWITCH:
+ if (!sdm660_cdc->spk_boost_set)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+ 0x10, 0x10);
+ break;
+ case BOOST_ALWAYS:
+ case BOOST_ON_FOREVER:
+ break;
+ case BYPASS_ALWAYS:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+ 0x10, 0x10);
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: invalid boost option: %d\n", __func__,
+ sdm660_cdc->boost_option);
+ break;
+ }
+ /* Wait for 1ms after SPK_DAC CTL setting */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0xE0);
+ if (get_codec_version(sdm660_cdc) != TOMBAK_1_0)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x01);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* Wait for 1ms after SPK_VBAT_LDO Enable */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ switch (sdm660_cdc->boost_option) {
+ case BOOST_SWITCH:
+ if (sdm660_cdc->spk_boost_set)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+ 0xEF, 0xEF);
+ else
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+ 0x10, 0x00);
+ break;
+ case BOOST_ALWAYS:
+ case BOOST_ON_FOREVER:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+ 0xEF, 0xEF);
+ break;
+ case BYPASS_ALWAYS:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: invalid boost option: %d\n", __func__,
+ sdm660_cdc->boost_option);
+ break;
+ }
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX3_MUTE_OFF);
+ snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX3_MUTE_ON);
+ /*
+ * Add 1 ms sleep for the mute to take effect
+ */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x10);
+ if (get_codec_version(sdm660_cdc) < CAJON_2_0)
+ msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMD);
+ snd_soc_update_bits(codec, w->reg, 0x80, 0x00);
+ switch (sdm660_cdc->boost_option) {
+ case BOOST_SWITCH:
+ if (sdm660_cdc->spk_boost_set)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+ 0xEF, 0x69);
+ break;
+ case BOOST_ALWAYS:
+ case BOOST_ON_FOREVER:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+ 0xEF, 0x69);
+ break;
+ case BYPASS_ALWAYS:
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: invalid boost option: %d\n", __func__,
+ sdm660_cdc->boost_option);
+ break;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0x00);
+ /* Wait for 1ms to allow setting time for spkr path disable */
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
+ if (get_codec_version(sdm660_cdc) != TOMBAK_1_0)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
+ if (get_codec_version(sdm660_cdc) >= CAJON_2_0)
+ msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMD);
+ break;
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_dig_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+ struct msm_asoc_mach_data *pdata = NULL;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+ dev_dbg(codec->dev, "%s event %d w->name %s\n", __func__,
+ event, w->name);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+ snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
+ msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMU);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (sdm660_cdc->rx_bias_count == 0)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x80, 0x00);
+ }
+ return 0;
+}
+
+
+
+static bool msm_anlg_cdc_use_mb(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (get_codec_version(sdm660_cdc) < CAJON)
+ return true;
+ else
+ return false;
+}
+
+static void msm_anlg_cdc_set_auto_zeroing(struct snd_soc_codec *codec,
+ bool enable)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (get_codec_version(sdm660_cdc) < CONGA) {
+ if (enable)
+ /*
+ * Set autozeroing for special headset detection and
+ * buttons to work.
+ */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN,
+ 0x18, 0x10);
+ else
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_2_EN,
+ 0x18, 0x00);
+
+ } else {
+ dev_dbg(codec->dev,
+ "%s: Auto Zeroing is not required from CONGA\n",
+ __func__);
+ }
+}
+
+static void msm_anlg_cdc_trim_btn_reg(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ if (get_codec_version(sdm660_cdc) == TOMBAK_1_0) {
+ pr_debug("%s: This device needs to be trimmed\n", __func__);
+ /*
+ * Calculate the trim value for each device used
+ * till is comes in production by hardware team
+ */
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+ 0xA5, 0xA5);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_TRIM_CTRL2,
+ 0xFF, 0x30);
+ } else {
+ dev_dbg(codec->dev, "%s: This device is trimmed at ATE\n",
+ __func__);
+ }
+}
+
+static int msm_anlg_cdc_enable_ext_mb_source(struct wcd_mbhc *wcd_mbhc,
+ bool turn_on)
+{
+ int ret = 0;
+ static int count;
+ struct snd_soc_codec *codec = wcd_mbhc->codec;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+ dev_dbg(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
+ count);
+ if (turn_on) {
+ if (!count) {
+ ret = snd_soc_dapm_force_enable_pin(dapm,
+ "MICBIAS_REGULATOR");
+ snd_soc_dapm_sync(dapm);
+ }
+ count++;
+ } else {
+ if (count > 0)
+ count--;
+ if (!count) {
+ ret = snd_soc_dapm_disable_pin(dapm,
+ "MICBIAS_REGULATOR");
+ snd_soc_dapm_sync(dapm);
+ }
+ }
+
+ if (ret)
+ dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+ __func__, turn_on ? "enable" : "disabled");
+ else
+ dev_dbg(codec->dev, "%s: %s external micbias source\n",
+ __func__, turn_on ? "Enabled" : "Disabled");
+
+ return ret;
+}
+
+static int msm_anlg_cdc_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+ u16 micb_int_reg;
+ char *internal1_text = "Internal1";
+ char *internal2_text = "Internal2";
+ char *internal3_text = "Internal3";
+ char *external2_text = "External2";
+ char *external_text = "External";
+ bool micbias2;
+
+ dev_dbg(codec->dev, "%s %d\n", __func__, event);
+ switch (w->reg) {
+ case MSM89XX_PMIC_ANALOG_MICB_1_EN:
+ case MSM89XX_PMIC_ANALOG_MICB_2_EN:
+ micb_int_reg = MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS;
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s: Error, invalid micbias register 0x%x\n",
+ __func__, w->reg);
+ return -EINVAL;
+ }
+
+ micbias2 = (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN) & 0x80);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (strnstr(w->name, internal1_text, strlen(w->name))) {
+ if (get_codec_version(sdm660_cdc) >= CAJON)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
+ 0x02, 0x02);
+ snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
+ } else if (strnstr(w->name, internal2_text, strlen(w->name))) {
+ snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
+ snd_soc_update_bits(codec, w->reg, 0x60, 0x00);
+ } else if (strnstr(w->name, internal3_text, strlen(w->name))) {
+ snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
+ /*
+ * update MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2
+ * for external bias only, not for external2.
+ */
+ } else if (!strnstr(w->name, external2_text, strlen(w->name)) &&
+ strnstr(w->name, external_text,
+ strlen(w->name))) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
+ 0x02, 0x02);
+ }
+ if (!strnstr(w->name, external_text, strlen(w->name)))
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_1_EN, 0x05, 0x04);
+ if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
+ msm_anlg_cdc_configure_cap(codec, true, micbias2);
+
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (get_codec_version(sdm660_cdc) <= TOMBAK_2_0)
+ /*
+ * Wait for 20ms post micbias enable
+ * for version < tombak 2.0.
+ */
+ usleep_range(20000, 20100);
+ if (strnstr(w->name, internal1_text, strlen(w->name))) {
+ snd_soc_update_bits(codec, micb_int_reg, 0x40, 0x40);
+ } else if (strnstr(w->name, internal2_text, strlen(w->name))) {
+ snd_soc_update_bits(codec, micb_int_reg, 0x08, 0x08);
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_POST_MICBIAS_2_ON);
+ } else if (strnstr(w->name, internal3_text, 30)) {
+ snd_soc_update_bits(codec, micb_int_reg, 0x01, 0x01);
+ } else if (strnstr(w->name, external2_text, strlen(w->name))) {
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_POST_MICBIAS_2_ON);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (strnstr(w->name, internal1_text, strlen(w->name))) {
+ snd_soc_update_bits(codec, micb_int_reg, 0xC0, 0x40);
+ } else if (strnstr(w->name, internal2_text, strlen(w->name))) {
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_POST_MICBIAS_2_OFF);
+ } else if (strnstr(w->name, internal3_text, 30)) {
+ snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
+ } else if (strnstr(w->name, external2_text, strlen(w->name))) {
+ /*
+ * send micbias turn off event to mbhc driver and then
+ * break, as no need to set MICB_1_EN register.
+ */
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_POST_MICBIAS_2_OFF);
+ break;
+ }
+ if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
+ msm_anlg_cdc_configure_cap(codec, false, micbias2);
+ break;
+ }
+ return 0;
+}
+
+static void update_clkdiv(void *handle, int val)
+{
+ struct sdm660_cdc *handle_cdc = handle;
+ struct snd_soc_codec *codec = handle_cdc->codec;
+
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV,
+ 0xFF, val);
+}
+
+static int get_cdc_version(void *handle)
+{
+ struct sdm660_cdc *handle_cdc = handle;
+ struct snd_soc_codec *codec = handle_cdc->codec;
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ return get_codec_version(sdm660_cdc);
+}
+
+static int sdm660_wcd_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ if (!sdm660_cdc->ext_spk_boost_set) {
+ dev_dbg(codec->dev, "%s: ext_boost not supported/disabled\n",
+ __func__);
+ return 0;
+ }
+ dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (sdm660_cdc->spkdrv_reg) {
+ ret = regulator_enable(sdm660_cdc->spkdrv_reg);
+ if (ret)
+ dev_err(codec->dev,
+ "%s Failed to enable spkdrv reg %s\n",
+ __func__, MSM89XX_VDD_SPKDRV_NAME);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (sdm660_cdc->spkdrv_reg) {
+ ret = regulator_disable(sdm660_cdc->spkdrv_reg);
+ if (ret)
+ dev_err(codec->dev,
+ "%s: Failed to disable spkdrv_reg %s\n",
+ __func__, MSM89XX_VDD_SPKDRV_NAME);
+ }
+ break;
+ }
+ return 0;
+}
+
+
+/* The register address is the same as other codec so it can use resmgr */
+static int msm_anlg_cdc_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ sdm660_cdc->rx_bias_count++;
+ if (sdm660_cdc->rx_bias_count == 1) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+ 0x80, 0x80);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+ 0x01, 0x01);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ sdm660_cdc->rx_bias_count--;
+ if (sdm660_cdc->rx_bias_count == 0) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+ 0x01, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+ 0x80, 0x00);
+ }
+ break;
+ }
+ dev_dbg(codec->dev, "%s rx_bias_count = %d\n",
+ __func__, sdm660_cdc->rx_bias_count);
+ return 0;
+}
+
+static uint32_t wcd_get_impedance_value(uint32_t imped)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wcd_imped_val) - 1; i++) {
+ if (imped >= wcd_imped_val[i] &&
+ imped < wcd_imped_val[i + 1])
+ break;
+ }
+
+ pr_debug("%s: selected impedance value = %d\n",
+ __func__, wcd_imped_val[i]);
+ return wcd_imped_val[i];
+}
+
+static void wcd_imped_config(struct snd_soc_codec *codec,
+ uint32_t imped, bool set_gain)
+{
+ uint32_t value;
+ int codec_version;
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ value = wcd_get_impedance_value(imped);
+
+ if (value < wcd_imped_val[0]) {
+ dev_dbg(codec->dev,
+ "%s, detected impedance is less than 4 Ohm\n",
+ __func__);
+ return;
+ }
+
+ codec_version = get_codec_version(sdm660_cdc);
+
+ if (set_gain) {
+ switch (codec_version) {
+ case TOMBAK_1_0:
+ case TOMBAK_2_0:
+ case CONGA:
+ /*
+ * For 32Ohm load and higher loads, Set 0x19E
+ * bit 5 to 1 (POS_0_DB_DI). For loads lower
+ * than 32Ohm (such as 16Ohm load), Set 0x19E
+ * bit 5 to 0 (POS_M4P5_DB_DI)
+ */
+ if (value >= 32)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x20, 0x20);
+ else
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x20, 0x00);
+ break;
+ case CAJON:
+ case CAJON_2_0:
+ case DIANGU:
+ case DRAX_CDC:
+ if (value >= 13) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x20, 0x20);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+ 0x07, 0x07);
+ } else {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x20, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+ 0x07, 0x04);
+ }
+ break;
+ }
+ } else {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x20, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+ 0x07, 0x04);
+ }
+
+ dev_dbg(codec->dev, "%s: Exit\n", __func__);
+}
+
+static int msm_anlg_cdc_hphl_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ uint32_t impedl, impedr;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+ ret = wcd_mbhc_get_impedance(&sdm660_cdc->mbhc,
+ &impedl, &impedr);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (get_codec_version(sdm660_cdc) > CAJON)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+ 0x08, 0x08);
+ if (get_codec_version(sdm660_cdc) == CAJON ||
+ get_codec_version(sdm660_cdc) == CAJON_2_0) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST,
+ 0x80, 0x80);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST,
+ 0x80, 0x80);
+ }
+ if (get_codec_version(sdm660_cdc) > CAJON)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+ 0x08, 0x00);
+ if (sdm660_cdc->hph_mode == HD2_MODE)
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_PRE_RX1_INT_ON);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02);
+ if (!ret)
+ wcd_imped_config(codec, impedl, true);
+ else
+ dev_dbg(codec->dev, "Failed to get mbhc impedance %d\n",
+ ret);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd_imped_config(codec, impedl, false);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00);
+ if (sdm660_cdc->hph_mode == HD2_MODE)
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_POST_RX1_INT_OFF);
+ break;
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_lo_dac_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);
+
+ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x20);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x80);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x80);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x40);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* Wait for 20ms before powerdown of lineout_dac */
+ usleep_range(20000, 20100);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_hphr_dac_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);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (sdm660_cdc->hph_mode == HD2_MODE)
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_PRE_RX2_INT_ON);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00);
+ if (sdm660_cdc->hph_mode == HD2_MODE)
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_POST_RX2_INT_OFF);
+ break;
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_hph_pa_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);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (w->shift == 5)
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_PRE_HPHL_PA_ON);
+ else if (w->shift == 4)
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_PRE_HPHR_PA_ON);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x20, 0x20);
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+ /* Wait for 7ms to allow setting time for HPH_PA Enable */
+ usleep_range(7000, 7100);
+ if (w->shift == 5) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX1_MUTE_OFF);
+ } else if (w->shift == 4) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX2_MUTE_OFF);
+ }
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ if (w->shift == 5) {
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX1_MUTE_ON);
+ /* Wait for 20ms after HPHL RX digital mute */
+ msleep(20);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x00);
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_PRE_HPHL_PA_OFF);
+ } else if (w->shift == 4) {
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX2_MUTE_ON);
+ /* Wait for 20ms after HPHR RX digital mute */
+ msleep(20);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x00);
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_PRE_HPHR_PA_OFF);
+ }
+ if (get_codec_version(sdm660_cdc) >= CAJON) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
+ 0xF0, 0x30);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (w->shift == 5) {
+ clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK,
+ &sdm660_cdc->mbhc.hph_pa_dac_state);
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_POST_HPHL_PA_OFF);
+ } else if (w->shift == 4) {
+ clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK,
+ &sdm660_cdc->mbhc.hph_pa_dac_state);
+ msm_anlg_cdc_notifier_call(codec,
+ WCD_EVENT_POST_HPHR_PA_OFF);
+ }
+ /* Wait for 15ms after HPH RX teardown */
+ usleep_range(15000, 15100);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* RDAC Connections */
+ {"HPHR DAC", NULL, "RDAC2 MUX"},
+ {"RDAC2 MUX", "RX1", "PDM_IN_RX1"},
+ {"RDAC2 MUX", "RX2", "PDM_IN_RX2"},
+
+ /* WSA */
+ {"WSA_SPK OUT", NULL, "WSA Spk Switch"},
+ {"WSA Spk Switch", "WSA", "EAR PA"},
+
+ /* Earpiece (RX MIX1) */
+ {"EAR", NULL, "EAR_S"},
+ {"EAR_S", "Switch", "EAR PA"},
+ {"EAR PA", NULL, "RX_BIAS"},
+ {"EAR PA", NULL, "HPHL DAC"},
+ {"EAR PA", NULL, "HPHR DAC"},
+ {"EAR PA", NULL, "EAR CP"},
+
+ /* Headset (RX MIX1 and RX MIX2) */
+ {"HEADPHONE", NULL, "HPHL PA"},
+ {"HEADPHONE", NULL, "HPHR PA"},
+
+ {"Ext Spk", NULL, "Ext Spk Switch"},
+ {"Ext Spk Switch", "On", "HPHL PA"},
+ {"Ext Spk Switch", "On", "HPHR PA"},
+
+ {"HPHL PA", NULL, "HPHL"},
+ {"HPHR PA", NULL, "HPHR"},
+ {"HPHL", "Switch", "HPHL DAC"},
+ {"HPHR", "Switch", "HPHR DAC"},
+ {"HPHL PA", NULL, "CP"},
+ {"HPHL PA", NULL, "RX_BIAS"},
+ {"HPHR PA", NULL, "CP"},
+ {"HPHR PA", NULL, "RX_BIAS"},
+ {"HPHL DAC", NULL, "PDM_IN_RX1"},
+
+ {"SPK_OUT", NULL, "SPK PA"},
+ {"SPK PA", NULL, "SPK_RX_BIAS"},
+ {"SPK PA", NULL, "SPK"},
+ {"SPK", "Switch", "SPK DAC"},
+ {"SPK DAC", NULL, "PDM_IN_RX3"},
+ {"SPK DAC", NULL, "VDD_SPKDRV"},
+
+ /* lineout */
+ {"LINEOUT", NULL, "LINEOUT PA"},
+ {"LINEOUT PA", NULL, "SPK_RX_BIAS"},
+ {"LINEOUT PA", NULL, "LINE_OUT"},
+ {"LINE_OUT", "Switch", "LINEOUT DAC"},
+ {"LINEOUT DAC", NULL, "PDM_IN_RX3"},
+
+ /* lineout to WSA */
+ {"WSA_SPK OUT", NULL, "LINEOUT PA"},
+
+ {"PDM_IN_RX1", NULL, "RX1 CLK"},
+ {"PDM_IN_RX2", NULL, "RX2 CLK"},
+ {"PDM_IN_RX3", NULL, "RX3 CLK"},
+
+ {"ADC1_OUT", NULL, "ADC1"},
+ {"ADC2_OUT", NULL, "ADC2"},
+ {"ADC3_OUT", NULL, "ADC3"},
+
+ /* ADC Connections */
+ {"ADC2", NULL, "ADC2 MUX"},
+ {"ADC3", NULL, "ADC2 MUX"},
+ {"ADC2 MUX", "INP2", "ADC2_INP2"},
+ {"ADC2 MUX", "INP3", "ADC2_INP3"},
+
+ {"ADC1", NULL, "AMIC1"},
+ {"ADC2_INP2", NULL, "AMIC2"},
+ {"ADC2_INP3", NULL, "AMIC3"},
+
+ {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
+ {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+ {"MIC BIAS External", NULL, "INT_LDO_H"},
+ {"MIC BIAS External2", NULL, "INT_LDO_H"},
+ {"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
+ {"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
+ {"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
+ {"MIC BIAS External2", NULL, "MICBIAS_REGULATOR"},
+};
+
+static int msm_anlg_cdc_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(dai->codec);
+
+ dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
+ __func__,
+ substream->name, substream->stream);
+ /*
+ * If status_mask is BUS_DOWN it means SSR is not complete.
+ * So return error.
+ */
+ if (test_bit(BUS_DOWN, &sdm660_cdc->status_mask)) {
+ dev_err(dai->codec->dev, "Error, Device is not up post SSR\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void msm_anlg_cdc_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ dev_dbg(dai->codec->dev,
+ "%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+}
+
+int msm_anlg_cdc_mclk_enable(struct snd_soc_codec *codec,
+ int mclk_enable, bool dapm)
+{
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
+ __func__, mclk_enable, dapm);
+ if (mclk_enable) {
+ sdm660_cdc->int_mclk0_enabled = true;
+ msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+ } else {
+ if (!sdm660_cdc->int_mclk0_enabled) {
+ dev_err(codec->dev, "Error, MCLK already diabled\n");
+ return -EINVAL;
+ }
+ sdm660_cdc->int_mclk0_enabled = false;
+ msm_anlg_cdc_codec_enable_clock_block(codec, 0);
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ dev_dbg(dai->codec->dev, "%s\n", __func__);
+ return 0;
+}
+
+static int msm_anlg_cdc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ dev_dbg(dai->codec->dev, "%s\n", __func__);
+ return 0;
+}
+
+static int msm_anlg_cdc_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+
+{
+ dev_dbg(dai->codec->dev, "%s\n", __func__);
+ return 0;
+}
+
+static int msm_anlg_cdc_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+ dev_dbg(dai->codec->dev, "%s\n", __func__);
+ return 0;
+}
+
+static struct snd_soc_dai_ops msm_anlg_cdc_dai_ops = {
+ .startup = msm_anlg_cdc_startup,
+ .shutdown = msm_anlg_cdc_shutdown,
+ .set_sysclk = msm_anlg_cdc_set_dai_sysclk,
+ .set_fmt = msm_anlg_cdc_set_dai_fmt,
+ .set_channel_map = msm_anlg_cdc_set_channel_map,
+ .get_channel_map = msm_anlg_cdc_get_channel_map,
+};
+
+static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[] = {
+ {
+ .name = "msm_anlg_cdc_i2s_rx1",
+ .id = AIF1_PB,
+ .playback = {
+ .stream_name = "Playback",
+ .rates = SDM660_CDC_RATES,
+ .formats = SDM660_CDC_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 3,
+ },
+ .ops = &msm_anlg_cdc_dai_ops,
+ },
+ {
+ .name = "msm_anlg_cdc_i2s_tx1",
+ .id = AIF1_CAP,
+ .capture = {
+ .stream_name = "Record",
+ .rates = SDM660_CDC_RATES,
+ .formats = SDM660_CDC_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &msm_anlg_cdc_dai_ops,
+ },
+ {
+ .name = "msm_anlg_cdc_i2s_tx2",
+ .id = AIF3_SVA,
+ .capture = {
+ .stream_name = "RecordSVA",
+ .rates = SDM660_CDC_RATES,
+ .formats = SDM660_CDC_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &msm_anlg_cdc_dai_ops,
+ },
+ {
+ .name = "msm_anlg_vifeedback",
+ .id = AIF2_VIFEED,
+ .capture = {
+ .stream_name = "VIfeed",
+ .rates = SDM660_CDC_RATES,
+ .formats = SDM660_CDC_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = &msm_anlg_cdc_dai_ops,
+ },
+};
+
+
+static int msm_anlg_cdc_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ dev_dbg(codec->dev, "%s: %d %s\n", __func__, event, w->name);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX3_MUTE_OFF);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX3_MUTE_ON);
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_spk_ext_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ dev_dbg(codec->dev,
+ "%s: enable external speaker PA\n", __func__);
+ if (sdm660_cdc->codec_spk_ext_pa_cb)
+ sdm660_cdc->codec_spk_ext_pa_cb(codec, 1);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ dev_dbg(codec->dev,
+ "%s: enable external speaker PA\n", __func__);
+ if (sdm660_cdc->codec_spk_ext_pa_cb)
+ sdm660_cdc->codec_spk_ext_pa_cb(codec, 0);
+ break;
+ }
+ return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ dev_dbg(codec->dev,
+ "%s: Sleeping 20ms after select EAR PA\n",
+ __func__);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x80, 0x80);
+ if (get_codec_version(sdm660_cdc) < CONGA)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x2A);
+ if (get_codec_version(sdm660_cdc) >= DIANGU) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, 0x08, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ dev_dbg(codec->dev,
+ "%s: Sleeping 20ms after enabling EAR PA\n",
+ __func__);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x40, 0x40);
+ /* Wait for 7ms after EAR PA enable */
+ usleep_range(7000, 7100);
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX1_MUTE_OFF);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_RX1_MUTE_ON);
+ /* Wait for 20ms for RX digital mute to take effect */
+ msleep(20);
+ if (sdm660_cdc->boost_option == BOOST_ALWAYS) {
+ dev_dbg(codec->dev,
+ "%s: boost_option:%d, tear down ear\n",
+ __func__, sdm660_cdc->boost_option);
+ msm_anlg_cdc_boost_mode_sequence(codec, EAR_PMD);
+ }
+ if (get_codec_version(sdm660_cdc) >= DIANGU) {
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x0);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x0);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ dev_dbg(codec->dev,
+ "%s: Sleeping 7ms after disabling EAR PA\n",
+ __func__);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0x40, 0x00);
+ /* Wait for 7ms after EAR PA teardown */
+ usleep_range(7000, 7100);
+ if (get_codec_version(sdm660_cdc) < CONGA)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x16);
+ if (get_codec_version(sdm660_cdc) >= DIANGU)
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, 0x08, 0x08);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget msm_anlg_cdc_dapm_widgets[] = {
+ SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM,
+ 0, 0, NULL, 0, msm_anlg_cdc_codec_enable_ear_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHL PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+ 5, 0, NULL, 0,
+ msm_anlg_cdc_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHR PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+ 4, 0, NULL, 0,
+ msm_anlg_cdc_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM,
+ 0, 0, NULL, 0, msm_anlg_cdc_codec_enable_spk_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL,
+ 5, 0, NULL, 0, msm_anlg_cdc_codec_enable_lo_pa,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, ear_pa_mux),
+ SND_SOC_DAPM_MUX("SPK", SND_SOC_NOPM, 0, 0, spkr_mux),
+ SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, hphl_mux),
+ SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, hphr_mux),
+ SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
+ SND_SOC_DAPM_MUX("WSA Spk Switch", SND_SOC_NOPM, 0, 0, wsa_spk_mux),
+ SND_SOC_DAPM_MUX("Ext Spk Switch", SND_SOC_NOPM, 0, 0, &ext_spk_mux),
+ SND_SOC_DAPM_MUX("LINE_OUT", SND_SOC_NOPM, 0, 0, lo_mux),
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+
+ SND_SOC_DAPM_MIXER_E("HPHL DAC",
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
+ 0, msm_anlg_cdc_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("HPHR DAC",
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
+ 0, msm_anlg_cdc_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_DAC("SPK DAC", NULL, MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+ 7, 0),
+ SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
+ SND_SOC_NOPM, 0, 0, msm_anlg_cdc_lo_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Ext Spk", msm_anlg_cdc_codec_enable_spk_ext_pa),
+
+ SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 2, 0, msm_anlg_cdc_codec_enable_dig_clk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("CP", MSM89XX_PMIC_ANALOG_NCP_EN, 0, 0,
+ msm_anlg_cdc_codec_enable_charge_pump,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("EAR CP", MSM89XX_PMIC_ANALOG_NCP_EN, 4, 0,
+ msm_anlg_cdc_codec_enable_charge_pump,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("RX_BIAS", 1, SND_SOC_NOPM,
+ 0, 0, msm_anlg_cdc_codec_enable_rx_bias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("SPK_RX_BIAS", 1, SND_SOC_NOPM, 0, 0,
+ msm_anlg_cdc_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
+ sdm660_wcd_codec_enable_vdd_spkr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
+ ON_DEMAND_MICBIAS, 0,
+ msm_anlg_cdc_codec_enable_on_demand_supply,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
+ MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+ msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
+ MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
+ msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
+ MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+ msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM89XX_PMIC_ANALOG_TX_1_EN, 7, 0,
+ msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2_INP2",
+ NULL, MSM89XX_PMIC_ANALOG_TX_2_EN, 7, 0,
+ msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2_INP3",
+ NULL, MSM89XX_PMIC_ANALOG_TX_3_EN, 7, 0,
+ msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
+ MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+ msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS External2",
+ MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
+ msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_INPUT("PDM_IN_RX1"),
+ SND_SOC_DAPM_INPUT("PDM_IN_RX2"),
+ SND_SOC_DAPM_INPUT("PDM_IN_RX3"),
+
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("WSA_SPK OUT"),
+ SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+ SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
+ SND_SOC_DAPM_OUTPUT("ADC1_OUT"),
+ SND_SOC_DAPM_OUTPUT("ADC2_OUT"),
+ SND_SOC_DAPM_OUTPUT("ADC3_OUT"),
+};
+
+static const struct sdm660_cdc_reg_mask_val msm_anlg_cdc_reg_defaults[] = {
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+};
+
+static const struct sdm660_cdc_reg_mask_val
+ msm_anlg_cdc_reg_defaults_2_0[] = {
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, 0x5F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, 0x88),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val conga_wcd_reg_defaults[] = {
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE, 0x0A),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val cajon_wcd_reg_defaults[] = {
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val cajon2p0_wcd_reg_defaults[] = {
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_EAR_STATUS, 0x10),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BYPASS_MODE, 0x18),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
+ MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static void msm_anlg_cdc_update_reg_defaults(struct snd_soc_codec *codec)
+{
+ u32 i, version;
+ struct sdm660_cdc_priv *sdm660_cdc =
+ snd_soc_codec_get_drvdata(codec);
+
+ version = get_codec_version(sdm660_cdc);
+ if (version == TOMBAK_1_0) {
+ for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_reg_defaults); i++)
+ snd_soc_write(codec, msm_anlg_cdc_reg_defaults[i].reg,
+ msm_anlg_cdc_reg_defaults[i].val);
+ } else if (version == TOMBAK_2_0) {
+ for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_reg_defaults_2_0); i++)
+ snd_soc_write(codec,
+ msm_anlg_cdc_reg_defaults_2_0[i].reg,
+ msm_anlg_cdc_reg_defaults_2_0[i].val);
+ } else if (version == CONGA) {
+ for (i = 0; i < ARRAY_SIZE(conga_wcd_reg_defaults); i++)
+ snd_soc_write(codec,
+ conga_wcd_reg_defaults[i].reg,
+ conga_wcd_reg_defaults[i].val);
+ } else if (version == CAJON) {
+ for (i = 0; i < ARRAY_SIZE(cajon_wcd_reg_defaults); i++)
+ snd_soc_write(codec,
+ cajon_wcd_reg_defaults[i].reg,
+ cajon_wcd_reg_defaults[i].val);
+ } else if (version == CAJON_2_0 || version == DIANGU
+ || version == DRAX_CDC) {
+ for (i = 0; i < ARRAY_SIZE(cajon2p0_wcd_reg_defaults); i++)
+ snd_soc_write(codec,
+ cajon2p0_wcd_reg_defaults[i].reg,
+ cajon2p0_wcd_reg_defaults[i].val);
+ }
+}
+
+static const struct sdm660_cdc_reg_mask_val
+ msm_anlg_cdc_codec_reg_init_val[] = {
+
+ /* Initialize current threshold to 350MA
+ * number of wait and run cycles to 4096
+ */
+ {MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0xFF, 0x12},
+ {MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+};
+
+static void msm_anlg_cdc_codec_init_cache(struct snd_soc_codec *codec)
+{
+ u32 i;
+
+ regcache_cache_only(codec->component.regmap, true);
+ /* update cache with POR values */
+ for (i = 0; i < ARRAY_SIZE(msm89xx_pmic_cdc_defaults); i++)
+ snd_soc_write(codec, msm89xx_pmic_cdc_defaults[i].reg,
+ msm89xx_pmic_cdc_defaults[i].def);
+ regcache_cache_only(codec->component.regmap, false);
+}
+
+static void msm_anlg_cdc_codec_init_reg(struct snd_soc_codec *codec)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_codec_reg_init_val); i++)
+ snd_soc_update_bits(codec,
+ msm_anlg_cdc_codec_reg_init_val[i].reg,
+ msm_anlg_cdc_codec_reg_init_val[i].mask,
+ msm_anlg_cdc_codec_reg_init_val[i].val);
+}
+
+static int msm_anlg_cdc_bringup(struct snd_soc_codec *codec)
+{
+ snd_soc_write(codec,
+ MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
+ 0xA5);
+ snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x01);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+ 0xA5);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x01);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
+ 0xA5);
+ snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x00);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+ 0xA5);
+ snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00);
+ return 0;
+}
+
+static struct regulator *msm_anlg_cdc_find_regulator(
+ const struct sdm660_cdc *sdm660_cdc,
+ const char *name)
+{
+ int i;
+
+ for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+ if (sdm660_cdc->supplies[i].supply &&
+ !strcmp(sdm660_cdc->supplies[i].supply, name))
+ return sdm660_cdc->supplies[i].consumer;
+ }
+
+ dev_err(sdm660_cdc->dev, "Error: regulator not found:%s\n"
+ , name);
+ return NULL;
+}
+
+static int msm_anlg_cdc_device_down(struct snd_soc_codec *codec)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ snd_soc_codec_get_drvdata(codec);
+ unsigned int tx_1_en;
+ unsigned int tx_2_en;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ dev_dbg(codec->dev, "%s: device down!\n", __func__);
+
+ tx_1_en = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_TX_1_EN);
+ tx_2_en = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_TX_2_EN);
+ tx_1_en = tx_1_en & 0x7f;
+ tx_2_en = tx_2_en & 0x7f;
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_TX_1_EN, tx_1_en);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_TX_2_EN, tx_2_en);
+ if (sdm660_cdc_priv->boost_option == BOOST_ON_FOREVER) {
+ if ((snd_soc_read(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL)
+ & 0x80) == 0) {
+ msm_anlg_cdc_dig_notifier_call(codec,
+ DIG_CDC_EVENT_CLK_ON);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL,
+ 0x0C, 0x0C);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+ 0x84, 0x84);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+ 0x10, 0x10);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
+ 0x1F, 0x1F);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+ 0x90, 0x90);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+ 0xFF, 0xFF);
+ /* Wait for 20us for boost settings to take effect */
+ usleep_range(20, 21);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
+ 0xFF, 0xFF);
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+ 0xE9, 0xE9);
+ }
+ }
+ msm_anlg_cdc_boost_off(codec);
+ sdm660_cdc_priv->hph_mode = NORMAL_MODE;
+
+ /* 40ms to allow boost to discharge */
+ msleep(40);
+ /* Disable PA to avoid pop during codec bring up */
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+ 0x30, 0x00);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+ 0x80, 0x00);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x20);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x20);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x12);
+ snd_soc_write(codec,
+ MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
+
+ msm_anlg_cdc_bringup(codec);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_DOWN);
+ set_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
+ snd_soc_card_change_online_state(codec->component.card, 0);
+ return 0;
+}
+
+static int msm_anlg_cdc_device_up(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ dev_dbg(codec->dev, "%s: device up!\n", __func__);
+
+ msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_UP);
+ clear_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
+ snd_soc_card_change_online_state(codec->component.card, 1);
+ /* delay is required to make sure sound card state updated */
+ usleep_range(5000, 5100);
+
+ msm_anlg_cdc_codec_init_reg(codec);
+ msm_anlg_cdc_update_reg_defaults(codec);
+
+ regcache_mark_dirty(codec->component.regmap);
+ regcache_sync_region(codec->component.regmap,
+ MSM89XX_PMIC_DIGITAL_REVISION1,
+ MSM89XX_PMIC_CDC_MAX_REGISTER);
+
+ snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_INT_EN_SET,
+ MSM89XX_PMIC_DIGITAL_INT_EN_SET__POR);
+ snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
+ MSM89XX_PMIC_DIGITAL_INT_EN_CLR__POR);
+
+ msm_anlg_cdc_set_boost_v(codec);
+ msm_anlg_cdc_set_micb_v(codec);
+ if (sdm660_cdc_priv->boost_option == BOOST_ON_FOREVER)
+ msm_anlg_cdc_boost_on(codec);
+ else if (sdm660_cdc_priv->boost_option == BYPASS_ALWAYS)
+ msm_anlg_cdc_bypass_on(codec);
+
+ msm_anlg_cdc_configure_cap(codec, false, false);
+ wcd_mbhc_stop(&sdm660_cdc_priv->mbhc);
+ wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc);
+ ret = wcd_mbhc_init(&sdm660_cdc_priv->mbhc, codec, &mbhc_cb,
+ &intr_ids, wcd_mbhc_registers, true);
+ if (ret)
+ dev_err(codec->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ else
+ wcd_mbhc_start(&sdm660_cdc_priv->mbhc,
+ sdm660_cdc_priv->mbhc.mbhc_cfg);
+
+ return 0;
+}
+
+static int sdm660_cdc_notifier_service_cb(struct notifier_block *nb,
+ unsigned long opcode, void *ptr)
+{
+ struct snd_soc_codec *codec;
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ container_of(nb, struct sdm660_cdc_priv,
+ audio_ssr_nb);
+ bool adsp_ready = false;
+ bool timedout;
+ unsigned long timeout;
+
+ codec = sdm660_cdc_priv->codec;
+ dev_dbg(codec->dev, "%s: Service opcode 0x%lx\n", __func__, opcode);
+
+ switch (opcode) {
+ case AUDIO_NOTIFIER_SERVICE_DOWN:
+ dev_dbg(codec->dev,
+ "ADSP is about to power down. teardown/reset codec\n");
+ msm_anlg_cdc_device_down(codec);
+ break;
+ case AUDIO_NOTIFIER_SERVICE_UP:
+ if (initial_boot) {
+ initial_boot = false;
+ break;
+ }
+ dev_dbg(codec->dev,
+ "ADSP is about to power up. bring up codec\n");
+
+ if (!q6core_is_adsp_ready()) {
+ dev_dbg(codec->dev,
+ "ADSP isn't ready\n");
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+ while (!(timedout = time_after(jiffies, timeout))) {
+ if (!q6core_is_adsp_ready()) {
+ dev_dbg(codec->dev,
+ "ADSP isn't ready\n");
+ } else {
+ dev_dbg(codec->dev,
+ "ADSP is ready\n");
+ adsp_ready = true;
+ goto powerup;
+ }
+ }
+ } else {
+ adsp_ready = true;
+ dev_dbg(codec->dev, "%s: DSP is ready\n", __func__);
+ }
+powerup:
+ if (adsp_ready)
+ msm_anlg_cdc_device_up(codec);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+int msm_anlg_cdc_hs_detect(struct snd_soc_codec *codec,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ snd_soc_codec_get_drvdata(codec);
+
+ return wcd_mbhc_start(&sdm660_cdc_priv->mbhc, mbhc_cfg);
+}
+EXPORT_SYMBOL(msm_anlg_cdc_hs_detect);
+
+void msm_anlg_cdc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ snd_soc_codec_get_drvdata(codec);
+
+ wcd_mbhc_stop(&sdm660_cdc_priv->mbhc);
+}
+EXPORT_SYMBOL(msm_anlg_cdc_hs_detect_exit);
+
+void msm_anlg_cdc_update_int_spk_boost(bool enable)
+{
+ pr_debug("%s: enable = %d\n", __func__, enable);
+ spkr_boost_en = enable;
+}
+EXPORT_SYMBOL(msm_anlg_cdc_update_int_spk_boost);
+
+static void msm_anlg_cdc_set_micb_v(struct snd_soc_codec *codec)
+{
+
+ struct sdm660_cdc *sdm660_cdc = codec->control_data;
+ struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data;
+ u8 reg_val;
+
+ reg_val = VOLTAGE_CONVERTER(pdata->micbias.cfilt1_mv, MICBIAS_MIN_VAL,
+ MICBIAS_STEP_SIZE);
+ dev_dbg(codec->dev, "cfilt1_mv %d reg_val %x\n",
+ (u32)pdata->micbias.cfilt1_mv, reg_val);
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_VAL,
+ 0xF8, (reg_val << 3));
+}
+
+static void msm_anlg_cdc_set_boost_v(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE,
+ 0x1F, sdm660_cdc_priv->boost_voltage);
+}
+
+static void msm_anlg_cdc_configure_cap(struct snd_soc_codec *codec,
+ bool micbias1, bool micbias2)
+{
+
+ struct msm_asoc_mach_data *pdata = NULL;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+ pr_debug("\n %s: micbias1 %x micbias2 = %d\n", __func__, micbias1,
+ micbias2);
+ if (micbias1 && micbias2) {
+ if ((pdata->micbias1_cap_mode
+ == MICBIAS_EXT_BYP_CAP) ||
+ (pdata->micbias2_cap_mode
+ == MICBIAS_EXT_BYP_CAP))
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_1_EN,
+ 0x40, (MICBIAS_EXT_BYP_CAP << 6));
+ else
+ snd_soc_update_bits(codec,
+ MSM89XX_PMIC_ANALOG_MICB_1_EN,
+ 0x40, (MICBIAS_NO_EXT_BYP_CAP << 6));
+ } else if (micbias2) {
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+ 0x40, (pdata->micbias2_cap_mode << 6));
+ } else if (micbias1) {
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+ 0x40, (pdata->micbias1_cap_mode << 6));
+ } else {
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+ 0x40, 0x00);
+ }
+}
+
+static ssize_t msm_anlg_codec_version_read(struct snd_info_entry *entry,
+ void *file_private_data,
+ struct file *file,
+ char __user *buf, size_t count,
+ loff_t pos)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv;
+ char buffer[MSM_ANLG_CDC_VERSION_ENTRY_SIZE];
+ int len = 0;
+
+ sdm660_cdc_priv = (struct sdm660_cdc_priv *) entry->private_data;
+ if (!sdm660_cdc_priv) {
+ pr_err("%s: sdm660_cdc_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (get_codec_version(sdm660_cdc_priv)) {
+ case DRAX_CDC:
+ len = snprintf(buffer, sizeof(buffer), "DRAX-CDC_1_0\n");
+ break;
+ default:
+ len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+ }
+
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_anlg_codec_info_ops = {
+ .read = msm_anlg_codec_version_read,
+};
+
+/*
+ * msm_anlg_codec_info_create_codec_entry - creates pmic_analog module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates pmic_analog module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_anlg_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec)
+{
+ struct snd_info_entry *version_entry;
+ struct sdm660_cdc_priv *sdm660_cdc_priv;
+ struct snd_soc_card *card;
+ int ret;
+
+ if (!codec_root || !codec)
+ return -EINVAL;
+
+ sdm660_cdc_priv = snd_soc_codec_get_drvdata(codec);
+ card = codec->component.card;
+ sdm660_cdc_priv->entry = snd_register_module_info(codec_root->module,
+ "spmi0-03",
+ codec_root);
+ if (!sdm660_cdc_priv->entry) {
+ dev_dbg(codec->dev, "%s: failed to create pmic_analog entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry = snd_info_create_card_entry(card->snd_card,
+ "version",
+ sdm660_cdc_priv->entry);
+ if (!version_entry) {
+ dev_dbg(codec->dev, "%s: failed to create pmic_analog version entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry->private_data = sdm660_cdc_priv;
+ version_entry->size = MSM_ANLG_CDC_VERSION_ENTRY_SIZE;
+ version_entry->content = SNDRV_INFO_CONTENT_DATA;
+ version_entry->c.ops = &msm_anlg_codec_info_ops;
+
+ if (snd_info_register(version_entry) < 0) {
+ snd_info_free_entry(version_entry);
+ return -ENOMEM;
+ }
+ sdm660_cdc_priv->version_entry = version_entry;
+ if (is_ssr_en) {
+ sdm660_cdc_priv->audio_ssr_nb.notifier_call =
+ sdm660_cdc_notifier_service_cb;
+ ret = audio_notifier_register("pmic_analog_cdc",
+ AUDIO_NOTIFIER_ADSP_DOMAIN,
+ &sdm660_cdc_priv->audio_ssr_nb);
+ if (ret < 0) {
+ pr_err("%s: Audio notifier register failed ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(msm_anlg_codec_info_create_codec_entry);
+
+static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv;
+ struct sdm660_cdc *handle_cdc;
+ int ret;
+
+ sdm660_cdc_priv = devm_kzalloc(codec->dev,
+ sizeof(struct sdm660_cdc_priv),
+ GFP_KERNEL);
+ if (!sdm660_cdc_priv)
+ return -ENOMEM;
+
+ codec->control_data = dev_get_drvdata(codec->dev);
+ snd_soc_codec_set_drvdata(codec, sdm660_cdc_priv);
+ sdm660_cdc_priv->codec = codec;
+ handle_cdc = codec->control_data;
+ handle_cdc->codec = codec;
+
+ /* codec resmgr module init */
+ sdm660_cdc_priv->spkdrv_reg =
+ msm_anlg_cdc_find_regulator(codec->control_data,
+ MSM89XX_VDD_SPKDRV_NAME);
+ sdm660_cdc_priv->pmic_rev =
+ snd_soc_read(codec,
+ MSM89XX_PMIC_DIGITAL_REVISION1);
+ sdm660_cdc_priv->codec_version =
+ snd_soc_read(codec,
+ MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE);
+ sdm660_cdc_priv->analog_major_rev =
+ snd_soc_read(codec,
+ MSM89XX_PMIC_ANALOG_REVISION4);
+
+ if (sdm660_cdc_priv->codec_version == CONGA) {
+ dev_dbg(codec->dev, "%s :Conga REV: %d\n", __func__,
+ sdm660_cdc_priv->codec_version);
+ sdm660_cdc_priv->ext_spk_boost_set = true;
+ } else {
+ dev_dbg(codec->dev, "%s :PMIC REV: %d\n", __func__,
+ sdm660_cdc_priv->pmic_rev);
+ if (sdm660_cdc_priv->pmic_rev == TOMBAK_1_0 &&
+ sdm660_cdc_priv->codec_version == CAJON_2_0) {
+ if (sdm660_cdc_priv->analog_major_rev == 0x02) {
+ sdm660_cdc_priv->codec_version = DRAX_CDC;
+ dev_dbg(codec->dev,
+ "%s : Drax codec detected\n", __func__);
+ } else {
+ sdm660_cdc_priv->codec_version = DIANGU;
+ dev_dbg(codec->dev, "%s : Diangu detected\n",
+ __func__);
+ }
+ } else if (sdm660_cdc_priv->pmic_rev == TOMBAK_1_0 &&
+ (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
+ & 0x80)) {
+ sdm660_cdc_priv->codec_version = CAJON;
+ dev_dbg(codec->dev, "%s : Cajon detected\n", __func__);
+ } else if (sdm660_cdc_priv->pmic_rev == TOMBAK_2_0 &&
+ (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
+ & 0x80)) {
+ sdm660_cdc_priv->codec_version = CAJON_2_0;
+ dev_dbg(codec->dev, "%s : Cajon 2.0 detected\n",
+ __func__);
+ }
+ }
+ /*
+ * set to default boost option BOOST_SWITCH, user mixer path can change
+ * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen.
+ */
+ sdm660_cdc_priv->boost_option = BOOST_SWITCH;
+ sdm660_cdc_priv->hph_mode = NORMAL_MODE;
+
+ msm_anlg_cdc_dt_parse_boost_info(codec);
+ msm_anlg_cdc_set_boost_v(codec);
+
+ snd_soc_add_codec_controls(codec, impedance_detect_controls,
+ ARRAY_SIZE(impedance_detect_controls));
+ snd_soc_add_codec_controls(codec, hph_type_detect_controls,
+ ARRAY_SIZE(hph_type_detect_controls));
+
+ msm_anlg_cdc_bringup(codec);
+ msm_anlg_cdc_codec_init_cache(codec);
+ msm_anlg_cdc_codec_init_reg(codec);
+ msm_anlg_cdc_update_reg_defaults(codec);
+
+ wcd9xxx_spmi_set_codec(codec);
+
+ sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
+ msm_anlg_cdc_find_regulator(
+ codec->control_data,
+ on_demand_supply_name[ON_DEMAND_MICBIAS]);
+ atomic_set(&sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].ref,
+ 0);
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc_priv->notifier);
+
+ sdm660_cdc_priv->fw_data = devm_kzalloc(codec->dev,
+ sizeof(*(sdm660_cdc_priv->fw_data)),
+ GFP_KERNEL);
+ if (!sdm660_cdc_priv->fw_data)
+ return -ENOMEM;
+
+ set_bit(WCD9XXX_MBHC_CAL, sdm660_cdc_priv->fw_data->cal_bit);
+ ret = wcd_cal_create_hwdep(sdm660_cdc_priv->fw_data,
+ WCD9XXX_CODEC_HWDEP_NODE, codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ wcd_mbhc_init(&sdm660_cdc_priv->mbhc, codec, &mbhc_cb, &intr_ids,
+ wcd_mbhc_registers, true);
+
+ sdm660_cdc_priv->int_mclk0_enabled = false;
+ /*Update speaker boost configuration*/
+ sdm660_cdc_priv->spk_boost_set = spkr_boost_en;
+ pr_debug("%s: speaker boost configured = %d\n",
+ __func__, sdm660_cdc_priv->spk_boost_set);
+
+ /* Set initial MICBIAS voltage level */
+ msm_anlg_cdc_set_micb_v(codec);
+
+ /* Set initial cap mode */
+ msm_anlg_cdc_configure_cap(codec, false, false);
+ return 0;
+}
+
+static int msm_anlg_cdc_soc_remove(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ snd_soc_codec_get_drvdata(codec);
+
+ sdm660_cdc_priv->spkdrv_reg = NULL;
+ sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
+ atomic_set(&sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].ref,
+ 0);
+ wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc);
+
+ return 0;
+}
+
+static int msm_anlg_cdc_enable_static_supplies_to_optimum(
+ struct sdm660_cdc *sdm660_cdc,
+ struct sdm660_cdc_pdata *pdata)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+ if (pdata->regulator[i].ondemand)
+ continue;
+ if (regulator_count_voltages(
+ sdm660_cdc->supplies[i].consumer) <= 0)
+ continue;
+
+ ret = regulator_set_voltage(
+ sdm660_cdc->supplies[i].consumer,
+ pdata->regulator[i].min_uv,
+ pdata->regulator[i].max_uv);
+ if (ret) {
+ dev_err(sdm660_cdc->dev,
+ "Setting volt failed for regulator %s err %d\n",
+ sdm660_cdc->supplies[i].supply, ret);
+ }
+
+ ret = regulator_set_load(sdm660_cdc->supplies[i].consumer,
+ pdata->regulator[i].optimum_ua);
+ dev_dbg(sdm660_cdc->dev, "Regulator %s set optimum mode\n",
+ sdm660_cdc->supplies[i].supply);
+ }
+
+ return ret;
+}
+
+static int msm_anlg_cdc_disable_static_supplies_to_optimum(
+ struct sdm660_cdc *sdm660_cdc,
+ struct sdm660_cdc_pdata *pdata)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+ if (pdata->regulator[i].ondemand)
+ continue;
+ if (regulator_count_voltages(
+ sdm660_cdc->supplies[i].consumer) <= 0)
+ continue;
+ regulator_set_voltage(sdm660_cdc->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uv);
+ regulator_set_load(sdm660_cdc->supplies[i].consumer, 0);
+ dev_dbg(sdm660_cdc->dev, "Regulator %s set optimum mode\n",
+ sdm660_cdc->supplies[i].supply);
+ }
+
+ return ret;
+}
+
+static int msm_anlg_cdc_suspend(struct snd_soc_codec *codec)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct sdm660_cdc *sdm660_cdc = codec->control_data;
+ struct sdm660_cdc_pdata *sdm660_cdc_pdata =
+ sdm660_cdc->dev->platform_data;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n",
+ __func__, atomic_read(&pdata->int_mclk0_rsc_ref),
+ atomic_read(&pdata->int_mclk0_enabled));
+ if (atomic_read(&pdata->int_mclk0_enabled) == true) {
+ cancel_delayed_work_sync(&pdata->disable_int_mclk0_work);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ pdata->digital_cdc_core_clk.enable = 0;
+ afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ }
+ msm_anlg_cdc_disable_static_supplies_to_optimum(sdm660_cdc,
+ sdm660_cdc_pdata);
+ return 0;
+}
+
+static int msm_anlg_cdc_resume(struct snd_soc_codec *codec)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct sdm660_cdc *sdm660_cdc = codec->control_data;
+ struct sdm660_cdc_pdata *sdm660_cdc_pdata =
+ sdm660_cdc->dev->platform_data;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ msm_anlg_cdc_enable_static_supplies_to_optimum(sdm660_cdc,
+ sdm660_cdc_pdata);
+ return 0;
+}
+
+static struct regmap *msm_anlg_get_regmap(struct device *dev)
+{
+ return dev_get_regmap(dev->parent, NULL);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sdm660_cdc = {
+ .probe = msm_anlg_cdc_soc_probe,
+ .remove = msm_anlg_cdc_soc_remove,
+ .suspend = msm_anlg_cdc_suspend,
+ .resume = msm_anlg_cdc_resume,
+ .reg_word_size = 1,
+ .controls = msm_anlg_cdc_snd_controls,
+ .num_controls = ARRAY_SIZE(msm_anlg_cdc_snd_controls),
+ .dapm_widgets = msm_anlg_cdc_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(msm_anlg_cdc_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+ .get_regmap = msm_anlg_get_regmap,
+};
+
+static int msm_anlg_cdc_init_supplies(struct sdm660_cdc *sdm660_cdc,
+ struct sdm660_cdc_pdata *pdata)
+{
+ int ret;
+ int i;
+
+ sdm660_cdc->supplies = devm_kzalloc(sdm660_cdc->dev,
+ sizeof(struct regulator_bulk_data) *
+ ARRAY_SIZE(pdata->regulator),
+ GFP_KERNEL);
+ if (!sdm660_cdc->supplies) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ sdm660_cdc->num_of_supplies = 0;
+ if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+ dev_err(sdm660_cdc->dev, "%s: Array Size out of bound\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (pdata->regulator[i].name) {
+ sdm660_cdc->supplies[i].supply =
+ pdata->regulator[i].name;
+ sdm660_cdc->num_of_supplies++;
+ }
+ }
+
+ ret = devm_regulator_bulk_get(sdm660_cdc->dev,
+ sdm660_cdc->num_of_supplies,
+ sdm660_cdc->supplies);
+ if (ret != 0) {
+ dev_err(sdm660_cdc->dev,
+ "Failed to get supplies: err = %d\n",
+ ret);
+ goto err_supplies;
+ }
+
+ for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+ if (regulator_count_voltages(
+ sdm660_cdc->supplies[i].consumer) <= 0)
+ continue;
+ ret = regulator_set_voltage(sdm660_cdc->supplies[i].consumer,
+ pdata->regulator[i].min_uv,
+ pdata->regulator[i].max_uv);
+ if (ret) {
+ dev_err(sdm660_cdc->dev,
+ "Setting regulator voltage failed for regulator %s err = %d\n",
+ sdm660_cdc->supplies[i].supply, ret);
+ goto err_supplies;
+ }
+ ret = regulator_set_load(sdm660_cdc->supplies[i].consumer,
+ pdata->regulator[i].optimum_ua);
+ if (ret < 0) {
+ dev_err(sdm660_cdc->dev,
+ "Setting regulator optimum mode failed for regulator %s err = %d\n",
+ sdm660_cdc->supplies[i].supply, ret);
+ goto err_supplies;
+ } else {
+ ret = 0;
+ }
+ }
+
+ return ret;
+
+err_supplies:
+ kfree(sdm660_cdc->supplies);
+err:
+ return ret;
+}
+
+static int msm_anlg_cdc_enable_static_supplies(
+ struct sdm660_cdc *sdm660_cdc,
+ struct sdm660_cdc_pdata *pdata)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+ if (pdata->regulator[i].ondemand)
+ continue;
+ ret = regulator_enable(sdm660_cdc->supplies[i].consumer);
+ if (ret) {
+ dev_err(sdm660_cdc->dev, "Failed to enable %s\n",
+ sdm660_cdc->supplies[i].supply);
+ break;
+ }
+ dev_dbg(sdm660_cdc->dev, "Enabled regulator %s\n",
+ sdm660_cdc->supplies[i].supply);
+ }
+
+ while (ret && --i)
+ if (!pdata->regulator[i].ondemand)
+ regulator_disable(sdm660_cdc->supplies[i].consumer);
+ return ret;
+}
+
+static void msm_anlg_cdc_disable_supplies(struct sdm660_cdc *sdm660_cdc,
+ struct sdm660_cdc_pdata *pdata)
+{
+ int i;
+
+ regulator_bulk_disable(sdm660_cdc->num_of_supplies,
+ sdm660_cdc->supplies);
+ for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+ if (regulator_count_voltages(
+ sdm660_cdc->supplies[i].consumer) <= 0)
+ continue;
+ regulator_set_voltage(sdm660_cdc->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uv);
+ regulator_set_load(sdm660_cdc->supplies[i].consumer, 0);
+ }
+ regulator_bulk_free(sdm660_cdc->num_of_supplies,
+ sdm660_cdc->supplies);
+ kfree(sdm660_cdc->supplies);
+}
+
+static const struct of_device_id sdm660_codec_of_match[] = {
+ { .compatible = "qcom,pmic-analog-codec", },
+ {},
+};
+
+static void msm_anlg_add_child_devices(struct work_struct *work)
+{
+ struct sdm660_cdc *pdata;
+ struct platform_device *pdev;
+ struct device_node *node;
+ struct msm_dig_ctrl_data *dig_ctrl_data = NULL, *temp;
+ int ret, ctrl_num = 0;
+ struct msm_dig_ctrl_platform_data *platdata;
+ char plat_dev_name[MSM_DIG_CDC_STRING_LEN];
+
+ pdata = container_of(work, struct sdm660_cdc,
+ msm_anlg_add_child_devices_work);
+ if (!pdata) {
+ pr_err("%s: Memory for pdata does not exist\n",
+ __func__);
+ return;
+ }
+ if (!pdata->dev->of_node) {
+ dev_err(pdata->dev,
+ "%s: DT node for pdata does not exist\n", __func__);
+ return;
+ }
+
+ platdata = &pdata->dig_plat_data;
+
+ for_each_child_of_node(pdata->dev->of_node, node) {
+ if (!strcmp(node->name, "msm-dig-codec"))
+ strlcpy(plat_dev_name, "msm_digital_codec",
+ (MSM_DIG_CDC_STRING_LEN - 1));
+ else
+ continue;
+
+ pdev = platform_device_alloc(plat_dev_name, -1);
+ if (!pdev) {
+ dev_err(pdata->dev, "%s: pdev memory alloc failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+ pdev->dev.parent = pdata->dev;
+ pdev->dev.of_node = node;
+
+ if (!strcmp(node->name, "msm-dig-codec")) {
+ ret = platform_device_add_data(pdev, platdata,
+ sizeof(*platdata));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: cannot add plat data ctrl:%d\n",
+ __func__, ctrl_num);
+ goto fail_pdev_add;
+ }
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Cannot add platform device\n",
+ __func__);
+ goto fail_pdev_add;
+ }
+
+ if (!strcmp(node->name, "msm-dig-codec")) {
+ temp = krealloc(dig_ctrl_data,
+ (ctrl_num + 1) * sizeof(
+ struct msm_dig_ctrl_data),
+ GFP_KERNEL);
+ if (!temp) {
+ dev_err(&pdev->dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ dig_ctrl_data = temp;
+ dig_ctrl_data[ctrl_num].dig_pdev = pdev;
+ ctrl_num++;
+ dev_dbg(&pdev->dev,
+ "%s: Added digital codec device(s)\n",
+ __func__);
+ pdata->dig_ctrl_data = dig_ctrl_data;
+ }
+ }
+
+ return;
+fail_pdev_add:
+ platform_device_put(pdev);
+err:
+ return;
+}
+
+static int msm_anlg_cdc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct sdm660_cdc *sdm660_cdc = NULL;
+ struct sdm660_cdc_pdata *pdata;
+ int adsp_state;
+
+ adsp_state = apr_get_subsys_state();
+ if (adsp_state != APR_SUBSYS_LOADED) {
+ dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
+ adsp_state);
+ return -EPROBE_DEFER;
+ }
+ device_init_wakeup(&pdev->dev, true);
+
+ if (pdev->dev.of_node) {
+ dev_dbg(&pdev->dev, "%s:Platform data from device tree\n",
+ __func__);
+ pdata = msm_anlg_cdc_populate_dt_pdata(&pdev->dev);
+ pdev->dev.platform_data = pdata;
+ } else {
+ dev_dbg(&pdev->dev, "%s:Platform data from board file\n",
+ __func__);
+ pdata = pdev->dev.platform_data;
+ }
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "%s:Platform data failed to populate\n",
+ __func__);
+ goto rtn;
+ }
+ sdm660_cdc = devm_kzalloc(&pdev->dev, sizeof(struct sdm660_cdc),
+ GFP_KERNEL);
+ if (sdm660_cdc == NULL) {
+ ret = -ENOMEM;
+ goto rtn;
+ }
+
+ sdm660_cdc->dev = &pdev->dev;
+ ret = msm_anlg_cdc_init_supplies(sdm660_cdc, pdata);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Fail to enable Codec supplies\n",
+ __func__);
+ goto rtn;
+ }
+ ret = msm_anlg_cdc_enable_static_supplies(sdm660_cdc, pdata);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Fail to enable Codec pre-reset supplies\n",
+ __func__);
+ goto rtn;
+ }
+ /* Allow supplies to be ready */
+ usleep_range(5, 6);
+
+ dev_set_drvdata(&pdev->dev, sdm660_cdc);
+ wcd9xxx_spmi_set_dev(pdev, 0);
+ wcd9xxx_spmi_set_dev(pdev, 1);
+ if (wcd9xxx_spmi_irq_init()) {
+ dev_err(&pdev->dev,
+ "%s: irq initialization failed\n", __func__);
+ } else {
+ dev_dbg(&pdev->dev,
+ "%s: irq initialization passed\n", __func__);
+ }
+
+ ret = snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_sdm660_cdc,
+ msm_anlg_cdc_i2s_dai,
+ ARRAY_SIZE(msm_anlg_cdc_i2s_dai));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s:snd_soc_register_codec failed with error %d\n",
+ __func__, ret);
+ goto err_supplies;
+ }
+ sdm660_cdc->dig_plat_data.handle = (void *) sdm660_cdc;
+ sdm660_cdc->dig_plat_data.update_clkdiv = update_clkdiv;
+ sdm660_cdc->dig_plat_data.get_cdc_version = get_cdc_version;
+ sdm660_cdc->dig_plat_data.register_notifier =
+ msm_anlg_cdc_dig_register_notifier;
+ INIT_WORK(&sdm660_cdc->msm_anlg_add_child_devices_work,
+ msm_anlg_add_child_devices);
+ schedule_work(&sdm660_cdc->msm_anlg_add_child_devices_work);
+
+ return ret;
+err_supplies:
+ msm_anlg_cdc_disable_supplies(sdm660_cdc, pdata);
+rtn:
+ return ret;
+}
+
+static int msm_anlg_cdc_remove(struct platform_device *pdev)
+{
+ struct sdm660_cdc *sdm660_cdc = dev_get_drvdata(&pdev->dev);
+ struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data;
+
+ snd_soc_unregister_codec(&pdev->dev);
+ msm_anlg_cdc_disable_supplies(sdm660_cdc, pdata);
+ return 0;
+}
+
+static struct platform_driver msm_anlg_codec_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(sdm660_codec_of_match)
+ },
+ .probe = msm_anlg_cdc_probe,
+ .remove = msm_anlg_cdc_remove,
+};
+module_platform_driver(msm_anlg_codec_driver);
+
+MODULE_DESCRIPTION("MSM Audio Analog codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h
new file mode 100644
index 0000000..bb3af57
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h
@@ -0,0 +1,240 @@
+/* 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_ANALOG_CDC_H
+#define MSM_ANALOG_CDC_H
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
+#include "../wcd-mbhc-v2.h"
+#include "../wcdcal-hwdep.h"
+#include "sdm660-cdc-registers.h"
+
+#define MICBIAS_EXT_BYP_CAP 0x00
+#define MICBIAS_NO_EXT_BYP_CAP 0x01
+
+#define MSM89XX_NUM_IRQ_REGS 2
+#define MAX_REGULATOR 7
+#define MSM89XX_REG_VAL(reg, val) {reg, 0, val}
+
+#define MSM89XX_VDD_SPKDRV_NAME "cdc-vdd-spkdrv"
+
+#define DEFAULT_MULTIPLIER 800
+#define DEFAULT_GAIN 9
+#define DEFAULT_OFFSET 100
+
+extern const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE];
+extern const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE];
+extern struct regmap_config msm89xx_cdc_core_regmap_config;
+extern struct regmap_config msm89xx_pmic_cdc_regmap_config;
+
+enum wcd_curr_ref {
+ I_h4_UA = 0,
+ I_pt5_UA,
+ I_14_UA,
+ I_l4_UA,
+ I_1_UA,
+};
+
+enum wcd_mbhc_imp_det_pin {
+ WCD_MBHC_DET_NONE = 0,
+ WCD_MBHC_DET_HPHL,
+ WCD_MBHC_DET_HPHR,
+ WCD_MBHC_DET_BOTH,
+};
+
+
+/* Each micbias can be assigned to one of three cfilters
+ * Vbatt_min >= .15V + ldoh_v
+ * ldoh_v >= .15v + cfiltx_mv
+ * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
+ * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
+ * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
+ * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
+ */
+
+struct wcd_micbias_setting {
+ u8 ldoh_v;
+ u32 cfilt1_mv; /* in mv */
+ u32 cfilt2_mv; /* in mv */
+ u32 cfilt3_mv; /* in mv */
+ /* Different WCD9xxx series codecs may not
+ * have 4 mic biases. If a codec has fewer
+ * mic biases, some of these properties will
+ * not be used.
+ */
+ u8 bias1_cfilt_sel;
+ u8 bias2_cfilt_sel;
+ u8 bias3_cfilt_sel;
+ u8 bias4_cfilt_sel;
+ u8 bias1_cap_mode;
+ u8 bias2_cap_mode;
+ u8 bias3_cap_mode;
+ u8 bias4_cap_mode;
+ bool bias2_is_headset_only;
+};
+
+enum sdm660_cdc_pid_current {
+ MSM89XX_PID_MIC_2P5_UA,
+ MSM89XX_PID_MIC_5_UA,
+ MSM89XX_PID_MIC_10_UA,
+ MSM89XX_PID_MIC_20_UA,
+};
+
+struct sdm660_cdc_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
+enum {
+ /* INTR_REG 0 - Digital Periph */
+ MSM89XX_IRQ_SPKR_CNP = 0,
+ MSM89XX_IRQ_SPKR_CLIP,
+ MSM89XX_IRQ_SPKR_OCP,
+ MSM89XX_IRQ_MBHC_INSREM_DET1,
+ MSM89XX_IRQ_MBHC_RELEASE,
+ MSM89XX_IRQ_MBHC_PRESS,
+ MSM89XX_IRQ_MBHC_INSREM_DET,
+ MSM89XX_IRQ_MBHC_HS_DET,
+ /* INTR_REG 1 - Analog Periph */
+ MSM89XX_IRQ_EAR_OCP,
+ MSM89XX_IRQ_HPHR_OCP,
+ MSM89XX_IRQ_HPHL_OCP,
+ MSM89XX_IRQ_EAR_CNP,
+ MSM89XX_IRQ_HPHR_CNP,
+ MSM89XX_IRQ_HPHL_CNP,
+ MSM89XX_NUM_IRQS,
+};
+
+enum {
+ ON_DEMAND_MICBIAS = 0,
+ ON_DEMAND_SPKDRV,
+ ON_DEMAND_SUPPLIES_MAX,
+};
+
+/*
+ * The delay list is per codec HW specification.
+ * Please add delay in the list in the future instead
+ * of magic number
+ */
+enum {
+ CODEC_DELAY_1_MS = 1000,
+ CODEC_DELAY_1_1_MS = 1100,
+};
+
+struct sdm660_cdc_regulator {
+ const char *name;
+ int min_uv;
+ int max_uv;
+ int optimum_ua;
+ bool ondemand;
+ struct regulator *regulator;
+};
+
+struct on_demand_supply {
+ struct regulator *supply;
+ atomic_t ref;
+};
+
+struct wcd_imped_i_ref {
+ enum wcd_curr_ref curr_ref;
+ int min_val;
+ int multiplier;
+ int gain_adj;
+ int offset;
+};
+
+enum sdm660_cdc_micbias_num {
+ MSM89XX_MICBIAS1 = 0,
+};
+
+/* Hold instance to digital codec platform device */
+struct msm_dig_ctrl_data {
+ struct platform_device *dig_pdev;
+};
+
+struct msm_dig_ctrl_platform_data {
+ void *handle;
+ void (*update_clkdiv)(void *handle, int val);
+ int (*get_cdc_version)(void *handle);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+};
+
+struct sdm660_cdc {
+ struct device *dev;
+ u32 num_of_supplies;
+ struct regulator_bulk_data *supplies;
+ struct snd_soc_codec *codec;
+ struct work_struct msm_anlg_add_child_devices_work;
+ struct msm_dig_ctrl_platform_data dig_plat_data;
+ /* digital codec data structure */
+ struct msm_dig_ctrl_data *dig_ctrl_data;
+ struct blocking_notifier_head notifier;
+};
+
+struct sdm660_cdc_pdata {
+ struct wcd_micbias_setting micbias;
+ struct sdm660_cdc_regulator regulator[MAX_REGULATOR];
+};
+
+struct sdm660_cdc_priv {
+ struct snd_soc_codec *codec;
+ u16 pmic_rev;
+ u16 codec_version;
+ u16 analog_major_rev;
+ u32 boost_voltage;
+ u32 adc_count;
+ u32 rx_bias_count;
+ bool int_mclk0_enabled;
+ u16 boost_option;
+ /* mode to select hd2 */
+ u32 hph_mode;
+ /* compander used for each rx chain */
+ bool spk_boost_set;
+ bool ear_pa_boost_set;
+ bool ext_spk_boost_set;
+ struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
+ struct regulator *spkdrv_reg;
+ struct blocking_notifier_head notifier;
+ /* mbhc module */
+ struct wcd_mbhc mbhc;
+ /* cal info for codec */
+ struct fw_info *fw_data;
+ struct notifier_block audio_ssr_nb;
+ int (*codec_spk_ext_pa_cb)(struct snd_soc_codec *codec, int enable);
+ unsigned long status_mask;
+ struct wcd_imped_i_ref imped_i_ref;
+ enum wcd_mbhc_imp_det_pin imped_det_pin;
+ /* Entry for version info */
+ struct snd_info_entry *entry;
+ struct snd_info_entry *version_entry;
+};
+
+extern int msm_anlg_cdc_mclk_enable(struct snd_soc_codec *codec,
+ int mclk_enable, bool dapm);
+
+extern int msm_anlg_cdc_hs_detect(struct snd_soc_codec *codec,
+ struct wcd_mbhc_config *mbhc_cfg);
+
+extern void msm_anlg_cdc_hs_detect_exit(struct snd_soc_codec *codec);
+
+extern void sdm660_cdc_update_int_spk_boost(bool enable);
+
+extern void msm_anlg_cdc_spk_ext_pa_cb(
+ int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
+ int enable), struct snd_soc_codec *codec);
+int msm_anlg_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec);
+#endif
diff --git a/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
new file mode 100644
index 0000000..95dbc76
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
@@ -0,0 +1,66 @@
+/* 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/regmap.h>
+#include "sdm660-cdc-registers.h"
+
+extern struct reg_default
+ msm89xx_cdc_core_defaults[MSM89XX_CDC_CORE_CACHE_SIZE];
+extern struct reg_default
+ msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE];
+
+bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg);
+bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg);
+
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ AIF2_VIFEED,
+ AIF3_SVA,
+ NUM_CODEC_DAIS,
+};
+
+enum codec_versions {
+ TOMBAK_1_0,
+ TOMBAK_2_0,
+ CONGA,
+ CAJON,
+ CAJON_2_0,
+ DIANGU,
+ DRAX_CDC,
+ UNSUPPORTED,
+};
+
+/* Support different hph modes */
+enum {
+ NORMAL_MODE = 0,
+ HD2_MODE,
+};
+
+enum dig_cdc_notify_event {
+ DIG_CDC_EVENT_INVALID,
+ DIG_CDC_EVENT_CLK_ON,
+ DIG_CDC_EVENT_CLK_OFF,
+ DIG_CDC_EVENT_RX1_MUTE_ON,
+ DIG_CDC_EVENT_RX1_MUTE_OFF,
+ DIG_CDC_EVENT_RX2_MUTE_ON,
+ DIG_CDC_EVENT_RX2_MUTE_OFF,
+ DIG_CDC_EVENT_RX3_MUTE_ON,
+ DIG_CDC_EVENT_RX3_MUTE_OFF,
+ DIG_CDC_EVENT_PRE_RX1_INT_ON,
+ DIG_CDC_EVENT_PRE_RX2_INT_ON,
+ DIG_CDC_EVENT_POST_RX1_INT_OFF,
+ DIG_CDC_EVENT_POST_RX2_INT_OFF,
+ DIG_CDC_EVENT_SSR_DOWN,
+ DIG_CDC_EVENT_SSR_UP,
+ DIG_CDC_EVENT_LAST,
+};
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
new file mode 100644
index 0000000..08f5556
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -0,0 +1,2075 @@
+/* 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/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <sound/q6afe-v2.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "sdm660-cdc-registers.h"
+#include "msm-digital-cdc.h"
+#include "msm-cdc-common.h"
+#include "../../msm/sdm660-common.h"
+
+#define DRV_NAME "msm_digital_codec"
+#define MCLK_RATE_9P6MHZ 9600000
+#define MCLK_RATE_12P288MHZ 12288000
+#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
+#define CF_MIN_3DB_4HZ 0x0
+#define CF_MIN_3DB_75HZ 0x1
+#define CF_MIN_3DB_150HZ 0x2
+
+#define MSM_DIG_CDC_VERSION_ENTRY_SIZE 32
+
+static unsigned long rx_digital_gain_reg[] = {
+ MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
+ MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
+ MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
+};
+
+static unsigned long tx_digital_gain_reg[] = {
+ MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
+ MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
+ MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN,
+ MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN,
+ MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+
+struct snd_soc_codec *registered_digcodec;
+struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+
+/* Codec supports 2 IIR filters */
+enum {
+ IIR1 = 0,
+ IIR2,
+ IIR_MAX,
+};
+
+static int msm_digcdc_clock_control(bool flag)
+{
+ int ret = -EINVAL;
+ struct msm_asoc_mach_data *pdata = NULL;
+
+ pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card);
+
+ if (flag) {
+ if (atomic_read(&pdata->int_mclk0_enabled) == false) {
+ pdata->digital_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s:failed to enable the MCLK\n",
+ __func__);
+ return ret;
+ }
+ pr_debug("enabled digital codec core clk\n");
+ atomic_set(&pdata->int_mclk0_enabled, true);
+ schedule_delayed_work(&pdata->disable_int_mclk0_work,
+ 50);
+ }
+ } else {
+ dev_dbg(registered_digcodec->dev,
+ "disable MCLK, workq to disable set already\n");
+ }
+ return 0;
+}
+
+static void enable_digital_callback(void *flag)
+{
+ msm_digcdc_clock_control(true);
+}
+
+static void disable_digital_callback(void *flag)
+{
+ pr_debug("disable mclk happens in workq\n");
+}
+
+static int msm_dig_cdc_put_dec_enum(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 *w = wlist->widgets[0];
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int dec_mux, decimator;
+ char *dec_name = NULL;
+ char *widget_name = NULL;
+ char *temp;
+ u16 tx_mux_ctl_reg;
+ u8 adc_dmic_sel = 0x0;
+ int ret = 0;
+ char *dec_num;
+
+ if (ucontrol->value.enumerated.item[0] > e->items) {
+ dev_err(codec->dev, "%s: Invalid enum value: %d\n",
+ __func__, ucontrol->value.enumerated.item[0]);
+ return -EINVAL;
+ }
+ dec_mux = ucontrol->value.enumerated.item[0];
+
+ widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!widget_name) {
+ dev_err(codec->dev, "%s: failed to copy string\n",
+ __func__);
+ return -ENOMEM;
+ }
+ temp = widget_name;
+
+ dec_name = strsep(&widget_name, " ");
+ widget_name = temp;
+ if (!dec_name) {
+ dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+ __func__, w->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dec_num = strpbrk(dec_name, "12345");
+ if (dec_num == NULL) {
+ dev_err(codec->dev, "%s: Invalid DEC selected\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = kstrtouint(dec_num, 10, &decimator);
+ if (ret < 0) {
+ dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+ __func__, dec_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
+ , __func__, w->name, decimator, dec_mux);
+
+ switch (decimator) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ if ((dec_mux == 4) || (dec_mux == 5) ||
+ (dec_mux == 6) || (dec_mux == 7))
+ adc_dmic_sel = 0x1;
+ else
+ adc_dmic_sel = 0x0;
+ break;
+ default:
+ dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
+ __func__, decimator);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tx_mux_ctl_reg =
+ MSM89XX_CDC_CORE_TX1_MUX_CTL + 32 * (decimator - 1);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+out:
+ kfree(widget_name);
+ return ret;
+}
+
+
+static int msm_dig_cdc_codec_config_compander(struct snd_soc_codec *codec,
+ int interp_n, int event)
+{
+ struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n",
+ __func__, event, interp_n,
+ dig_cdc->comp_enabled[interp_n]);
+
+ /* compander is not enabled */
+ if (!dig_cdc->comp_enabled[interp_n])
+ return 0;
+
+ switch (dig_cdc->comp_enabled[interp_n]) {
+ case COMPANDER_1:
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ /* Enable Compander Clock */
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_COMP0_B1_CTL,
+ 1 << interp_n, 1 << interp_n);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50);
+ /* add sleep for compander to settle */
+ usleep_range(1000, 1100);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0);
+
+ /* Enable Compander GPIO */
+ if (dig_cdc->codec_hph_comp_gpio)
+ dig_cdc->codec_hph_comp_gpio(1, codec);
+ } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ /* Disable Compander GPIO */
+ if (dig_cdc->codec_hph_comp_gpio)
+ dig_cdc->codec_hph_comp_gpio(0, codec);
+
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_COMP0_B1_CTL,
+ 1 << interp_n, 0);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00);
+ }
+ break;
+ default:
+ dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__,
+ dig_cdc->comp_enabled[interp_n]);
+ break;
+ };
+
+ return 0;
+}
+
+/**
+ * msm_dig_cdc_hph_comp_cb - registers callback to codec by machine driver.
+ *
+ * @codec_hph_comp_gpio: function pointer to set comp gpio at machine driver
+ * @codec: codec pointer
+ *
+ */
+void msm_dig_cdc_hph_comp_cb(
+ int (*codec_hph_comp_gpio)(bool enable, struct snd_soc_codec *codec),
+ struct snd_soc_codec *codec)
+{
+ struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: Enter\n", __func__);
+ dig_cdc->codec_hph_comp_gpio = codec_hph_comp_gpio;
+}
+EXPORT_SYMBOL(msm_dig_cdc_hph_comp_cb);
+
+static int msm_dig_cdc_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct msm_dig *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+ dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+ if (w->shift >= MSM89XX_RX_MAX || w->shift < 0) {
+ dev_err(codec->dev, "%s: wrong RX index: %d\n",
+ __func__, w->shift);
+ return -EINVAL;
+ }
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msm_dig_cdc_codec_config_compander(codec, w->shift, event);
+ /* apply the digital gain after the interpolator is enabled*/
+ if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
+ snd_soc_write(codec,
+ rx_digital_gain_reg[w->shift],
+ snd_soc_read(codec,
+ rx_digital_gain_reg[w->shift])
+ );
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ msm_dig_cdc_codec_config_compander(codec, w->shift, event);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
+ 1 << w->shift, 1 << w->shift);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
+ 1 << w->shift, 0x0);
+ /*
+ * disable the mute enabled during the PMD of this device
+ */
+ if ((w->shift == 0) &&
+ (msm_dig_cdc->mute_mask & HPHL_PA_DISABLE)) {
+ pr_debug("disabling HPHL mute\n");
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
+ msm_dig_cdc->mute_mask &= ~(HPHL_PA_DISABLE);
+ } else if ((w->shift == 1) &&
+ (msm_dig_cdc->mute_mask & HPHR_PA_DISABLE)) {
+ pr_debug("disabling HPHR mute\n");
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
+ msm_dig_cdc->mute_mask &= ~(HPHR_PA_DISABLE);
+ } else if ((w->shift == 2) &&
+ (msm_dig_cdc->mute_mask & SPKR_PA_DISABLE)) {
+ pr_debug("disabling SPKR mute\n");
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
+ msm_dig_cdc->mute_mask &= ~(SPKR_PA_DISABLE);
+ }
+ }
+ return 0;
+}
+
+static int msm_dig_cdc_get_iir_enable_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ (snd_soc_read(codec,
+ (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
+ (1 << band_idx)) != 0;
+
+ dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_dig_cdc_put_iir_enable_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ /* Mask first 5 bits, 6-8 are reserved */
+ snd_soc_update_bits(codec,
+ (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx),
+ (1 << band_idx), (value << band_idx));
+
+ dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx,
+ ((snd_soc_read(codec,
+ (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
+ (1 << band_idx)) != 0));
+
+ return 0;
+}
+
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+ int iir_idx, int band_idx,
+ int coeff_idx)
+{
+ uint32_t value = 0;
+
+ /* Address does not automatically update if reading */
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t)) & 0x7F);
+
+ value |= snd_soc_read(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx));
+
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 1) & 0x7F);
+
+ value |= (snd_soc_read(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
+
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 2) & 0x7F);
+
+ value |= (snd_soc_read(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
+
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 3) & 0x7F);
+
+ /* Mask bits top 2 bits since they are reserved */
+ value |= ((snd_soc_read(codec, (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL
+ + 64 * iir_idx)) & 0x3f) << 24);
+
+ return value;
+
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+ int iir_idx, int band_idx,
+ uint32_t value)
+{
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+ (value & 0xFF));
+
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+ (value >> 8) & 0xFF);
+
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+ (value >> 16) & 0xFF);
+
+ /* Mask top 2 bits, 7-8 are reserved */
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+ (value >> 24) & 0x3F);
+
+}
+
+static int msm_dig_cdc_get_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+ ucontrol->value.integer.value[1] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+ ucontrol->value.integer.value[2] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+ ucontrol->value.integer.value[3] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+ ucontrol->value.integer.value[4] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+ dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
+ "%s: IIR #%d band #%d b1 = 0x%x\n"
+ "%s: IIR #%d band #%d b2 = 0x%x\n"
+ "%s: IIR #%d band #%d a1 = 0x%x\n"
+ "%s: IIR #%d band #%d a2 = 0x%x\n",
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[0],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[1],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[2],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[3],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[4]);
+ return 0;
+}
+
+static int msm_dig_cdc_put_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ /* Mask top bit it is reserved */
+ /* Updates addr automatically for each B2 write */
+ snd_soc_write(codec,
+ (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+ (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+
+ set_iir_band_coeff(codec, iir_idx, band_idx,
+ ucontrol->value.integer.value[0]);
+ set_iir_band_coeff(codec, iir_idx, band_idx,
+ ucontrol->value.integer.value[1]);
+ set_iir_band_coeff(codec, iir_idx, band_idx,
+ ucontrol->value.integer.value[2]);
+ set_iir_band_coeff(codec, iir_idx, band_idx,
+ ucontrol->value.integer.value[3]);
+ set_iir_band_coeff(codec, iir_idx, band_idx,
+ ucontrol->value.integer.value[4]);
+
+ dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
+ "%s: IIR #%d band #%d b1 = 0x%x\n"
+ "%s: IIR #%d band #%d b2 = 0x%x\n"
+ "%s: IIR #%d band #%d a1 = 0x%x\n"
+ "%s: IIR #%d band #%d a2 = 0x%x\n",
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+ return 0;
+}
+
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+ struct delayed_work *hpf_delayed_work;
+ struct hpf_work *hpf_work;
+ struct snd_soc_codec *codec;
+ struct msm_dig *msm_dig_cdc;
+ u16 tx_mux_ctl_reg;
+ u8 hpf_cut_of_freq;
+
+ hpf_delayed_work = to_delayed_work(work);
+ hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+ codec = hpf_work->dig_cdc->codec;
+ msm_dig_cdc = codec->control_data;
+ hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+ tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
+ (hpf_work->decimator - 1) * 32;
+
+ dev_dbg(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
+ __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+ msm_dig_cdc->update_clkdiv(msm_dig_cdc->handle, 0x51);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+static int msm_dig_cdc_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ int value = 0, reg;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (w->shift == 0)
+ reg = MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL;
+ else if (w->shift == 1)
+ reg = MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL;
+ else
+ goto ret;
+ value = snd_soc_read(codec, reg);
+ snd_soc_write(codec, reg, value);
+ break;
+ default:
+ pr_err("%s: event = %d not expected\n", __func__, event);
+ }
+ret:
+ return 0;
+}
+
+static int msm_dig_cdc_compander_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+ int comp_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int rx_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ dev_dbg(codec->dev, "%s: msm_dig_cdc->comp[%d]_enabled[%d] = %d\n",
+ __func__, comp_idx, rx_idx,
+ dig_cdc->comp_enabled[rx_idx]);
+
+ ucontrol->value.integer.value[0] = dig_cdc->comp_enabled[rx_idx];
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_dig_cdc_compander_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+ int comp_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int rx_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ if (dig_cdc->version >= DIANGU) {
+ if (!value)
+ dig_cdc->comp_enabled[rx_idx] = 0;
+ else
+ dig_cdc->comp_enabled[rx_idx] = comp_idx;
+ }
+
+ dev_dbg(codec->dev, "%s: msm_dig_cdc->comp[%d]_enabled[%d] = %d\n",
+ __func__, comp_idx, rx_idx,
+ dig_cdc->comp_enabled[rx_idx]);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new compander_kcontrols[] = {
+ SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM89XX_RX1, 1, 0,
+ msm_dig_cdc_compander_get, msm_dig_cdc_compander_set),
+
+ SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM89XX_RX2, 1, 0,
+ msm_dig_cdc_compander_get, msm_dig_cdc_compander_set),
+
+};
+
+static int msm_dig_cdc_set_interpolator_rate(struct snd_soc_dai *dai,
+ u8 rx_fs_rate_reg_val,
+ u32 sample_rate)
+{
+ snd_soc_update_bits(dai->codec,
+ MSM89XX_CDC_CORE_RX1_B5_CTL, 0xF0, rx_fs_rate_reg_val);
+ snd_soc_update_bits(dai->codec,
+ MSM89XX_CDC_CORE_RX2_B5_CTL, 0xF0, rx_fs_rate_reg_val);
+ return 0;
+}
+
+static int msm_dig_cdc_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ u8 tx_fs_rate, rx_fs_rate, rx_clk_fs_rate;
+ int ret;
+
+ dev_dbg(dai->codec->dev,
+ "%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
+ __func__, dai->name, dai->id, params_rate(params),
+ params_channels(params), params_format(params));
+
+ switch (params_rate(params)) {
+ case 8000:
+ tx_fs_rate = 0x00;
+ rx_fs_rate = 0x00;
+ rx_clk_fs_rate = 0x00;
+ break;
+ case 16000:
+ tx_fs_rate = 0x20;
+ rx_fs_rate = 0x20;
+ rx_clk_fs_rate = 0x01;
+ break;
+ case 32000:
+ tx_fs_rate = 0x40;
+ rx_fs_rate = 0x40;
+ rx_clk_fs_rate = 0x02;
+ break;
+ case 44100:
+ case 48000:
+ tx_fs_rate = 0x60;
+ rx_fs_rate = 0x60;
+ rx_clk_fs_rate = 0x03;
+ break;
+ case 96000:
+ tx_fs_rate = 0x80;
+ rx_fs_rate = 0x80;
+ rx_clk_fs_rate = 0x04;
+ break;
+ case 192000:
+ tx_fs_rate = 0xA0;
+ rx_fs_rate = 0xA0;
+ rx_clk_fs_rate = 0x05;
+ break;
+ default:
+ dev_err(dai->codec->dev,
+ "%s: Invalid sampling rate %d\n", __func__,
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(dai->codec,
+ MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x0F, rx_clk_fs_rate);
+
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_CAPTURE:
+ break;
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ ret = msm_dig_cdc_set_interpolator_rate(dai, rx_fs_rate,
+ params_rate(params));
+ if (ret < 0) {
+ dev_err(dai->codec->dev,
+ "%s: set decimator rate failed %d\n", __func__,
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_err(dai->codec->dev,
+ "%s: Invalid stream type %d\n", __func__,
+ substream->stream);
+ return -EINVAL;
+ }
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(dai->codec,
+ MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ snd_soc_update_bits(dai->codec,
+ MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x00);
+ break;
+ default:
+ dev_err(dai->codec->dev, "%s: wrong format selected\n",
+ __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_dig_cdc_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+ u8 dmic_clk_en;
+ u16 dmic_clk_reg;
+ s32 *dmic_clk_cnt;
+ unsigned int dmic;
+ int ret;
+ char *dmic_num = strpbrk(w->name, "1234");
+
+ if (dmic_num == NULL) {
+ dev_err(codec->dev, "%s: Invalid DMIC\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = kstrtouint(dmic_num, 10, &dmic);
+ if (ret < 0) {
+ dev_err(codec->dev,
+ "%s: Invalid DMIC line on the codec\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (dmic) {
+ case 1:
+ case 2:
+ dmic_clk_en = 0x01;
+ dmic_clk_cnt = &(dig_cdc->dmic_1_2_clk_cnt);
+ dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL;
+ dev_dbg(codec->dev,
+ "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
+ __func__, event, dmic, *dmic_clk_cnt);
+ break;
+ case 3:
+ case 4:
+ dmic_clk_en = 0x01;
+ dmic_clk_cnt = &(dig_cdc->dmic_3_4_clk_cnt);
+ dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL;
+ dev_dbg(codec->dev,
+ "%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
+ __func__, event, dmic, *dmic_clk_cnt);
+ break;
+ default:
+ dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ (*dmic_clk_cnt)++;
+ if (*dmic_clk_cnt == 1) {
+ snd_soc_update_bits(codec, dmic_clk_reg,
+ 0x0E, 0x04);
+ snd_soc_update_bits(codec, dmic_clk_reg,
+ dmic_clk_en, dmic_clk_en);
+ }
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_TX1_DMIC_CTL + (dmic - 1) * 0x20,
+ 0x07, 0x02);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ (*dmic_clk_cnt)--;
+ if (*dmic_clk_cnt == 0)
+ snd_soc_update_bits(codec, dmic_clk_reg,
+ dmic_clk_en, 0);
+ break;
+ }
+ return 0;
+}
+
+static int msm_dig_cdc_codec_enable_dec(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct msm_asoc_mach_data *pdata = NULL;
+ unsigned int decimator;
+ struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+ struct msm_dig *msm_dig_cdc = codec->control_data;
+ char *dec_name = NULL;
+ char *widget_name = NULL;
+ char *temp;
+ int ret = 0, i;
+ u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+ u8 dec_hpf_cut_of_freq;
+ int offset;
+ char *dec_num;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+ widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!widget_name)
+ return -ENOMEM;
+ temp = widget_name;
+
+ dec_name = strsep(&widget_name, " ");
+ widget_name = temp;
+ if (!dec_name) {
+ dev_err(codec->dev,
+ "%s: Invalid decimator = %s\n", __func__, w->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dec_num = strpbrk(dec_name, "12345");
+ if (dec_num == NULL) {
+ dev_err(codec->dev, "%s: Invalid Decimator\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = kstrtouint(dec_num, 10, &decimator);
+ if (ret < 0) {
+ dev_err(codec->dev,
+ "%s: Invalid decimator = %s\n", __func__, dec_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dev_dbg(codec->dev,
+ "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+ w->name, dec_name, decimator);
+
+ if (w->reg == MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL) {
+ dec_reset_reg = MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL;
+ offset = 0;
+ } else {
+ dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
+ 32 * (decimator - 1);
+ tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
+ 32 * (decimator - 1);
+ if (decimator == 5) {
+ tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG;
+ tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX5_MUX_CTL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enableable TX digital mute */
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+ for (i = 0; i < NUM_DECIMATORS; i++) {
+ if (decimator == i + 1)
+ dig_cdc->dec_active[i] = true;
+ }
+
+ dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
+
+ dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
+
+ tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
+ dec_hpf_cut_of_freq;
+
+ if (dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ) {
+
+ /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+ CF_MIN_3DB_150HZ << 4);
+ }
+ msm_dig_cdc->update_clkdiv(msm_dig_cdc->handle, 0x42);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* enable HPF */
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
+
+ if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
+ CF_MIN_3DB_150HZ) {
+
+ schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
+ msecs_to_jiffies(300));
+ }
+ /* apply the digital gain after the decimator is enabled*/
+ if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
+ snd_soc_write(codec,
+ tx_digital_gain_reg[w->shift + offset],
+ snd_soc_read(codec,
+ tx_digital_gain_reg[w->shift + offset])
+ );
+ if (pdata->lb_mode) {
+ pr_debug("%s: loopback mode unmute the DEC\n",
+ __func__);
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+ }
+ snd_soc_update_bits(codec, tx_vol_ctl_reg,
+ 0x01, 0x00);
+
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+ msleep(20);
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+ cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+ 1 << w->shift);
+ snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+ (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+ for (i = 0; i < NUM_DECIMATORS; i++) {
+ if (decimator == i + 1)
+ dig_cdc->dec_active[i] = false;
+ }
+ break;
+ }
+out:
+ kfree(widget_name);
+ return ret;
+}
+
+static int msm_dig_cdc_event_notify(struct notifier_block *block,
+ unsigned long val,
+ void *data)
+{
+ enum dig_cdc_notify_event event = (enum dig_cdc_notify_event)val;
+ struct snd_soc_codec *codec = registered_digcodec;
+ struct msm_dig *msm_dig_cdc = codec->control_data;
+ struct msm_asoc_mach_data *pdata = NULL;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+ switch (event) {
+ case DIG_CDC_EVENT_CLK_ON:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03);
+ if (pdata->mclk_freq == MCLK_RATE_12P288MHZ ||
+ pdata->native_clk_set)
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x00);
+ else if (pdata->mclk_freq == MCLK_RATE_9P6MHZ)
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x01);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01);
+ break;
+ case DIG_CDC_EVENT_CLK_OFF:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x00);
+ break;
+ case DIG_CDC_EVENT_RX1_MUTE_ON:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01);
+ msm_dig_cdc->mute_mask |= HPHL_PA_DISABLE;
+ break;
+ case DIG_CDC_EVENT_RX1_MUTE_OFF:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
+ msm_dig_cdc->mute_mask &= (~HPHL_PA_DISABLE);
+ break;
+ case DIG_CDC_EVENT_RX2_MUTE_ON:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x01);
+ msm_dig_cdc->mute_mask |= HPHR_PA_DISABLE;
+ break;
+ case DIG_CDC_EVENT_RX2_MUTE_OFF:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
+ msm_dig_cdc->mute_mask &= (~HPHR_PA_DISABLE);
+ break;
+ case DIG_CDC_EVENT_RX3_MUTE_ON:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x01);
+ msm_dig_cdc->mute_mask |= SPKR_PA_DISABLE;
+ break;
+ case DIG_CDC_EVENT_RX3_MUTE_OFF:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
+ msm_dig_cdc->mute_mask &= (~SPKR_PA_DISABLE);
+ break;
+ case DIG_CDC_EVENT_PRE_RX1_INT_ON:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x80);
+ break;
+ case DIG_CDC_EVENT_PRE_RX2_INT_ON:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x80);
+ break;
+ case DIG_CDC_EVENT_POST_RX1_INT_OFF:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x00);
+ break;
+ case DIG_CDC_EVENT_POST_RX2_INT_OFF:
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF);
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x00);
+ break;
+ case DIG_CDC_EVENT_SSR_DOWN:
+ regcache_cache_only(msm_dig_cdc->regmap, true);
+ break;
+ case DIG_CDC_EVENT_SSR_UP:
+ regcache_cache_only(msm_dig_cdc->regmap, false);
+ regcache_mark_dirty(msm_dig_cdc->regmap);
+ regcache_sync(msm_dig_cdc->regmap);
+ break;
+ case DIG_CDC_EVENT_INVALID:
+ default:
+ break;
+ }
+ return 0;
+}
+
+static ssize_t msm_dig_codec_version_read(struct snd_info_entry *entry,
+ void *file_private_data,
+ struct file *file,
+ char __user *buf, size_t count,
+ loff_t pos)
+{
+ struct msm_dig_priv *msm_dig;
+ char buffer[MSM_DIG_CDC_VERSION_ENTRY_SIZE];
+ int len = 0;
+
+ msm_dig = (struct msm_dig_priv *) entry->private_data;
+ if (!msm_dig) {
+ pr_err("%s: msm_dig priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (msm_dig->version) {
+ case DRAX_CDC:
+ len = snprintf(buffer, sizeof(buffer), "SDM660-CDC_1_0\n");
+ break;
+ default:
+ len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+ }
+
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_dig_codec_info_ops = {
+ .read = msm_dig_codec_version_read,
+};
+
+/*
+ * msm_dig_codec_info_create_codec_entry - creates msm_dig module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates msm_dig module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec)
+{
+ struct snd_info_entry *version_entry;
+ struct msm_dig_priv *msm_dig;
+ struct snd_soc_card *card;
+
+ if (!codec_root || !codec)
+ return -EINVAL;
+
+ msm_dig = snd_soc_codec_get_drvdata(codec);
+ card = codec->component.card;
+ msm_dig->entry = snd_register_module_info(codec_root->module,
+ "msm_digital_codec",
+ codec_root);
+ if (!msm_dig->entry) {
+ dev_dbg(codec->dev, "%s: failed to create msm_digital entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry = snd_info_create_card_entry(card->snd_card,
+ "version",
+ msm_dig->entry);
+ if (!version_entry) {
+ dev_dbg(codec->dev, "%s: failed to create msm_digital version entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry->private_data = msm_dig;
+ version_entry->size = MSM_DIG_CDC_VERSION_ENTRY_SIZE;
+ version_entry->content = SNDRV_INFO_CONTENT_DATA;
+ version_entry->c.ops = &msm_dig_codec_info_ops;
+
+ if (snd_info_register(version_entry) < 0) {
+ snd_info_free_entry(version_entry);
+ return -ENOMEM;
+ }
+ msm_dig->version_entry = version_entry;
+ return 0;
+}
+EXPORT_SYMBOL(msm_dig_codec_info_create_codec_entry);
+
+static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec)
+{
+ struct msm_dig_priv *dig_cdc = NULL;
+ struct msm_dig *msm_dig_cdc = dev_get_drvdata(codec->dev);
+ int i, ret;
+
+ dig_cdc = devm_kzalloc(codec->dev, sizeof(struct msm_dig_priv),
+ GFP_KERNEL);
+ if (!dig_cdc)
+ return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, dig_cdc);
+ dig_cdc->codec = codec;
+ codec->control_data = msm_dig_cdc;
+
+ snd_soc_add_codec_controls(codec, compander_kcontrols,
+ ARRAY_SIZE(compander_kcontrols));
+
+ for (i = 0; i < NUM_DECIMATORS; i++) {
+ tx_hpf_work[i].dig_cdc = dig_cdc;
+ tx_hpf_work[i].decimator = i + 1;
+ INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+ tx_hpf_corner_freq_callback);
+ }
+
+ for (i = 0; i < MSM89XX_RX_MAX; i++)
+ dig_cdc->comp_enabled[i] = COMPANDER_NONE;
+
+ /* Register event notifier */
+ msm_dig_cdc->nblock.notifier_call = msm_dig_cdc_event_notify;
+ if (msm_dig_cdc->register_notifier) {
+ ret = msm_dig_cdc->register_notifier(msm_dig_cdc->handle,
+ &msm_dig_cdc->nblock,
+ true);
+ if (ret) {
+ pr_err("%s: Failed to register notifier %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+ /* Assign to DRAX_CDC for initial version */
+ dig_cdc->version = DRAX_CDC;
+ registered_digcodec = codec;
+ return 0;
+}
+
+static int msm_dig_cdc_soc_remove(struct snd_soc_codec *codec)
+{
+ struct msm_dig *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+ if (msm_dig_cdc->register_notifier)
+ msm_dig_cdc->register_notifier(msm_dig_cdc->handle,
+ &msm_dig_cdc->nblock,
+ false);
+ iounmap(msm_dig_cdc->dig_base);
+ return 0;
+}
+
+static const struct snd_soc_dapm_route audio_dig_map[] = {
+ {"RX_I2S_CLK", NULL, "CDC_CONN"},
+ {"I2S RX1", NULL, "RX_I2S_CLK"},
+ {"I2S RX2", NULL, "RX_I2S_CLK"},
+ {"I2S RX3", NULL, "RX_I2S_CLK"},
+
+ {"I2S TX1", NULL, "TX_I2S_CLK"},
+ {"I2S TX2", NULL, "TX_I2S_CLK"},
+ {"I2S TX3", NULL, "TX_I2S_CLK"},
+ {"I2S TX4", NULL, "TX_I2S_CLK"},
+ {"I2S TX5", NULL, "TX_I2S_CLK"},
+ {"I2S TX6", NULL, "TX_I2S_CLK"},
+
+ {"I2S TX1", NULL, "DEC1 MUX"},
+ {"I2S TX2", NULL, "DEC2 MUX"},
+ {"I2S TX3", NULL, "I2S TX2 INP1"},
+ {"I2S TX4", NULL, "I2S TX2 INP2"},
+ {"I2S TX5", NULL, "DEC3 MUX"},
+ {"I2S TX6", NULL, "I2S TX3 INP2"},
+
+ {"I2S TX2 INP1", "RX_MIX1", "RX1 MIX2"},
+ {"I2S TX2 INP1", "DEC3", "DEC3 MUX"},
+ {"I2S TX2 INP2", "RX_MIX2", "RX2 MIX2"},
+ {"I2S TX2 INP2", "RX_MIX3", "RX3 MIX1"},
+ {"I2S TX2 INP2", "DEC4", "DEC4 MUX"},
+ {"I2S TX3 INP2", "DEC4", "DEC4 MUX"},
+ {"I2S TX3 INP2", "DEC5", "DEC5 MUX"},
+
+ {"PDM_OUT_RX1", NULL, "RX1 CHAIN"},
+ {"PDM_OUT_RX2", NULL, "RX2 CHAIN"},
+ {"PDM_OUT_RX3", NULL, "RX3 CHAIN"},
+
+ {"RX1 CHAIN", NULL, "RX1 MIX2"},
+ {"RX2 CHAIN", NULL, "RX2 MIX2"},
+ {"RX3 CHAIN", NULL, "RX3 MIX1"},
+
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
+ {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+ {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+ {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+ {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+ {"RX1 MIX2", NULL, "RX1 MIX1"},
+ {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
+ {"RX2 MIX2", NULL, "RX2 MIX1"},
+ {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
+
+ {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
+ {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
+ {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
+ {"RX1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX1 MIX1 INP1", "IIR2", "IIR2"},
+ {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
+ {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
+ {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
+ {"RX1 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX1 MIX1 INP2", "IIR2", "IIR2"},
+ {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
+ {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
+ {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
+
+ {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
+ {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
+ {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
+ {"RX2 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX2 MIX1 INP1", "IIR2", "IIR2"},
+ {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
+ {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
+ {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
+ {"RX2 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX2 MIX1 INP2", "IIR2", "IIR2"},
+
+ {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
+ {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
+ {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
+ {"RX3 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX3 MIX1 INP1", "IIR2", "IIR2"},
+ {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
+ {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
+ {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
+ {"RX3 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX3 MIX1 INP2", "IIR2", "IIR2"},
+
+ {"RX1 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX2 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX1 MIX2 INP1", "IIR2", "IIR2"},
+ {"RX2 MIX2 INP1", "IIR2", "IIR2"},
+
+ /* Decimator Inputs */
+ {"DEC1 MUX", "DMIC1", "DMIC1"},
+ {"DEC1 MUX", "DMIC2", "DMIC2"},
+ {"DEC1 MUX", "DMIC3", "DMIC3"},
+ {"DEC1 MUX", "DMIC4", "DMIC4"},
+ {"DEC1 MUX", "ADC1", "ADC1_IN"},
+ {"DEC1 MUX", "ADC2", "ADC2_IN"},
+ {"DEC1 MUX", "ADC3", "ADC3_IN"},
+ {"DEC1 MUX", NULL, "CDC_CONN"},
+
+ {"DEC2 MUX", "DMIC1", "DMIC1"},
+ {"DEC2 MUX", "DMIC2", "DMIC2"},
+ {"DEC2 MUX", "DMIC3", "DMIC3"},
+ {"DEC2 MUX", "DMIC4", "DMIC4"},
+ {"DEC2 MUX", "ADC1", "ADC1_IN"},
+ {"DEC2 MUX", "ADC2", "ADC2_IN"},
+ {"DEC2 MUX", "ADC3", "ADC3_IN"},
+ {"DEC2 MUX", NULL, "CDC_CONN"},
+
+ {"DEC3 MUX", "DMIC1", "DMIC1"},
+ {"DEC3 MUX", "DMIC2", "DMIC2"},
+ {"DEC3 MUX", "DMIC3", "DMIC3"},
+ {"DEC3 MUX", "DMIC4", "DMIC4"},
+ {"DEC3 MUX", "ADC1", "ADC1_IN"},
+ {"DEC3 MUX", "ADC2", "ADC2_IN"},
+ {"DEC3 MUX", "ADC3", "ADC3_IN"},
+ {"DEC3 MUX", NULL, "CDC_CONN"},
+
+ {"DEC4 MUX", "DMIC1", "DMIC1"},
+ {"DEC4 MUX", "DMIC2", "DMIC2"},
+ {"DEC4 MUX", "DMIC3", "DMIC3"},
+ {"DEC4 MUX", "DMIC4", "DMIC4"},
+ {"DEC4 MUX", "ADC1", "ADC1_IN"},
+ {"DEC4 MUX", "ADC2", "ADC2_IN"},
+ {"DEC4 MUX", "ADC3", "ADC3_IN"},
+ {"DEC4 MUX", NULL, "CDC_CONN"},
+
+ {"DEC5 MUX", "DMIC1", "DMIC1"},
+ {"DEC5 MUX", "DMIC2", "DMIC2"},
+ {"DEC5 MUX", "DMIC3", "DMIC3"},
+ {"DEC5 MUX", "DMIC4", "DMIC4"},
+ {"DEC5 MUX", "ADC1", "ADC1_IN"},
+ {"DEC5 MUX", "ADC2", "ADC2_IN"},
+ {"DEC5 MUX", "ADC3", "ADC3_IN"},
+ {"DEC5 MUX", NULL, "CDC_CONN"},
+
+ {"IIR1", NULL, "IIR1 INP1 MUX"},
+ {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR2", NULL, "IIR2 INP1 MUX"},
+ {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+};
+
+
+static const char * const i2s_tx2_inp1_text[] = {
+ "ZERO", "RX_MIX1", "DEC3"
+};
+
+static const char * const i2s_tx2_inp2_text[] = {
+ "ZERO", "RX_MIX2", "RX_MIX3", "DEC4"
+};
+
+static const char * const i2s_tx3_inp2_text[] = {
+ "DEC4", "DEC5"
+};
+
+static const char * const rx_mix1_text[] = {
+ "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
+};
+
+static const char * const rx_mix2_text[] = {
+ "ZERO", "IIR1", "IIR2"
+};
+
+static const char * const dec_mux_text[] = {
+ "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
+};
+
+static const char * const iir_inp1_text[] = {
+ "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3", "DEC3", "DEC4"
+};
+
+/* I2S TX MUXes */
+static const struct soc_enum i2s_tx2_inp1_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+ 2, 3, i2s_tx2_inp1_text);
+
+static const struct soc_enum i2s_tx2_inp2_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+ 0, 4, i2s_tx2_inp2_text);
+
+static const struct soc_enum i2s_tx3_inp2_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+ 4, 2, i2s_tx3_inp2_text);
+
+/* RX1 MIX1 */
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
+ 0, 6, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
+ 3, 6, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp3_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B2_CTL,
+ 0, 6, rx_mix1_text);
+
+/* RX1 MIX2 */
+static const struct soc_enum rx_mix2_inp1_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B3_CTL,
+ 0, 3, rx_mix2_text);
+
+/* RX2 MIX1 */
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+ 0, 6, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+ 3, 6, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp3_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+ 0, 6, rx_mix1_text);
+
+/* RX2 MIX2 */
+static const struct soc_enum rx2_mix2_inp1_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B3_CTL,
+ 0, 3, rx_mix2_text);
+
+/* RX3 MIX1 */
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+ 0, 6, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+ 3, 6, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp3_chain_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+ 0, 6, rx_mix1_text);
+
+/* DEC */
+static const struct soc_enum dec1_mux_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
+ 0, 8, dec_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
+ 3, 8, dec_mux_text);
+
+static const struct soc_enum dec3_mux_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B2_CTL,
+ 0, 8, dec_mux_text);
+
+static const struct soc_enum dec4_mux_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B2_CTL,
+ 3, 8, dec_mux_text);
+
+static const struct soc_enum decsva_mux_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B3_CTL,
+ 0, 8, dec_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL,
+ 0, 8, iir_inp1_text);
+
+static const struct soc_enum iir2_inp1_mux_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL,
+ 0, 8, iir_inp1_text);
+
+/*cut of frequency for high pass filter*/
+static const char * const cf_text[] = {
+ "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+static const struct soc_enum cf_rxmix1_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX1_B4_CTL, 0, 3, cf_text);
+
+static const struct soc_enum cf_rxmix2_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX2_B4_CTL, 0, 3, cf_text);
+
+static const struct soc_enum cf_rxmix3_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX3_B4_CTL, 0, 3, cf_text);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+#define MSM89XX_DEC_ENUM(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_dapm_get_enum_double, \
+ .put = msm_dig_cdc_put_dec_enum, \
+ .private_value = (unsigned long)&xenum }
+
+static const struct snd_kcontrol_new dec1_mux =
+ MSM89XX_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+ MSM89XX_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new dec3_mux =
+ MSM89XX_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+
+static const struct snd_kcontrol_new dec4_mux =
+ MSM89XX_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+
+static const struct snd_kcontrol_new decsva_mux =
+ MSM89XX_DEC_ENUM("DEC5 MUX Mux", decsva_mux_enum);
+
+static const struct snd_kcontrol_new i2s_tx2_inp1_mux =
+ SOC_DAPM_ENUM("I2S TX2 INP1 Mux", i2s_tx2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new i2s_tx2_inp2_mux =
+ SOC_DAPM_ENUM("I2S TX2 INP2 Mux", i2s_tx2_inp2_chain_enum);
+
+static const struct snd_kcontrol_new i2s_tx3_inp2_mux =
+ SOC_DAPM_ENUM("I2S TX3 INP2 Mux", i2s_tx3_inp2_chain_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+ SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp1_mux =
+ SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp3_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp3_mux =
+ SOC_DAPM_ENUM("RX2 MIX1 INP3 Mux", rx2_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp3_mux =
+ SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
+ SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
+ SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
+
+static const struct snd_soc_dapm_widget msm_dig_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MIXER_E("RX1 MIX2", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+ MSM89XX_RX1, 0, NULL, 0,
+ msm_dig_cdc_codec_enable_interpolator,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX2 MIX2", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+ MSM89XX_RX2, 0, NULL, 0,
+ msm_dig_cdc_codec_enable_interpolator,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX3 MIX1", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+ MSM89XX_RX3, 0, NULL, 0,
+ msm_dig_cdc_codec_enable_interpolator,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("RX1 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX3 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp3_mux),
+
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp3_mux),
+
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp3_mux),
+
+ SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+ &rx1_mix2_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix2_inp1_mux),
+
+ SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, MSM89XX_CDC_CORE_CLK_OTHR_CTL,
+ 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX_E("DEC1 MUX",
+ MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+ &dec1_mux, msm_dig_cdc_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC2 MUX",
+ MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+ &dec2_mux, msm_dig_cdc_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC3 MUX",
+ MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+ &dec3_mux, msm_dig_cdc_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC4 MUX",
+ MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+ &dec4_mux, msm_dig_cdc_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC5 MUX",
+ MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 4, 0,
+ &decsva_mux, msm_dig_cdc_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ /* Sidetone */
+ SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+ SND_SOC_DAPM_PGA_E("IIR1", MSM89XX_CDC_CORE_CLK_SD_CTL, 0, 0, NULL, 0,
+ msm_dig_cdc_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
+ SND_SOC_DAPM_PGA_E("IIR2", MSM89XX_CDC_CORE_CLK_SD_CTL, 1, 0, NULL, 0,
+ msm_dig_cdc_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_SUPPLY("RX_I2S_CLK",
+ MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("TX_I2S_CLK",
+ MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 4, 0, NULL, 0),
+
+
+ SND_SOC_DAPM_MUX("I2S TX2 INP1", SND_SOC_NOPM, 0, 0,
+ &i2s_tx2_inp1_mux),
+ SND_SOC_DAPM_MUX("I2S TX2 INP2", SND_SOC_NOPM, 0, 0,
+ &i2s_tx2_inp2_mux),
+ SND_SOC_DAPM_MUX("I2S TX3 INP2", SND_SOC_NOPM, 0, 0,
+ &i2s_tx3_inp2_mux),
+
+ /* Digital Mic Inputs */
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+ msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+ msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+ msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("ADC1_IN"),
+ SND_SOC_DAPM_INPUT("ADC2_IN"),
+ SND_SOC_DAPM_INPUT("ADC3_IN"),
+ SND_SOC_DAPM_OUTPUT("PDM_OUT_RX1"),
+ SND_SOC_DAPM_OUTPUT("PDM_OUT_RX2"),
+ SND_SOC_DAPM_OUTPUT("PDM_OUT_RX3"),
+};
+
+static const struct soc_enum cf_dec1_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX1_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec2_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX2_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec3_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX3_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec4_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX4_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_decsva_enum =
+ SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX5_MUX_CTL, 4, 3, cf_text);
+
+static const struct snd_kcontrol_new msm_dig_snd_controls[] = {
+ SOC_SINGLE_SX_TLV("DEC1 Volume",
+ MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC2 Volume",
+ MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC3 Volume",
+ MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC4 Volume",
+ MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC5 Volume",
+ MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN,
+ 0, -84, 40, digital_gain),
+
+ SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
+ MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
+ MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
+ MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP4 Volume",
+ MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR2 INP1 Volume",
+ MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL,
+ 0, -84, 40, digital_gain),
+
+ SOC_SINGLE_SX_TLV("RX1 Digital Volume",
+ MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX2 Digital Volume",
+ MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX3 Digital Volume",
+ MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+
+ SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+
+ SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+ msm_dig_cdc_get_iir_enable_audio_mixer,
+ msm_dig_cdc_put_iir_enable_audio_mixer),
+
+ SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+
+ SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+ msm_dig_cdc_get_iir_band_audio_mixer,
+ msm_dig_cdc_put_iir_band_audio_mixer),
+
+ SOC_SINGLE("RX1 HPF Switch",
+ MSM89XX_CDC_CORE_RX1_B5_CTL, 2, 1, 0),
+ SOC_SINGLE("RX2 HPF Switch",
+ MSM89XX_CDC_CORE_RX2_B5_CTL, 2, 1, 0),
+ SOC_SINGLE("RX3 HPF Switch",
+ MSM89XX_CDC_CORE_RX3_B5_CTL, 2, 1, 0),
+
+ SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
+ SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
+ SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
+
+ SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+ SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+ SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
+ SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
+ SOC_ENUM("TX5 HPF cut off", cf_decsva_enum),
+ SOC_SINGLE("TX1 HPF Switch",
+ MSM89XX_CDC_CORE_TX1_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX2 HPF Switch",
+ MSM89XX_CDC_CORE_TX2_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX3 HPF Switch",
+ MSM89XX_CDC_CORE_TX3_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX4 HPF Switch",
+ MSM89XX_CDC_CORE_TX4_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX5 HPF Switch",
+ MSM89XX_CDC_CORE_TX5_MUX_CTL, 3, 1, 0),
+};
+
+static int msm_dig_cdc_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = NULL;
+ u16 tx_vol_ctl_reg = 0;
+ u8 decimator = 0, i;
+ struct msm_dig_priv *dig_cdc;
+
+ pr_debug("%s: Digital Mute val = %d\n", __func__, mute);
+
+ if (!dai || !dai->codec) {
+ pr_err("%s: Invalid params\n", __func__);
+ return -EINVAL;
+ }
+ codec = dai->codec;
+ dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+ if (dai->id == AIF1_PB) {
+ dev_dbg(codec->dev, "%s: Not capture use case skip\n",
+ __func__);
+ return 0;
+ }
+
+ mute = (mute) ? 1 : 0;
+ if (!mute) {
+ /*
+ * 15 ms is an emperical value for the mute time
+ * that was arrived by checking the pop level
+ * to be inaudible
+ */
+ usleep_range(15000, 15010);
+ }
+
+ if (dai->id == AIF3_SVA) {
+ snd_soc_update_bits(codec,
+ MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG, 0x01, mute);
+ goto ret;
+ }
+ for (i = 0; i < (NUM_DECIMATORS - 1); i++) {
+ if (dig_cdc->dec_active[i])
+ decimator = i + 1;
+ if (decimator && decimator < NUM_DECIMATORS) {
+ /* mute/unmute decimators corresponding to Tx DAI's */
+ tx_vol_ctl_reg =
+ MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
+ 32 * (decimator - 1);
+ snd_soc_update_bits(codec, tx_vol_ctl_reg,
+ 0x01, mute);
+ }
+ decimator = 0;
+ }
+ret:
+ return 0;
+}
+
+static struct snd_soc_dai_ops msm_dig_dai_ops = {
+ .hw_params = msm_dig_cdc_hw_params,
+ .digital_mute = msm_dig_cdc_digital_mute,
+};
+
+
+static struct snd_soc_dai_driver msm_codec_dais[] = {
+ {
+ .name = "msm_dig_cdc_dai_rx1",
+ .id = AIF1_PB,
+ .playback = { /* Support maximum range */
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &msm_dig_dai_ops,
+ },
+ {
+ .name = "msm_dig_cdc_dai_tx1",
+ .id = AIF1_CAP,
+ .capture = { /* Support maximum range */
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &msm_dig_dai_ops,
+ },
+ {
+ .name = "msm_dig_cdc_dai_tx2",
+ .id = AIF3_SVA,
+ .capture = { /* Support maximum range */
+ .stream_name = "AIF2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &msm_dig_dai_ops,
+ },
+ {
+ .name = "msm_dig_cdc_dai_vifeed",
+ .id = AIF2_VIFEED,
+ .capture = { /* Support maximum range */
+ .stream_name = "AIF2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &msm_dig_dai_ops,
+ },
+};
+
+static struct regmap *msm_digital_get_regmap(struct device *dev)
+{
+ struct msm_dig *msm_dig_cdc = dev_get_drvdata(dev);
+
+ return msm_dig_cdc->regmap;
+}
+
+static struct snd_soc_codec_driver soc_msm_dig_codec = {
+ .probe = msm_dig_cdc_soc_probe,
+ .remove = msm_dig_cdc_soc_remove,
+ .controls = msm_dig_snd_controls,
+ .num_controls = ARRAY_SIZE(msm_dig_snd_controls),
+ .dapm_widgets = msm_dig_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(msm_dig_dapm_widgets),
+ .dapm_routes = audio_dig_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_dig_map),
+ .get_regmap = msm_digital_get_regmap,
+};
+
+const struct regmap_config msm_digital_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .lock = enable_digital_callback,
+ .unlock = disable_digital_callback,
+ .cache_type = REGCACHE_FLAT,
+ .reg_defaults = msm89xx_cdc_core_defaults,
+ .num_reg_defaults = MSM89XX_CDC_CORE_MAX_REGISTER,
+ .readable_reg = msm89xx_cdc_core_readable_reg,
+ .volatile_reg = msm89xx_cdc_core_volatile_reg,
+ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+ .max_register = MSM89XX_CDC_CORE_MAX_REGISTER,
+};
+
+static int msm_dig_cdc_probe(struct platform_device *pdev)
+{
+ int ret;
+ u32 dig_cdc_addr;
+ struct msm_dig *msm_dig_cdc;
+ struct dig_ctrl_platform_data *pdata;
+
+ msm_dig_cdc = devm_kzalloc(&pdev->dev, sizeof(struct msm_dig),
+ GFP_KERNEL);
+ if (!msm_dig_cdc)
+ return -ENOMEM;
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "%s: pdata from parent is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ goto rtn;
+ }
+ dev_set_drvdata(&pdev->dev, msm_dig_cdc);
+
+ ret = of_property_read_u32(pdev->dev.of_node, "reg",
+ &dig_cdc_addr);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+ __func__, "reg");
+ return ret;
+ }
+
+ msm_dig_cdc->dig_base = ioremap(dig_cdc_addr,
+ MSM89XX_CDC_CORE_MAX_REGISTER);
+ if (msm_dig_cdc->dig_base == NULL) {
+ dev_err(&pdev->dev, "%s ioremap failed\n", __func__);
+ return -ENOMEM;
+ }
+ msm_dig_cdc->regmap =
+ devm_regmap_init_mmio_clk(&pdev->dev, NULL,
+ msm_dig_cdc->dig_base, &msm_digital_regmap_config);
+
+ msm_dig_cdc->update_clkdiv = pdata->update_clkdiv;
+ msm_dig_cdc->get_cdc_version = pdata->get_cdc_version;
+ msm_dig_cdc->handle = pdata->handle;
+ msm_dig_cdc->register_notifier = pdata->register_notifier;
+
+ snd_soc_register_codec(&pdev->dev, &soc_msm_dig_codec,
+ msm_codec_dais, ARRAY_SIZE(msm_codec_dais));
+ dev_dbg(&pdev->dev, "%s: registered DIG CODEC 0x%x\n",
+ __func__, dig_cdc_addr);
+rtn:
+ return ret;
+}
+
+static int msm_dig_cdc_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_dig_cdc_of_match[] = {
+ {.compatible = "qcom,msm-digital-codec"},
+ {},
+};
+
+static struct platform_driver msm_digcodec_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .of_match_table = msm_dig_cdc_of_match,
+ },
+ .probe = msm_dig_cdc_probe,
+ .remove = msm_dig_cdc_remove,
+};
+module_platform_driver(msm_digcodec_driver);
+
+MODULE_DESCRIPTION("MSM Audio Digital codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h
new file mode 100644
index 0000000..6d83290
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h
@@ -0,0 +1,93 @@
+/* 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 MSM_DIGITAL_CDC_H
+#define MSM_DIGITAL_CDC_H
+
+#define HPHL_PA_DISABLE (0x01 << 1)
+#define HPHR_PA_DISABLE (0x01 << 2)
+#define SPKR_PA_DISABLE (0x01 << 3)
+
+#define NUM_DECIMATORS 5
+/* Codec supports 1 compander */
+enum {
+ COMPANDER_NONE = 0,
+ COMPANDER_1, /* HPHL/R */
+ COMPANDER_MAX,
+};
+
+/* Number of output I2S port */
+enum {
+ MSM89XX_RX1 = 0,
+ MSM89XX_RX2,
+ MSM89XX_RX3,
+ MSM89XX_RX_MAX,
+};
+
+struct msm_dig_priv {
+ struct snd_soc_codec *codec;
+ u32 comp_enabled[MSM89XX_RX_MAX];
+ int (*codec_hph_comp_gpio)(bool enable, struct snd_soc_codec *codec);
+ s32 dmic_1_2_clk_cnt;
+ s32 dmic_3_4_clk_cnt;
+ bool dec_active[NUM_DECIMATORS];
+ int version;
+ /* Entry for version info */
+ struct snd_info_entry *entry;
+ struct snd_info_entry *version_entry;
+};
+
+struct msm_dig {
+ char __iomem *dig_base;
+ struct regmap *regmap;
+ struct notifier_block nblock;
+ u32 mute_mask;
+ void *handle;
+ void (*update_clkdiv)(void *handle, int val);
+ int (*get_cdc_version)(void *handle);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+};
+
+struct dig_ctrl_platform_data {
+ void *handle;
+ void (*update_clkdiv)(void *handle, int val);
+ int (*get_cdc_version)(void *handle);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+};
+
+struct hpf_work {
+ struct msm_dig_priv *dig_cdc;
+ u32 decimator;
+ u8 tx_hpf_cut_of_freq;
+ struct delayed_work dwork;
+};
+
+/* Codec supports 5 bands */
+enum {
+ BAND1 = 0,
+ BAND2,
+ BAND3,
+ BAND4,
+ BAND5,
+ BAND_MAX,
+};
+
+extern void msm_dig_cdc_hph_comp_cb(
+ int (*codec_hph_comp_gpio)(
+ bool enable, struct snd_soc_codec *codec),
+ struct snd_soc_codec *codec);
+int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec);
+#endif
diff --git a/sound/soc/codecs/msm8x16/msm8916-wcd-irq.c b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.c
similarity index 88%
rename from sound/soc/codecs/msm8x16/msm8916-wcd-irq.c
rename to sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.c
index a722842..ee4ec34 100644
--- a/sound/soc/codecs/msm8x16/msm8916-wcd-irq.c
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,7 @@
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/of_irq.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -25,9 +26,9 @@
#include <linux/pm_qos.h>
#include <soc/qcom/pm.h>
#include <sound/soc.h>
-#include "msm8x16-wcd.h"
-#include "msm8916-wcd-irq.h"
-#include "msm8x16_wcd_registers.h"
+#include "msm-analog-cdc.h"
+#include "sdm660-cdc-irq.h"
+#include "sdm660-cdc-registers.h"
#define MAX_NUM_IRQS 14
#define NUM_IRQ_REGS 2
@@ -83,7 +84,7 @@
uint8_t mask[NUM_IRQ_REGS];
int linuxirq[MAX_NUM_IRQS];
irq_handler_t handler[MAX_NUM_IRQS];
- struct spmi_device *spmi[NUM_IRQ_REGS];
+ struct platform_device *spmi[NUM_IRQ_REGS];
struct snd_soc_codec *codec;
enum wcd9xxx_spmi_pm_state pm_state;
@@ -99,22 +100,6 @@
void wcd9xxx_spmi_enable_irq(int irq)
{
pr_debug("%s: irqno =%d\n", __func__, irq);
- if ((irq >= 0) && (irq <= 7)) {
- snd_soc_update_bits(map.codec,
- MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
- (0x01 << irq), 0x00);
- snd_soc_update_bits(map.codec,
- MSM89XX_PMIC_DIGITAL_INT_EN_SET,
- (0x01 << irq), (0x01 << irq));
- }
- if ((irq > 7) && (irq <= 15)) {
- snd_soc_update_bits(map.codec,
- MSM89XX_PMIC_ANALOG_INT_EN_CLR,
- (0x01 << (irq - 8)), 0x00);
- snd_soc_update_bits(map.codec,
- MSM89XX_PMIC_ANALOG_INT_EN_SET,
- (0x01 << (irq - 8)), (0x01 << (irq - 8)));
- }
if (!(map.mask[BIT_BYTE(irq)] & (BYTE_BIT_MASK(irq))))
return;
@@ -128,23 +113,6 @@
void wcd9xxx_spmi_disable_irq(int irq)
{
pr_debug("%s: irqno =%d\n", __func__, irq);
- if ((irq >= 0) && (irq <= 7)) {
- snd_soc_update_bits(map.codec,
- MSM89XX_PMIC_DIGITAL_INT_EN_SET,
- (0x01 << (irq)), 0x00);
- snd_soc_update_bits(map.codec,
- MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
- (0x01 << irq), (0x01 << irq));
- }
-
- if ((irq > 7) && (irq <= 15)) {
- snd_soc_update_bits(map.codec,
- MSM89XX_PMIC_ANALOG_INT_EN_SET,
- (0x01 << (irq - 8)), 0x00);
- snd_soc_update_bits(map.codec,
- MSM89XX_PMIC_ANALOG_INT_EN_CLR,
- (0x01 << (irq - 8)), (0x01 << (irq - 8)));
- }
if (map.mask[BIT_BYTE(irq)] & (BYTE_BIT_MASK(irq)))
return;
@@ -161,6 +129,10 @@
int rc;
unsigned long irq_flags;
+ map.linuxirq[irq] =
+ platform_get_irq_byname(map.spmi[BIT_BYTE(irq)],
+ irq_names[irq]);
+
if (strcmp(name, "mbhc sw intr"))
irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_ONESHOT;
@@ -414,7 +386,7 @@
map.codec = codec;
}
-void wcd9xxx_spmi_set_dev(struct spmi_device *spmi, int i)
+void wcd9xxx_spmi_set_dev(struct platform_device *spmi, int i)
{
if (i < NUM_IRQ_REGS)
map.spmi[i] = spmi;
diff --git a/sound/soc/codecs/msm8x16/msm8916-wcd-irq.h b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.h
similarity index 89%
rename from sound/soc/codecs/msm8x16/msm8916-wcd-irq.h
rename to sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.h
index 3862865..d0f48d0 100644
--- a/sound/soc/codecs/msm8x16/msm8916-wcd-irq.h
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,7 +24,7 @@
const char *name, void *priv);
extern int wcd9xxx_spmi_free_irq(int irq, void *priv);
extern void wcd9xxx_spmi_set_codec(struct snd_soc_codec *codec);
-extern void wcd9xxx_spmi_set_dev(struct spmi_device *spmi, int i);
+extern void wcd9xxx_spmi_set_dev(struct platform_device *spmi, int i);
extern int wcd9xxx_spmi_irq_init(void);
extern int wcd9xxx_spmi_suspend(pm_message_t pmesg);
extern int wcd9xxx_spmi_resume(void);
diff --git a/sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-registers.h
similarity index 82%
rename from sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h
rename to sound/soc/codecs/sdm660_cdc/sdm660-cdc-registers.h
index ec26ef39..1317ce1 100644
--- a/sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-registers.h
@@ -9,8 +9,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#ifndef MSM8X16_WCD_REGISTERS_H
-#define MSM8X16_WCD_REGISTERS_H
+#ifndef SDM660_WCD_REGISTERS_H
+#define SDM660_WCD_REGISTERS_H
#define CDC_DIG_BASE 0xF000
#define CDC_ANA_BASE 0xF100
@@ -335,20 +335,20 @@
MSM89XX_PMIC_CDC_NUM_REGISTERS
-#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL (0x00)
+#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL (0x00)
#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL (0x04)
-#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL (0x08)
+#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL (0x04)
+#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL (0x08)
#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL__POR (0x00)
#define MSM89XX_CDC_CORE_CLK_RX_I2S_CTL (0x0C)
#define MSM89XX_CDC_CORE_CLK_RX_I2S_CTL__POR (0x13)
#define MSM89XX_CDC_CORE_CLK_TX_I2S_CTL (0x10)
#define MSM89XX_CDC_CORE_CLK_TX_I2S_CTL__POR (0x13)
-#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL (0x14)
-#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL (0x18)
-#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL (0x14)
+#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL (0x18)
+#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL__POR (0x00)
#define MSM89XX_CDC_CORE_CLK_OTHR_CTL (0x1C)
#define MSM89XX_CDC_CORE_CLK_OTHR_CTL__POR (0x04)
#define MSM89XX_CDC_CORE_CLK_RX_B1_CTL (0x20)
@@ -359,10 +359,12 @@
#define MSM89XX_CDC_CORE_CLK_PDM_CTL__POR (0x00)
#define MSM89XX_CDC_CORE_CLK_SD_CTL (0x2C)
#define MSM89XX_CDC_CORE_CLK_SD_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL (0x30)
-#define MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL (0x30)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL__POR (0x00)
#define MSM89XX_CDC_CORE_CLK_RX_B2_CTL (0x34)
#define MSM89XX_CDC_CORE_CLK_RX_B2_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL (0x38)
+#define MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL__POR (0x13)
#define MSM89XX_CDC_CORE_RX1_B1_CTL (0x40)
#define MSM89XX_CDC_CORE_RX1_B1_CTL__POR (0x00)
#define MSM89XX_CDC_CORE_RX2_B1_CTL (0x60)
@@ -399,19 +401,19 @@
#define MSM89XX_CDC_CORE_RX2_B6_CTL__POR (0x00)
#define MSM89XX_CDC_CORE_RX3_B6_CTL (0x94)
#define MSM89XX_CDC_CORE_RX3_B6_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL (0x58)
-#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL (0x78)
-#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL (0x98)
-#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL (0x5C)
-#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL (0x7C)
-#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL (0x9C)
-#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE (0xA0)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL (0x58)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL (0x78)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL (0x98)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL (0x5C)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL (0x7C)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL (0x9C)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE (0xA0)
#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE__POR (0x00)
#define MSM89XX_CDC_CORE_TOP_CTL (0xA4)
#define MSM89XX_CDC_CORE_TOP_CTL__POR (0x01)
@@ -427,129 +429,145 @@
#define MSM89XX_CDC_CORE_COMP0_B5_CTL__POR (0x7F)
#define MSM89XX_CDC_CORE_COMP0_B6_CTL (0xC4)
#define MSM89XX_CDC_CORE_COMP0_B6_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS (0xC8)
-#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS__POR (0x03)
+#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS (0xC8)
+#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS__POR (0x03)
#define MSM89XX_CDC_CORE_COMP0_FS_CFG (0xCC)
#define MSM89XX_CDC_CORE_COMP0_FS_CFG__POR (0x03)
-#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL (0xD0)
-#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL__POR (0x02)
-#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL (0xE0)
+#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL (0xD0)
+#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL__POR (0x02)
+#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL (0xE0)
#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL (0xE4)
+#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL (0xE4)
#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG (0xE8)
+#define MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG (0xE8)
#define MSM89XX_CDC_CORE_DEBUG_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG (0xEC)
+#define MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG (0xEC)
#define MSM89XX_CDC_CORE_DEBUG_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG (0xF0)
+#define MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG (0xF0)
#define MSM89XX_CDC_CORE_DEBUG_B3_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL (0x100)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL (0x100)
#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL (0x140)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL (0x140)
#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL (0x104)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL (0x104)
#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL (0x144)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL (0x144)
#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL (0x108)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL (0x108)
#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL (0x148)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL (0x148)
#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL (0x10C)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL (0x10C)
#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL (0x14C)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL (0x14C)
#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL (0x110)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL (0x110)
#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL (0x150)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL (0x150)
#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL (0x114)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL (0x114)
#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL (0x154)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL (0x154)
#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL (0x118)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL (0x118)
#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL (0x158)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL (0x158)
#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL (0x11C)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL (0x11C)
#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL (0x15C)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL (0x15C)
#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL__POR (0x00)
#define MSM89XX_CDC_CORE_IIR1_CTL (0x120)
-#define MSM89XX_CDC_CORE_IIR1_CTL__POR (0x40)
+#define MSM89XX_CDC_CORE_IIR1_CTL__POR (0x40)
#define MSM89XX_CDC_CORE_IIR2_CTL (0x160)
-#define MSM89XX_CDC_CORE_IIR2_CTL__POR (0x40)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL (0x124)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL (0x164)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL (0x128)
+#define MSM89XX_CDC_CORE_IIR2_CTL__POR (0x40)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL (0x124)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL (0x164)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL (0x128)
#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL (0x168)
+#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL (0x168)
#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL (0x12C)
+#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL (0x12C)
#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL (0x16C)
+#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL (0x16C)
#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL (0x180)
+#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL (0x180)
#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL (0x184)
+#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL (0x184)
#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL (0x188)
+#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL (0x188)
#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL (0x18C)
+#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL (0x18C)
#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL (0x190)
+#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL (0x190)
#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL (0x194)
+#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL (0x194)
#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL (0x198)
+#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL (0x198)
#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL (0x19C)
+#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL (0x19C)
#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL__POR (0x00)
#define MSM89XX_CDC_CORE_CONN_TX_B1_CTL (0x1A0)
#define MSM89XX_CDC_CORE_CONN_TX_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL (0x1A8)
+#define MSM89XX_CDC_CORE_CONN_TX_B2_CTL (0x1A4)
+#define MSM89XX_CDC_CORE_CONN_TX_B2_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL (0x1A8)
#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL (0x1AC)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL (0x1AC)
#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL (0x1B0)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL (0x1B0)
#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL (0x1B4)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL (0x1B4)
#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL (0x1B8)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL (0x1B8)
#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL (0x1BC)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL (0x1BC)
#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL (0x1C0)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL (0x1C0)
#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL (0x1C4)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL (0x1C4)
#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL (0x1C8)
-#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL__POR (0x00)
-#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER (0x280)
+#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL (0x1C8)
+#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_CONN_TX_B3_CTL (0x1CC)
+#define MSM89XX_CDC_CORE_CONN_TX_B3_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER (0x1E0)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER__POR (0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN (0x1E4)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN__POR (0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG (0x1E8)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG__POR (0x00)
+#define MSM89XX_CDC_CORE_TX5_MUX_CTL (0x1EC)
+#define MSM89XX_CDC_CORE_TX5_MUX_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_TX5_CLK_FS_CTL (0x1F0)
+#define MSM89XX_CDC_CORE_TX5_CLK_FS_CTL__POR (0x03)
+#define MSM89XX_CDC_CORE_TX5_DMIC_CTL (0x1F4)
+#define MSM89XX_CDC_CORE_TX5_DMIC_CTL__POR (0x00)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER (0x280)
#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER__POR (0x00)
-#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER (0x2A0)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER (0x2A0)
#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER__POR (0x00)
-#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER (0x2C0)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER (0x2C0)
#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER__POR (0x00)
-#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER (0x2E0)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER (0x2E0)
#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER__POR (0x00)
-#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN (0x284)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN (0x284)
#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN__POR (0x00)
-#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN (0x2A4)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN (0x2A4)
#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN__POR (0x00)
-#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN (0x2C4)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN (0x2C4)
#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN__POR (0x00)
-#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN (0x2E4)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN (0x2E4)
#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN__POR (0x00)
-#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG (0x288)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG (0x288)
#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG__POR (0x00)
-#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG (0x2A8)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG (0x2A8)
#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG__POR (0x00)
-#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG (0x2C8)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG (0x2C8)
#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG__POR (0x00)
-#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG (0x2E8)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG (0x2E8)
#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG__POR (0x00)
#define MSM89XX_CDC_CORE_TX1_MUX_CTL (0x28C)
#define MSM89XX_CDC_CORE_TX1_MUX_CTL__POR (0x00)
diff --git a/sound/soc/codecs/msm8x16/msm89xx-regmap.c b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
similarity index 67%
rename from sound/soc/codecs/msm8x16/msm89xx-regmap.c
rename to sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
index 007b74c..fff1fdc 100644
--- a/sound/soc/codecs/msm8x16/msm89xx-regmap.c
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -12,8 +12,7 @@
*/
#include <linux/regmap.h>
-#include <linux/device.h>
-#include "msm8x16-wcd.h"
+#include "sdm660-cdc-registers.h"
/*
* Default register reset values that are common across different versions
@@ -21,7 +20,7 @@
* then remove it from this structure and add it in version specific
* structures.
*/
-static struct reg_default
+struct reg_default
msm89xx_cdc_core_defaults[MSM89XX_CDC_CORE_CACHE_SIZE] = {
{MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, 0x00},
{MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL, 0x00},
@@ -35,8 +34,9 @@
{MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x00},
{MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x00},
{MSM89XX_CDC_CORE_CLK_SD_CTL, 0x00},
- {MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL, 0x00},
+ {MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL, 0x00},
{MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x00},
+ {MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL, 0x13},
{MSM89XX_CDC_CORE_RX1_B1_CTL, 0x00},
{MSM89XX_CDC_CORE_RX2_B1_CTL, 0x00},
{MSM89XX_CDC_CORE_RX3_B1_CTL, 0x00},
@@ -78,8 +78,9 @@
{MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG, 0x00},
{MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG, 0x00},
{MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL, 0x00},
- {MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL, 0x00},
+ {MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, 0x00},
{MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL, 0x00},
+ {MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL, 0x00},
{MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL, 0x00},
{MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL, 0x00},
{MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL, 0x00},
@@ -92,7 +93,6 @@
{MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL, 0x00},
{MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL, 0x00},
{MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL, 0x00},
- {MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, 0x00},
{MSM89XX_CDC_CORE_IIR1_CTL, 0x40},
{MSM89XX_CDC_CORE_IIR2_CTL, 0x40},
{MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL, 0x00},
@@ -110,6 +110,7 @@
{MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, 0x00},
{MSM89XX_CDC_CORE_CONN_RX3_B2_CTL, 0x00},
{MSM89XX_CDC_CORE_CONN_TX_B1_CTL, 0x00},
+ {MSM89XX_CDC_CORE_CONN_TX_B2_CTL, 0x00},
{MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL, 0x00},
{MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL, 0x00},
{MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL, 0x00},
@@ -119,6 +120,13 @@
{MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL, 0x00},
{MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL, 0x00},
{MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL, 0x00},
+ {MSM89XX_CDC_CORE_CONN_TX_B3_CTL, 0x00},
+ {MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER, 0x00},
+ {MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN, 0x00},
+ {MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG, 0x00},
+ {MSM89XX_CDC_CORE_TX5_MUX_CTL, 0x00},
+ {MSM89XX_CDC_CORE_TX5_CLK_FS_CTL, 0x03},
+ {MSM89XX_CDC_CORE_TX5_DMIC_CTL, 0x00},
{MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER, 0x00},
{MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER, 0x00},
{MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER, 0x00},
@@ -145,7 +153,7 @@
{MSM89XX_CDC_CORE_TX4_DMIC_CTL, 0x00},
};
-static struct reg_default
+struct reg_default
msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE] = {
{MSM89XX_PMIC_DIGITAL_REVISION1, 0x00},
{MSM89XX_PMIC_DIGITAL_REVISION2, 0x00},
@@ -304,114 +312,148 @@
{MSM89XX_PMIC_ANALOG_TRIM_CTRL4, 0x00},
};
-static bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg)
+static const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
+ [MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_SD_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1,
+ [MSM89XX_CDC_CORE_TOP_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS] = 1,
+ [MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1,
+ [MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_TX_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX5_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX5_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX5_DMIC_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
+};
+
+bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg)
{
return msm89xx_cdc_core_reg_readable[reg];
}
-static bool msm89xx_pmic_cdc_readable_reg(struct device *dev, unsigned int reg)
-{
- return msm89xx_pmic_cdc_reg_readable[reg];
-}
-
-static bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg)
+bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case MSM89XX_CDC_CORE_RX1_B1_CTL:
- case MSM89XX_CDC_CORE_RX2_B1_CTL:
- case MSM89XX_CDC_CORE_RX3_B1_CTL:
- case MSM89XX_CDC_CORE_RX1_B6_CTL:
- case MSM89XX_CDC_CORE_RX2_B6_CTL:
- case MSM89XX_CDC_CORE_RX3_B6_CTL:
- case MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG:
- case MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG:
- case MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL:
- case MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL:
- case MSM89XX_CDC_CORE_CLK_MCLK_CTL:
- case MSM89XX_CDC_CORE_CLK_PDM_CTL:
- case MSM89XX_PMIC_ANALOG_BYPASS_MODE:
- case MSM89XX_PMIC_ANALOG_BOOST_EN_CTL:
- case MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL:
- case MSM89XX_PMIC_ANALOG_CURRENT_LIMIT:
- case MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL:
- case MSM89XX_PMIC_ANALOG_NCP_FBCTRL:
- case MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1:
- return true;
+ /* cache bypass for initial version */
default:
- return false;
+ return true;
}
}
-
-static bool msm89xx_pmic_cdc_volatile_reg(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case MSM89XX_PMIC_DIGITAL_REVISION1:
- case MSM89XX_PMIC_DIGITAL_REVISION2:
- case MSM89XX_PMIC_DIGITAL_PERPH_TYPE:
- case MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE:
- case MSM89XX_PMIC_DIGITAL_INT_RT_STS:
- case MSM89XX_PMIC_DIGITAL_INT_SET_TYPE:
- case MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH:
- case MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW:
- case MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS:
- case MSM89XX_PMIC_DIGITAL_INT_PENDING_STS:
- case MSM89XX_PMIC_DIGITAL_PIN_STATUS:
- case MSM89XX_PMIC_DIGITAL_SEC_ACCESS:
- case MSM89XX_PMIC_ANALOG_SEC_ACCESS:
- case MSM89XX_PMIC_ANALOG_REVISION1:
- case MSM89XX_PMIC_ANALOG_REVISION2:
- case MSM89XX_PMIC_ANALOG_REVISION3:
- case MSM89XX_PMIC_ANALOG_REVISION4:
- case MSM89XX_PMIC_ANALOG_PERPH_TYPE:
- case MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE:
- case MSM89XX_PMIC_ANALOG_INT_RT_STS:
- case MSM89XX_PMIC_ANALOG_INT_SET_TYPE:
- case MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH:
- case MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW:
- case MSM89XX_PMIC_ANALOG_INT_LATCHED_STS:
- case MSM89XX_PMIC_ANALOG_INT_PENDING_STS:
- case MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT:
- case MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT:
- case MSM89XX_PMIC_ANALOG_RX_HPH_STATUS:
- case MSM89XX_PMIC_ANALOG_RX_EAR_STATUS:
- case MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS:
- case MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS:
- return true;
- default:
- return false;
- }
-}
-
-struct regmap_config msm89xx_pmic_cdc_regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
- .max_register = MSM89XX_PMIC_CDC_CACHE_SIZE,
- .fast_io = true,
- .reg_defaults = msm89xx_pmic_cdc_defaults,
- .num_reg_defaults = ARRAY_SIZE(msm89xx_pmic_cdc_defaults),
- .readable_reg = msm89xx_pmic_cdc_readable_reg,
- .volatile_reg = msm89xx_pmic_cdc_volatile_reg,
- .cache_type = REGCACHE_RBTREE,
- .reg_format_endian = REGMAP_ENDIAN_NATIVE,
- .val_format_endian = REGMAP_ENDIAN_NATIVE,
- .can_multi_write = true,
- .lock = enable_digital_callback,
- .unlock = disable_digital_callback,
-
-};
-
-struct regmap_config msm89xx_cdc_core_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
-
- .max_register = MSM89XX_CDC_CORE_CACHE_SIZE,
- .reg_defaults = msm89xx_cdc_core_defaults,
- .num_reg_defaults = ARRAY_SIZE(msm89xx_cdc_core_defaults),
- .readable_reg = msm89xx_cdc_core_readable_reg,
- .volatile_reg = msm89xx_cdc_core_volatile_reg,
- .cache_type = REGCACHE_RBTREE,
- .reg_format_endian = REGMAP_ENDIAN_NATIVE,
- .val_format_endian = REGMAP_ENDIAN_NATIVE,
- .can_multi_write = true,
-};
diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c
index 5c27f10..ae53294 100644
--- a/sound/soc/codecs/wcd-dsp-mgr.c
+++ b/sound/soc/codecs/wcd-dsp-mgr.c
@@ -881,12 +881,50 @@
static int wdsp_suspend(struct device *wdsp_dev)
{
- return 0;
+ struct wdsp_mgr_priv *wdsp;
+ int rc = 0, i;
+
+ if (!wdsp_dev) {
+ pr_err("%s: Invalid handle to device\n", __func__);
+ return -EINVAL;
+ }
+
+ wdsp = dev_get_drvdata(wdsp_dev);
+
+ for (i = WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) {
+ rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_SUSPEND, NULL);
+ if (rc < 0) {
+ WDSP_ERR(wdsp, "component %s failed to suspend\n",
+ WDSP_GET_CMPNT_TYPE_STR(i));
+ break;
+ }
+ }
+
+ return rc;
}
static int wdsp_resume(struct device *wdsp_dev)
{
- return 0;
+ struct wdsp_mgr_priv *wdsp;
+ int rc = 0, i;
+
+ if (!wdsp_dev) {
+ pr_err("%s: Invalid handle to device\n", __func__);
+ return -EINVAL;
+ }
+
+ wdsp = dev_get_drvdata(wdsp_dev);
+
+ for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) {
+ rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_RESUME, NULL);
+ if (rc < 0) {
+ WDSP_ERR(wdsp, "component %s failed to resume\n",
+ WDSP_GET_CMPNT_TYPE_STR(i));
+ break;
+ }
+ }
+
+ return rc;
}
static struct wdsp_mgr_ops wdsp_ops = {
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index e719c00..75e2709 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -25,6 +25,7 @@
#include <linux/input.h>
#include <linux/firmware.h>
#include <linux/completion.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "wcd-mbhc-v2.h"
@@ -52,7 +53,7 @@
#define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50
#define ANC_DETECT_RETRY_CNT 7
-#define WCD_MBHC_SPL_HS_CNT 1
+#define WCD_MBHC_SPL_HS_CNT 2
static int det_extn_cable_en;
module_param(det_extn_cable_en, int, 0664);
@@ -1165,6 +1166,8 @@
bool micbias1 = false;
int ret = 0;
int rc, spl_hs_count = 0;
+ int cross_conn;
+ int try = 0;
pr_debug("%s: enter\n", __func__);
@@ -1182,11 +1185,6 @@
wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
- if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
- mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
- goto correct_plug_type;
- }
-
/* Enable HW FSM */
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
/*
@@ -1214,8 +1212,23 @@
plug_type = MBHC_PLUG_TYPE_INVALID;
}
- pr_debug("%s: Valid plug found, plug type is %d\n",
+ do {
+ cross_conn = wcd_check_cross_conn(mbhc);
+ try++;
+ } while (try < GND_MIC_SWAP_THRESHOLD);
+ /*
+ * check for cross coneection 4 times.
+ * conisder the result of the fourth iteration.
+ */
+ if (cross_conn > 0) {
+ pr_debug("%s: cross con found, start polling\n",
+ __func__);
+ plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+ pr_debug("%s: Plug found, plug type is %d\n",
__func__, plug_type);
+ goto correct_plug_type;
+ }
+
if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&
(!wcd_swch_level_remove(mbhc))) {
@@ -1233,7 +1246,8 @@
mbhc->hs_detect_work_stop);
wcd_enable_curr_micbias(mbhc,
WCD_MBHC_EN_NONE);
- if (mbhc->micbias_enable) {
+ if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
+ mbhc->micbias_enable) {
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
mbhc->codec, MIC_BIAS_2, false);
if (mbhc->mbhc_cb->set_micbias_value)
@@ -1258,7 +1272,8 @@
mbhc->hs_detect_work_stop);
wcd_enable_curr_micbias(mbhc,
WCD_MBHC_EN_NONE);
- if (mbhc->micbias_enable) {
+ if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
+ mbhc->micbias_enable) {
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
mbhc->codec, MIC_BIAS_2, false);
if (mbhc->mbhc_cb->set_micbias_value)
@@ -1455,10 +1470,7 @@
static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
{
struct snd_soc_codec *codec = mbhc->codec;
- enum wcd_mbhc_plug_type plug_type;
bool micbias1 = false;
- int cross_conn;
- int try = 0;
pr_debug("%s: enter\n", __func__);
WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
@@ -1479,21 +1491,6 @@
else
wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
- do {
- cross_conn = wcd_check_cross_conn(mbhc);
- try++;
- } while (try < GND_MIC_SWAP_THRESHOLD);
-
- if (cross_conn > 0) {
- pr_debug("%s: cross con found, start polling\n",
- __func__);
- plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
- if (!mbhc->current_plug)
- mbhc->current_plug = plug_type;
- pr_debug("%s: Plug found, plug type is %d\n",
- __func__, plug_type);
- }
-
/* Re-initialize button press completion object */
reinit_completion(&mbhc->btn_press_compl);
wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
@@ -1556,6 +1553,7 @@
if (mbhc->mbhc_cb->enable_mb_source)
mbhc->mbhc_cb->enable_mb_source(mbhc, true);
mbhc->btn_press_intr = false;
+ mbhc->is_btn_press = false;
wcd_mbhc_detect_plug_type(mbhc);
} else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
&& !detection_type) {
@@ -1573,6 +1571,7 @@
mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false);
mbhc->btn_press_intr = false;
+ mbhc->is_btn_press = false;
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM,
false);
@@ -1610,12 +1609,8 @@
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT);
} else if (mbhc->current_plug == MBHC_PLUG_TYPE_ANC_HEADPHONE) {
- mbhc->mbhc_cb->irq_control(codec,
- mbhc->intr_ids->mbhc_hs_rem_intr,
- false);
- mbhc->mbhc_cb->irq_control(codec,
- mbhc->intr_ids->mbhc_hs_ins_intr,
- false);
+ wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, false);
+ wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
0);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
@@ -1761,6 +1756,7 @@
mic_trigerred = 0;
mbhc->is_extn_cable = true;
mbhc->btn_press_intr = false;
+ mbhc->is_btn_press = false;
wcd_mbhc_detect_plug_type(mbhc);
WCD_MBHC_RSC_UNLOCK(mbhc);
pr_debug("%s: leave\n", __func__);
@@ -1937,15 +1933,13 @@
pr_debug("%s: enter\n", __func__);
complete(&mbhc->btn_press_compl);
WCD_MBHC_RSC_LOCK(mbhc);
- /* send event to sw intr handler*/
- mbhc->is_btn_press = true;
wcd_cancel_btn_work(mbhc);
if (wcd_swch_level_remove(mbhc)) {
pr_debug("%s: Switch level is low ", __func__);
goto done;
}
- mbhc->btn_press_intr = true;
+ mbhc->is_btn_press = true;
msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
pr_debug("%s: msec_val = %ld\n", __func__, msec_val);
if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN) {
@@ -1959,12 +1953,15 @@
__func__);
goto done;
}
+ mask = wcd_mbhc_get_button_mask(mbhc);
+ if (mask == SND_JACK_BTN_0)
+ mbhc->btn_press_intr = true;
+
if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) {
pr_debug("%s: Plug isn't headset, ignore button press\n",
__func__);
goto done;
}
- mask = wcd_mbhc_get_button_mask(mbhc);
mbhc->buttons_pressed |= mask;
mbhc->mbhc_cb->lock_sleep(mbhc, true);
if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
@@ -1990,8 +1987,8 @@
goto exit;
}
- if (mbhc->btn_press_intr) {
- mbhc->btn_press_intr = false;
+ if (mbhc->is_btn_press) {
+ mbhc->is_btn_press = false;
} else {
pr_debug("%s: This release is for fake btn press\n", __func__);
goto exit;
@@ -2135,6 +2132,22 @@
if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config)
mbhc->mbhc_cb->mbhc_moisture_config(mbhc);
+ /*
+ * For USB analog we need to override the switch configuration.
+ * Also, disable hph_l pull-up current source as HS_DET_L is driven
+ * by an external source
+ */
+ if (mbhc->mbhc_cfg->enable_usbc_analog) {
+ mbhc->hphl_swh = 1;
+ mbhc->gnd_swh = 1;
+
+ if (mbhc->mbhc_cb->hph_pull_up_control)
+ mbhc->mbhc_cb->hph_pull_up_control(codec, I_OFF);
+ else
+ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL,
+ 0);
+ }
+
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
@@ -2143,8 +2156,14 @@
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1);
- /* Insertion debounce set to 96ms */
- WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6);
+ if (mbhc->mbhc_cfg->enable_usbc_analog) {
+ /* Insertion debounce set to 48ms */
+ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 4);
+ } else {
+ /* Insertion debounce set to 96ms */
+ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6);
+ }
+
/* Button Debounce set to 16ms */
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2);
@@ -2307,15 +2326,280 @@
return result;
}
-int wcd_mbhc_start(struct wcd_mbhc *mbhc,
- struct wcd_mbhc_config *mbhc_cfg)
+static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc,
+ bool active)
{
int rc = 0;
+ struct usbc_ana_audio_config *config =
+ &mbhc->mbhc_cfg->usbc_analog_cfg;
+ union power_supply_propval pval;
- pr_debug("%s: enter\n", __func__);
+ dev_dbg(mbhc->codec->dev, "%s: setting GPIOs active = %d\n",
+ __func__, active);
+
+ memset(&pval, 0, sizeof(pval));
+
+ if (active) {
+ pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
+ if (power_supply_set_property(mbhc->usb_psy,
+ POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
+ dev_info(mbhc->codec->dev, "%s: force PR_SOURCE mode unsuccessful\n",
+ __func__);
+ else
+ mbhc->usbc_force_pr_mode = true;
+
+ if (config->usbc_en1_gpio_p)
+ rc = msm_cdc_pinctrl_select_active_state(
+ config->usbc_en1_gpio_p);
+ if (rc == 0 && config->usbc_en2n_gpio_p)
+ rc = msm_cdc_pinctrl_select_active_state(
+ config->usbc_en2n_gpio_p);
+ if (rc == 0 && config->usbc_force_gpio_p)
+ rc = msm_cdc_pinctrl_select_active_state(
+ config->usbc_force_gpio_p);
+ mbhc->usbc_mode = POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
+ } else {
+ /* no delay is required when disabling GPIOs */
+ if (config->usbc_en2n_gpio_p)
+ msm_cdc_pinctrl_select_sleep_state(
+ config->usbc_en2n_gpio_p);
+ if (config->usbc_en1_gpio_p)
+ msm_cdc_pinctrl_select_sleep_state(
+ config->usbc_en1_gpio_p);
+ if (config->usbc_force_gpio_p)
+ msm_cdc_pinctrl_select_sleep_state(
+ config->usbc_force_gpio_p);
+
+ if (mbhc->usbc_force_pr_mode) {
+ pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+ if (power_supply_set_property(mbhc->usb_psy,
+ POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
+ dev_info(mbhc->codec->dev, "%s: force PR_DUAL mode unsuccessful\n",
+ __func__);
+
+ mbhc->usbc_force_pr_mode = false;
+ }
+
+ mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE;
+ }
+
+ return rc;
+}
+
+/* workqueue */
+static void wcd_mbhc_usbc_analog_work_fn(struct work_struct *work)
+{
+ struct wcd_mbhc *mbhc =
+ container_of(work, struct wcd_mbhc, usbc_analog_work);
+
+ wcd_mbhc_usb_c_analog_setup_gpios(mbhc,
+ mbhc->usbc_mode != POWER_SUPPLY_TYPEC_NONE);
+}
+
+/* this callback function is used to process PMI notification */
+static int wcd_mbhc_usb_c_event_changed(struct notifier_block *nb,
+ unsigned long evt, void *ptr)
+{
+ int ret;
+ union power_supply_propval mode;
+ struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, psy_nb);
+ struct snd_soc_codec *codec = mbhc->codec;
+
+ if (ptr != mbhc->usb_psy || evt != PSY_EVENT_PROP_CHANGED)
+ return 0;
+
+ ret = power_supply_get_property(mbhc->usb_psy,
+ POWER_SUPPLY_PROP_TYPEC_MODE, &mode);
+ if (ret) {
+ dev_err(codec->dev, "%s: Unable to read USB TYPEC_MODE: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ dev_dbg(codec->dev, "%s: USB change event received\n",
+ __func__);
+ dev_dbg(codec->dev, "%s: supply mode %d, expected %d\n", __func__,
+ mode.intval, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER);
+
+ switch (mode.intval) {
+ case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER:
+ case POWER_SUPPLY_TYPEC_NONE:
+ dev_dbg(codec->dev, "%s: usbc_mode: %d; mode.intval: %d\n",
+ __func__, mbhc->usbc_mode, mode.intval);
+
+ if (mbhc->usbc_mode == mode.intval)
+ break; /* filter notifications received before */
+ mbhc->usbc_mode = mode.intval;
+
+ dev_dbg(codec->dev, "%s: queueing usbc_analog_work\n",
+ __func__);
+ schedule_work(&mbhc->usbc_analog_work);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+/* PMI registration code */
+static int wcd_mbhc_usb_c_analog_init(struct wcd_mbhc *mbhc)
+{
+ int ret = 0;
+ struct snd_soc_codec *codec = mbhc->codec;
+
+ dev_dbg(mbhc->codec->dev, "%s: usb-c analog setup start\n", __func__);
+ INIT_WORK(&mbhc->usbc_analog_work, wcd_mbhc_usbc_analog_work_fn);
+
+ mbhc->usb_psy = power_supply_get_by_name("usb");
+ if (IS_ERR_OR_NULL(mbhc->usb_psy)) {
+ dev_err(codec->dev, "%s: could not get USB psy info\n",
+ __func__);
+ ret = -EPROBE_DEFER;
+ if (IS_ERR(mbhc->usb_psy))
+ ret = PTR_ERR(mbhc->usb_psy);
+ mbhc->usb_psy = NULL;
+ goto err;
+ }
+
+ ret = wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false);
+ if (ret) {
+ dev_err(codec->dev, "%s: error while setting USBC ana gpios\n",
+ __func__);
+ goto err;
+ }
+
+ mbhc->psy_nb.notifier_call = wcd_mbhc_usb_c_event_changed;
+ mbhc->psy_nb.priority = 0;
+ ret = power_supply_reg_notifier(&mbhc->psy_nb);
+ if (ret) {
+ dev_err(codec->dev, "%s: power supply registration failed\n",
+ __func__);
+ goto err;
+ }
+
+ /*
+ * as part of the init sequence check if there is a connected
+ * USB C analog adapter
+ */
+ dev_dbg(mbhc->codec->dev, "%s: verify if USB adapter is already inserted\n",
+ __func__);
+ ret = wcd_mbhc_usb_c_event_changed(&mbhc->psy_nb,
+ PSY_EVENT_PROP_CHANGED,
+ mbhc->usb_psy);
+
+err:
+ return ret;
+}
+
+static int wcd_mbhc_usb_c_analog_deinit(struct wcd_mbhc *mbhc)
+{
+ wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false);
+
+ /* deregister from PMI */
+ power_supply_unreg_notifier(&mbhc->psy_nb);
+
+ return 0;
+}
+
+static int wcd_mbhc_init_gpio(struct wcd_mbhc *mbhc,
+ struct wcd_mbhc_config *mbhc_cfg,
+ const char *gpio_dt_str,
+ int *gpio, struct device_node **gpio_dn)
+{
+ int rc = 0;
+ struct snd_soc_codec *codec = mbhc->codec;
+ struct snd_soc_card *card = codec->component.card;
+
+ dev_dbg(mbhc->codec->dev, "%s: gpio %s\n", __func__, gpio_dt_str);
+
+ *gpio_dn = of_parse_phandle(card->dev->of_node, gpio_dt_str, 0);
+
+ if (!(*gpio_dn)) {
+ *gpio = of_get_named_gpio(card->dev->of_node, gpio_dt_str, 0);
+ if (!gpio_is_valid(*gpio)) {
+ dev_err(card->dev, "%s, property %s not in node %s",
+ __func__, gpio_dt_str,
+ card->dev->of_node->full_name);
+ rc = -EINVAL;
+ }
+ }
+
+ return rc;
+}
+
+int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg)
+{
+ int rc = 0;
+ struct usbc_ana_audio_config *config;
+ struct snd_soc_codec *codec;
+ struct snd_soc_card *card;
+ const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported";
+
+ if (!mbhc || !mbhc_cfg)
+ return -EINVAL;
+
+ config = &mbhc_cfg->usbc_analog_cfg;
+ codec = mbhc->codec;
+ card = codec->component.card;
+
/* update the mbhc config */
mbhc->mbhc_cfg = mbhc_cfg;
+ dev_dbg(mbhc->codec->dev, "%s: enter\n", __func__);
+
+ /* check if USB C analog is defined on device tree */
+ mbhc_cfg->enable_usbc_analog = 0;
+ if (of_find_property(card->dev->of_node, usb_c_dt, NULL)) {
+ rc = of_property_read_u32(card->dev->of_node, usb_c_dt,
+ &mbhc_cfg->enable_usbc_analog);
+ }
+ if (mbhc_cfg->enable_usbc_analog == 0 || rc != 0) {
+ dev_info(card->dev,
+ "%s: %s in dt node is missing or false\n",
+ __func__, usb_c_dt);
+ dev_info(card->dev,
+ "%s: skipping USB c analog configuration\n", __func__);
+ }
+
+ /* initialize GPIOs */
+ if (mbhc_cfg->enable_usbc_analog) {
+ dev_dbg(mbhc->codec->dev, "%s: usbc analog enabled\n",
+ __func__);
+ rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
+ "qcom,usbc-analog-en1_gpio",
+ &config->usbc_en1_gpio,
+ &config->usbc_en1_gpio_p);
+ if (rc)
+ goto err;
+
+ rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
+ "qcom,usbc-analog-en2_n_gpio",
+ &config->usbc_en2n_gpio,
+ &config->usbc_en2n_gpio_p);
+ if (rc)
+ goto err;
+
+ if (of_find_property(card->dev->of_node,
+ "qcom,usbc-analog-force_detect_gpio",
+ NULL)) {
+ rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
+ "qcom,usbc-analog-force_detect_gpio",
+ &config->usbc_force_gpio,
+ &config->usbc_force_gpio_p);
+ if (rc)
+ goto err;
+ }
+
+ dev_dbg(mbhc->codec->dev, "%s: calling usb_c_analog_init\n",
+ __func__);
+ /* init PMI notifier */
+ rc = wcd_mbhc_usb_c_analog_init(mbhc);
+ if (rc) {
+ rc = EPROBE_DEFER;
+ goto err;
+ }
+ }
+
/* Set btn key code */
if ((!mbhc->is_btn_already_regd) && wcd_mbhc_set_keycode(mbhc))
pr_err("Set btn key code error!!!\n");
@@ -2332,14 +2616,44 @@
pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
__func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
}
- pr_debug("%s: leave %d\n", __func__, rc);
+
+ return rc;
+err:
+ if (config->usbc_en1_gpio > 0) {
+ dev_dbg(card->dev, "%s free usb en1 gpio %d\n",
+ __func__, config->usbc_en1_gpio);
+ gpio_free(config->usbc_en1_gpio);
+ config->usbc_en1_gpio = 0;
+ }
+ if (config->usbc_en2n_gpio > 0) {
+ dev_dbg(card->dev, "%s free usb_en2 gpio %d\n",
+ __func__, config->usbc_en2n_gpio);
+ gpio_free(config->usbc_en2n_gpio);
+ config->usbc_en2n_gpio = 0;
+ }
+ if (config->usbc_force_gpio > 0) {
+ dev_dbg(card->dev, "%s free usb_force gpio %d\n",
+ __func__, config->usbc_force_gpio);
+ gpio_free(config->usbc_force_gpio);
+ config->usbc_force_gpio = 0;
+ }
+ if (config->usbc_en1_gpio_p)
+ of_node_put(config->usbc_en1_gpio_p);
+ if (config->usbc_en2n_gpio_p)
+ of_node_put(config->usbc_en2n_gpio_p);
+ if (config->usbc_force_gpio_p)
+ of_node_put(config->usbc_force_gpio_p);
+ dev_dbg(mbhc->codec->dev, "%s: leave %d\n", __func__, rc);
return rc;
}
EXPORT_SYMBOL(wcd_mbhc_start);
void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
{
+ struct usbc_ana_audio_config *config = &mbhc->mbhc_cfg->usbc_analog_cfg;
+
pr_debug("%s: enter\n", __func__);
+
if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) {
if (mbhc->mbhc_cb && mbhc->mbhc_cb->skip_imped_detect)
mbhc->mbhc_cb->skip_imped_detect(mbhc->codec);
@@ -2361,6 +2675,25 @@
mbhc->mbhc_fw = NULL;
mbhc->mbhc_cal = NULL;
}
+
+ if (mbhc->mbhc_cfg->enable_usbc_analog) {
+ wcd_mbhc_usb_c_analog_deinit(mbhc);
+ /* free GPIOs */
+ if (config->usbc_en1_gpio > 0)
+ gpio_free(config->usbc_en1_gpio);
+ if (config->usbc_en2n_gpio > 0)
+ gpio_free(config->usbc_en2n_gpio);
+ if (config->usbc_force_gpio)
+ gpio_free(config->usbc_force_gpio);
+
+ if (config->usbc_en1_gpio_p)
+ of_node_put(config->usbc_en1_gpio_p);
+ if (config->usbc_en2n_gpio_p)
+ of_node_put(config->usbc_en2n_gpio_p);
+ if (config->usbc_force_gpio_p)
+ of_node_put(config->usbc_force_gpio_p);
+ }
+
pr_debug("%s: leave\n", __func__);
}
EXPORT_SYMBOL(wcd_mbhc_stop);
@@ -2379,6 +2712,7 @@
int ret = 0;
int hph_swh = 0;
int gnd_swh = 0;
+ u32 hph_moist_config[3];
struct snd_soc_card *card = codec->component.card;
const char *hph_switch = "qcom,msm-mbhc-hphl-swh";
const char *gnd_switch = "qcom,msm-mbhc-gnd-swh";
@@ -2399,6 +2733,21 @@
goto err;
}
+ ret = of_property_read_u32_array(card->dev->of_node,
+ "qcom,msm-mbhc-moist-cfg",
+ hph_moist_config, 3);
+ if (ret) {
+ dev_dbg(card->dev, "%s: no qcom,msm-mbhc-moist-cfg in DT\n",
+ __func__);
+ mbhc->moist_vref = V_45_MV;
+ mbhc->moist_iref = I_3P0_UA;
+ mbhc->moist_rref = R_24_KOHM;
+ } else {
+ mbhc->moist_vref = hph_moist_config[0];
+ mbhc->moist_iref = hph_moist_config[1];
+ mbhc->moist_rref = hph_moist_config[2];
+ }
+
mbhc->in_swch_irq_handler = false;
mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
mbhc->is_btn_press = false;
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index c9bd4fe..e6cd1971 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -14,6 +14,7 @@
#include <linux/wait.h>
#include <linux/stringify.h>
+#include <linux/power_supply.h>
#include "wcdcal-hwdep.h"
#define TOMBAK_MBHC_NC 0
@@ -249,6 +250,15 @@
R_184_KOHM,
};
+struct usbc_ana_audio_config {
+ int usbc_en1_gpio;
+ int usbc_en2n_gpio;
+ int usbc_force_gpio;
+ struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */
+ struct device_node *usbc_en2n_gpio_p; /* used by pinctrl API */
+ struct device_node *usbc_force_gpio_p; /* used by pinctrl API */
+};
+
struct wcd_mbhc_config {
bool read_fw_bin;
void *calibration;
@@ -263,6 +273,8 @@
int mbhc_micbias;
int anc_micbias;
bool enable_anc_mic_detect;
+ u32 enable_usbc_analog;
+ struct usbc_ana_audio_config usbc_analog_cfg;
};
struct wcd_mbhc_intr {
@@ -393,6 +405,9 @@
bool in_swch_irq_handler;
bool hphl_swh; /*track HPHL switch NC / NO */
bool gnd_swh; /*track GND switch NC / NO */
+ u32 moist_vref;
+ u32 moist_iref;
+ u32 moist_rref;
u8 micbias1_cap_mode; /* track ext cap setting */
u8 micbias2_cap_mode; /* track ext cap setting */
bool hs_detect_work_stop;
@@ -440,6 +455,12 @@
unsigned long intr_status;
bool is_hph_ocp_pending;
+
+ bool usbc_force_pr_mode;
+ int usbc_mode;
+ struct notifier_block psy_nb;
+ struct power_supply *usb_psy;
+ struct work_struct usbc_analog_work;
};
#define WCD_MBHC_CAL_SIZE(buttons, rload) ( \
sizeof(struct wcd_mbhc_general_cfg) + \
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 869b39d..7e217a6 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -60,7 +60,8 @@
/* Command delays */
#define WCD_SPI_CLKREQ_DELAY_USECS (500)
-#define WCD_SPI_CLK_OFF_TIMER_MS (3000)
+#define WCD_SPI_CLK_OFF_TIMER_MS (500)
+#define WCD_SPI_RESUME_TIMEOUT_MS 100
/* Command masks */
#define WCD_CMD_ADDR_MASK \
@@ -90,6 +91,7 @@
/* Status mask bits */
#define WCD_SPI_CLK_STATE_ENABLED BIT(0)
+#define WCD_SPI_IS_SUSPENDED BIT(1)
/* Locking related */
#define WCD_SPI_MUTEX_LOCK(spi, lock) \
@@ -144,6 +146,9 @@
/* Debugfs related information */
struct wcd_spi_debug_data debug_data;
+
+ /* Completion object to indicate system resume completion */
+ struct completion resume_comp;
};
enum xfer_request {
@@ -170,6 +175,55 @@
xfer->len = 0;
}
+static bool wcd_spi_is_suspended(struct wcd_spi_priv *wcd_spi)
+{
+ return test_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+}
+
+static bool wcd_spi_can_suspend(struct wcd_spi_priv *wcd_spi)
+{
+ struct spi_device *spi = wcd_spi->spi;
+
+ if (wcd_spi->clk_users > 0 ||
+ test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask)) {
+ dev_err(&spi->dev, "%s: cannot suspend, clk_users = %d\n",
+ __func__, wcd_spi->clk_users);
+ return false;
+ }
+
+ return true;
+}
+
+static int wcd_spi_wait_for_resume(struct wcd_spi_priv *wcd_spi)
+{
+ struct spi_device *spi = wcd_spi->spi;
+ int rc = 0;
+
+ WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+ /* If the system is already in resumed state, return right away */
+ if (!wcd_spi_is_suspended(wcd_spi))
+ goto done;
+
+ /* If suspended then wait for resume to happen */
+ reinit_completion(&wcd_spi->resume_comp);
+ WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+ rc = wait_for_completion_timeout(&wcd_spi->resume_comp,
+ msecs_to_jiffies(WCD_SPI_RESUME_TIMEOUT_MS));
+ WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+ if (rc == 0) {
+ dev_err(&spi->dev, "%s: failed to resume in %u msec\n",
+ __func__, WCD_SPI_RESUME_TIMEOUT_MS);
+ rc = -EIO;
+ goto done;
+ }
+
+ dev_dbg(&spi->dev, "%s: resume successful\n", __func__);
+ rc = 0;
+done:
+ WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+ return rc;
+}
+
static int wcd_spi_read_single(struct spi_device *spi,
u32 remote_addr, u32 *val)
{
@@ -579,6 +633,18 @@
}
if (request == WCD_SPI_CLK_ENABLE) {
+ /*
+ * If the SPI bus is suspended, then return error
+ * as the transaction cannot be completed.
+ */
+ if (wcd_spi_is_suspended(wcd_spi)) {
+ dev_err(&spi->dev,
+ "%s: SPI suspended, cannot enable clk\n",
+ __func__);
+ ret = -EIO;
+ goto done;
+ }
+
/* Cancel the disable clk work */
WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
cancel_delayed_work_sync(&wcd_spi->clk_dwork);
@@ -899,6 +965,17 @@
ret = wdsp_spi_read_section(spi, data);
break;
+ case WDSP_EVENT_SUSPEND:
+ WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+ if (!wcd_spi_can_suspend(wcd_spi))
+ ret = -EBUSY;
+ WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+ break;
+
+ case WDSP_EVENT_RESUME:
+ ret = wcd_spi_wait_for_resume(wcd_spi);
+ break;
+
default:
dev_dbg(&spi->dev, "%s: Unhandled event %d\n",
__func__, event);
@@ -1303,6 +1380,7 @@
mutex_init(&wcd_spi->clk_mutex);
mutex_init(&wcd_spi->xfer_mutex);
INIT_DELAYED_WORK(&wcd_spi->clk_dwork, wcd_spi_clk_work);
+ init_completion(&wcd_spi->resume_comp);
wcd_spi->spi = spi;
spi_set_drvdata(spi, wcd_spi);
@@ -1340,6 +1418,61 @@
return 0;
}
+#ifdef CONFIG_PM
+static int wcd_spi_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+ int rc = 0;
+
+ WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+ if (!wcd_spi_can_suspend(wcd_spi)) {
+ rc = -EBUSY;
+ goto done;
+ }
+
+ /*
+ * If we are here, it is okay to let the suspend go
+ * through for this driver. But, still need to notify
+ * the master to make sure all other components can suspend
+ * as well.
+ */
+ if (wcd_spi->m_dev && wcd_spi->m_ops &&
+ wcd_spi->m_ops->suspend) {
+ WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+ rc = wcd_spi->m_ops->suspend(wcd_spi->m_dev);
+ WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+ }
+
+ if (rc == 0)
+ set_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+ else
+ dev_dbg(&spi->dev, "%s: cannot suspend, err = %d\n",
+ __func__, rc);
+done:
+ WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+ return rc;
+}
+
+static int wcd_spi_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+
+ WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+ clear_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+ complete(&wcd_spi->resume_comp);
+ WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+
+ return 0;
+}
+
+static const struct dev_pm_ops wcd_spi_pm_ops = {
+ .suspend = wcd_spi_suspend,
+ .resume = wcd_spi_resume,
+};
+#endif
+
static const struct of_device_id wcd_spi_of_match[] = {
{ .compatible = "qcom,wcd-spi-v2", },
{ }
@@ -1350,6 +1483,9 @@
.driver = {
.name = "wcd-spi-v2",
.of_match_table = wcd_spi_of_match,
+#ifdef CONFIG_PM
+ .pm = &wcd_spi_pm_ops,
+#endif
},
.probe = wcd_spi_probe,
.remove = wcd_spi_remove,
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 2185f4b..5ea0551 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -2197,7 +2197,7 @@
{
struct snd_soc_codec *codec = mbhc->codec;
- if (TASHA_MBHC_MOISTURE_VREF == V_OFF)
+ if (mbhc->moist_vref == V_OFF)
return;
/* Donot enable moisture detection if jack type is NC */
@@ -2208,8 +2208,8 @@
}
snd_soc_update_bits(codec, WCD9335_MBHC_CTL_2,
- 0x0C, TASHA_MBHC_MOISTURE_VREF << 2);
- tasha_mbhc_hph_l_pull_up_control(codec, TASHA_MBHC_MOISTURE_IREF);
+ 0x0C, mbhc->moist_vref << 2);
+ tasha_mbhc_hph_l_pull_up_control(codec, mbhc->moist_iref);
}
static const struct wcd_mbhc_cb mbhc_cb = {
@@ -7926,6 +7926,13 @@
tasha_mad_input = ucontrol->value.integer.value[0];
+ if (tasha_mad_input >= ARRAY_SIZE(tasha_conn_mad_text)) {
+ dev_err(codec->dev,
+ "%s: tasha_mad_input = %d out of bounds\n",
+ __func__, tasha_mad_input);
+ return -EINVAL;
+ }
+
if (!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED1") ||
!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED2") ||
!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED3") ||
@@ -13436,8 +13443,6 @@
/* Class-H Init*/
wcd_clsh_init(&tasha->clsh_d);
- /* Default HPH Mode to Class-H HiFi */
- tasha->hph_mode = CLS_H_HIFI;
for (i = 0; i < TASHA_MAX_MICBIAS; i++)
tasha->micb_ref[i] = 0;
@@ -13445,8 +13450,6 @@
tasha_update_reg_defaults(tasha);
tasha->codec = codec;
- for (i = 0; i < COMPANDER_MAX; i++)
- tasha->comp_enabled[i] = 0;
dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
__func__, control->mclk_rate);
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
index b57b3d4..8da0425 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -607,8 +607,6 @@
/* Disable WDOG */
snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
0x3F, 0x01);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
- 0x04, 0x00);
/* Put WDSP in reset state */
snd_soc_update_bits(codec, WCD934X_CPE_SS_CPE_CTL,
@@ -633,11 +631,7 @@
if (cntl->debug_mode) {
snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
0x3F, 0x01);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
- 0x04, 0x00);
} else {
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
- 0x04, 0x04);
snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
0x3F, 0x21);
}
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
index 0e0c26d..3d032f0 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -772,18 +772,24 @@
{
struct snd_soc_codec *codec = mbhc->codec;
- if (TAVIL_MBHC_MOISTURE_RREF == R_OFF)
+ if ((mbhc->moist_rref == R_OFF) ||
+ (mbhc->mbhc_cfg->enable_usbc_analog)) {
+ snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
+ 0x0C, R_OFF << 2);
return;
+ }
/* Donot enable moisture detection if jack type is NC */
if (!mbhc->hphl_swh) {
dev_dbg(codec->dev, "%s: disable moisture detection for NC\n",
__func__);
+ snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
+ 0x0C, R_OFF << 2);
return;
}
snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
- 0x0C, TAVIL_MBHC_MOISTURE_RREF << 2);
+ 0x0C, mbhc->moist_rref << 2);
}
static bool tavil_hph_register_recovery(struct wcd_mbhc *mbhc)
diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h
index 8ca4c07..cd165af 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-routing.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-routing.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -914,9 +914,23 @@
{"ANC OUT EAR Enable", "Switch", "ADC MUX11"},
{"RX INT0 MIX2", NULL, "ANC OUT EAR Enable"},
+ {"ANC OUT HPHL Enable", "Switch", "ADC MUX10"},
+ {"ANC OUT HPHL Enable", "Switch", "ADC MUX11"},
+ {"RX INT1 MIX2", NULL, "ANC OUT HPHL Enable"},
+
+ {"ANC OUT HPHR Enable", "Switch", "ADC MUX12"},
+ {"ANC OUT HPHR Enable", "Switch", "ADC MUX13"},
+ {"RX INT2 MIX2", NULL, "ANC OUT HPHR Enable"},
+
{"ANC EAR PA", NULL, "RX INT0 DAC"},
{"ANC EAR", NULL, "ANC EAR PA"},
+ {"ANC HPHL PA", NULL, "RX INT1 DAC"},
+ {"ANC HPHL", NULL, "ANC HPHL PA"},
+
+ {"ANC HPHR PA", NULL, "RX INT2 DAC"},
+ {"ANC HPHR", NULL, "ANC HPHR PA"},
+
{"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX10"},
{"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX11"},
{"RX INT7 MIX2", NULL, "ANC OUT EAR SPKR Enable"},
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 724d961..eb856c2 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -174,6 +174,10 @@
AUDIO_NOMINAL,
HPH_PA_DELAY,
CLSH_Z_CONFIG,
+ ANC_MIC_AMIC1,
+ ANC_MIC_AMIC2,
+ ANC_MIC_AMIC3,
+ ANC_MIC_AMIC4,
};
enum {
@@ -507,6 +511,7 @@
module_param(tx_unmute_delay, int, 0664);
MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path");
+static void tavil_codec_set_tx_hold(struct snd_soc_codec *, u16, bool);
/* Hold instance to soundwire platform device */
struct tavil_swr_ctrl_data {
@@ -995,14 +1000,30 @@
snd_soc_dapm_enable_pin(dapm, "ANC EAR PA");
snd_soc_dapm_enable_pin(dapm, "ANC EAR");
snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA");
+ snd_soc_dapm_enable_pin(dapm, "ANC HPHL PA");
+ snd_soc_dapm_enable_pin(dapm, "ANC HPHR PA");
+ snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
snd_soc_dapm_disable_pin(dapm, "EAR PA");
snd_soc_dapm_disable_pin(dapm, "EAR");
+ snd_soc_dapm_disable_pin(dapm, "HPHL PA");
+ snd_soc_dapm_disable_pin(dapm, "HPHR PA");
+ snd_soc_dapm_disable_pin(dapm, "HPHL");
+ snd_soc_dapm_disable_pin(dapm, "HPHR");
} else {
snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
snd_soc_dapm_disable_pin(dapm, "ANC EAR");
snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
snd_soc_dapm_enable_pin(dapm, "EAR PA");
snd_soc_dapm_enable_pin(dapm, "EAR");
+ snd_soc_dapm_enable_pin(dapm, "HPHL");
+ snd_soc_dapm_enable_pin(dapm, "HPHR");
+ snd_soc_dapm_enable_pin(dapm, "HPHL PA");
+ snd_soc_dapm_enable_pin(dapm, "HPHR PA");
}
mutex_unlock(&tavil->codec_mutex);
@@ -1119,16 +1140,56 @@
}
/* Rate converter clk enable and set bypass mode */
- snd_soc_update_bits(codec, WCD934X_CDC_ANC0_RC_COMMON_CTL,
- 0x05, 0x05);
+ if (!strcmp(w->name, "RX INT0 DAC") ||
+ !strcmp(w->name, "RX INT1 DAC") ||
+ !strcmp(w->name, "ANC SPK1 PA")) {
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC0_RC_COMMON_CTL,
+ 0x05, 0x05);
+ if (!strcmp(w->name, "RX INT1 DAC")) {
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC0_FIFO_COMMON_CTL,
+ 0x66, 0x66);
+ }
+ } else if (!strcmp(w->name, "RX INT2 DAC")) {
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC1_RC_COMMON_CTL,
+ 0x05, 0x05);
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC1_FIFO_COMMON_CTL,
+ 0x66, 0x66);
+ }
+ if (!strcmp(w->name, "RX INT1 DAC"))
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08);
+ else if (!strcmp(w->name, "RX INT2 DAC"))
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08);
+
if (!hwdep_cal)
release_firmware(fw);
break;
+
+ case SND_SOC_DAPM_POST_PMU:
+ if (!strcmp(w->name, "ANC HPHL PA") ||
+ !strcmp(w->name, "ANC HPHR PA")) {
+ /* Remove ANC Rx from reset */
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC0_CLK_RESET_CTL,
+ 0x08, 0x00);
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC1_CLK_RESET_CTL,
+ 0x08, 0x00);
+ }
+
+ break;
+
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, WCD934X_CDC_ANC0_RC_COMMON_CTL,
0x05, 0x00);
if (!strcmp(w->name, "ANC EAR PA") ||
- !strcmp(w->name, "ANC SPK1 PA")) {
+ !strcmp(w->name, "ANC SPK1 PA") ||
+ !strcmp(w->name, "ANC HPHL PA")) {
snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_1_CTL,
0x30, 0x00);
msleep(50);
@@ -1143,6 +1204,21 @@
snd_soc_update_bits(codec,
WCD934X_CDC_ANC0_CLK_RESET_CTL,
0x38, 0x00);
+ } else if (!strcmp(w->name, "ANC HPHR PA")) {
+ snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_1_CTL,
+ 0x30, 0x00);
+ msleep(50);
+ snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_1_CTL,
+ 0x01, 0x00);
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC1_CLK_RESET_CTL,
+ 0x38, 0x38);
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC1_CLK_RESET_CTL,
+ 0x07, 0x00);
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_ANC1_CLK_RESET_CTL,
+ 0x38, 0x00);
}
break;
}
@@ -1879,12 +1955,8 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
case SND_SOC_DAPM_POST_PMU:
- if (!(snd_soc_read(codec,
- WCD934X_CDC_RX2_RX_PATH_CTL) & 0x10) &&
- (!(snd_soc_read(codec,
- WCD934X_CDC_RX1_RX_PATH_CTL) & 0x10)))
- snd_soc_update_bits(codec,
- WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02);
+ snd_soc_update_bits(codec,
+ WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec,
@@ -1894,6 +1966,18 @@
}
}
+static void tavil_codec_clear_anc_tx_hold(struct tavil_priv *tavil)
+{
+ if (test_and_clear_bit(ANC_MIC_AMIC1, &tavil->status_mask))
+ tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC1, false);
+ if (test_and_clear_bit(ANC_MIC_AMIC2, &tavil->status_mask))
+ tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC2, false);
+ if (test_and_clear_bit(ANC_MIC_AMIC3, &tavil->status_mask))
+ tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC3, false);
+ if (test_and_clear_bit(ANC_MIC_AMIC4, &tavil->status_mask))
+ tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC4, false);
+}
+
static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -1901,6 +1985,7 @@
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+ int ret = 0;
dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
@@ -1909,6 +1994,11 @@
if (TAVIL_IS_1_0(tavil->wcd9xxx))
snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
0x06, (0x03 << 1));
+
+ if ((!(strcmp(w->name, "ANC HPHR PA"))) &&
+ (test_bit(HPH_PA_DELAY, &tavil->status_mask)))
+ snd_soc_update_bits(codec, WCD934X_ANA_HPH, 0xC0, 0xC0);
+
set_bit(HPH_PA_DELAY, &tavil->status_mask);
if (dsd_conf &&
(snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) {
@@ -1918,14 +2008,34 @@
}
break;
case SND_SOC_DAPM_POST_PMU:
+ if ((!(strcmp(w->name, "ANC HPHR PA")))) {
+ if ((snd_soc_read(codec, WCD934X_ANA_HPH) & 0xC0)
+ != 0xC0)
+ /*
+ * If PA_EN is not set (potentially in ANC case)
+ * then do nothing for POST_PMU and let left
+ * channel handle everything.
+ */
+ break;
+ }
/*
* 7ms sleep is required after PA is enabled as per
- * HW requirement
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is needed.
*/
if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) {
- usleep_range(7000, 7100);
+ if (!tavil->comp_enabled[COMPANDER_2])
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
clear_bit(HPH_PA_DELAY, &tavil->status_mask);
}
+ if (tavil->anc_func) {
+ /* Clear Tx FE HOLD if both PAs are enabled */
+ if ((snd_soc_read(tavil->codec, WCD934X_ANA_HPH) &
+ 0xC0) == 0xC0)
+ tavil_codec_clear_anc_tx_hold(tavil);
+ }
snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x01);
@@ -1948,6 +2058,34 @@
(snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2,
0x04, 0x00);
+ if (!(strcmp(w->name, "ANC HPHR PA"))) {
+ pr_debug("%s:Do everything needed for left channel\n",
+ __func__);
+ /* Do everything needed for left channel */
+ snd_soc_update_bits(codec, WCD934X_HPH_L_TEST,
+ 0x01, 0x01);
+
+ /* Remove mute */
+ snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
+ 0x10, 0x00);
+
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_read(codec,
+ WCD934X_CDC_RX1_RX_PATH_MIX_CTL)) &
+ 0x10)
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+ 0x10, 0x00);
+
+ if (dsd_conf && (snd_soc_read(codec,
+ WCD934X_CDC_DSD0_PATH_CTL) &
+ 0x01))
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_DSD0_CFG2,
+ 0x04, 0x00);
+ /* Remove ANC Rx from reset */
+ ret = tavil_codec_enable_anc(w, kcontrol, event);
+ }
tavil_codec_override(codec, tavil->hph_mode, event);
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -1962,10 +2100,20 @@
snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x00);
snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
0x10, 0x10);
+ snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+ 0x10, 0x10);
+ if (!(strcmp(w->name, "ANC HPHR PA")))
+ snd_soc_update_bits(codec, WCD934X_ANA_HPH, 0x40, 0x00);
break;
case SND_SOC_DAPM_POST_PMD:
- /* 5ms sleep is required after PA disable */
- usleep_range(5000, 5100);
+ /*
+ * 5ms sleep is required after PA disable. If compander is
+ * disabled, then 20ms delay is needed after PA disable.
+ */
+ if (!tavil->comp_enabled[COMPANDER_2])
+ usleep_range(20000, 20100);
+ else
+ usleep_range(5000, 5100);
tavil_codec_override(codec, tavil->hph_mode, event);
blocking_notifier_call_chain(&tavil->mbhc->notifier,
WCD_EVENT_POST_HPHR_PA_OFF,
@@ -1973,10 +2121,16 @@
if (TAVIL_IS_1_0(tavil->wcd9xxx))
snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
0x06, 0x0);
+ if (!(strcmp(w->name, "ANC HPHR PA"))) {
+ ret = tavil_codec_enable_anc(w, kcontrol, event);
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_RX2_RX_PATH_CFG0,
+ 0x10, 0x00);
+ }
break;
};
- return 0;
+ return ret;
}
static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
@@ -1986,6 +2140,7 @@
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+ int ret = 0;
dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
@@ -1994,6 +2149,10 @@
if (TAVIL_IS_1_0(tavil->wcd9xxx))
snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
0x06, (0x03 << 1));
+ if ((!(strcmp(w->name, "ANC HPHL PA"))) &&
+ (test_bit(HPH_PA_DELAY, &tavil->status_mask)))
+ snd_soc_update_bits(codec, WCD934X_ANA_HPH,
+ 0xC0, 0xC0);
set_bit(HPH_PA_DELAY, &tavil->status_mask);
if (dsd_conf &&
(snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01)) {
@@ -2003,14 +2162,35 @@
}
break;
case SND_SOC_DAPM_POST_PMU:
+ if (!(strcmp(w->name, "ANC HPHL PA"))) {
+ if ((snd_soc_read(codec, WCD934X_ANA_HPH) & 0xC0)
+ != 0xC0)
+ /*
+ * If PA_EN is not set (potentially in ANC
+ * case) then do nothing for POST_PMU and
+ * let right channel handle everything.
+ */
+ break;
+ }
/*
* 7ms sleep is required after PA is enabled as per
- * HW requirement
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is needed.
*/
if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) {
- usleep_range(7000, 7100);
+ if (!tavil->comp_enabled[COMPANDER_1])
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
clear_bit(HPH_PA_DELAY, &tavil->status_mask);
}
+ if (tavil->anc_func) {
+ /* Clear Tx FE HOLD if both PAs are enabled */
+ if ((snd_soc_read(tavil->codec, WCD934X_ANA_HPH) &
+ 0xC0) == 0xC0)
+ tavil_codec_clear_anc_tx_hold(tavil);
+ }
+
snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x01);
/* Remove Mute on primary path */
snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
@@ -2031,6 +2211,33 @@
(snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01))
snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2,
0x04, 0x00);
+ if (!(strcmp(w->name, "ANC HPHL PA"))) {
+ pr_debug("%s:Do everything needed for right channel\n",
+ __func__);
+
+ /* Do everything needed for right channel */
+ snd_soc_update_bits(codec, WCD934X_HPH_R_TEST,
+ 0x01, 0x01);
+
+ /* Remove mute */
+ snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
+ 0x10, 0x00);
+
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_read(codec,
+ WCD934X_CDC_RX2_RX_PATH_MIX_CTL)) &
+ 0x10)
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+ 0x10, 0x00);
+ if (dsd_conf && (snd_soc_read(codec,
+ WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_DSD1_CFG2,
+ 0x04, 0x00);
+ /* Remove ANC Rx from reset */
+ ret = tavil_codec_enable_anc(w, kcontrol, event);
+ }
tavil_codec_override(codec, tavil->hph_mode, event);
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -2046,10 +2253,21 @@
snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x00);
snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
0x10, 0x10);
+ snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+ 0x10, 0x10);
+ if (!(strcmp(w->name, "ANC HPHL PA")))
+ snd_soc_update_bits(codec, WCD934X_ANA_HPH,
+ 0x80, 0x00);
break;
case SND_SOC_DAPM_POST_PMD:
- /* 5ms sleep is required after PA disable */
- usleep_range(5000, 5100);
+ /*
+ * 5ms sleep is required after PA disable. If compander is
+ * disabled, then 20ms delay is needed after PA disable.
+ */
+ if (!tavil->comp_enabled[COMPANDER_1])
+ usleep_range(20000, 20100);
+ else
+ usleep_range(5000, 5100);
tavil_codec_override(codec, tavil->hph_mode, event);
blocking_notifier_call_chain(&tavil->mbhc->notifier,
WCD_EVENT_POST_HPHL_PA_OFF,
@@ -2057,10 +2275,15 @@
if (TAVIL_IS_1_0(tavil->wcd9xxx))
snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
0x06, 0x0);
+ if (!(strcmp(w->name, "ANC HPHL PA"))) {
+ ret = tavil_codec_enable_anc(w, kcontrol, event);
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_RX1_RX_PATH_CFG0, 0x10, 0x00);
+ }
break;
};
- return 0;
+ return ret;
}
static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
@@ -2167,12 +2390,18 @@
int hph_mode = tavil->hph_mode;
u8 dem_inp;
struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+ int ret = 0;
dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__,
w->name, event, hph_mode);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if (tavil->anc_func) {
+ ret = tavil_codec_enable_anc(w, kcontrol, event);
+ /* 40 msec delay is needed to avoid click and pop */
+ msleep(40);
+ }
/* Read DEM INP Select */
dem_inp = snd_soc_read(codec, WCD934X_CDC_RX2_RX_PATH_SEC0) &
0x03;
@@ -2203,6 +2432,10 @@
WCD_CLSH_EVENT_PRE_DAC,
WCD_CLSH_STATE_HPHR,
hph_mode);
+ if (tavil->anc_func)
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_RX2_RX_PATH_CFG0,
+ 0x10, 0x10);
break;
case SND_SOC_DAPM_POST_PMD:
/* 1000us required as per HW requirement */
@@ -2246,6 +2479,11 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if (tavil->anc_func) {
+ ret = tavil_codec_enable_anc(w, kcontrol, event);
+ /* 40 msec delay is needed to avoid click and pop */
+ msleep(40);
+ }
/* Read DEM INP Select */
dem_inp = snd_soc_read(codec, WCD934X_CDC_RX1_RX_PATH_SEC0) &
0x03;
@@ -2277,6 +2515,11 @@
WCD_CLSH_STATE_HPHL,
hph_mode);
+ if (tavil->anc_func)
+ snd_soc_update_bits(codec,
+ WCD934X_CDC_RX1_RX_PATH_CFG0,
+ 0x10, 0x10);
+
ret = tavil_mbhc_get_impedance(tavil->mbhc,
&impedl, &impedr);
if (!ret) {
@@ -2596,6 +2839,8 @@
/* Undo reset for MAD */
snd_soc_update_bits(codec, WCD934X_CPE_SS_MAD_CTL,
0x02, 0x00);
+ snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+ 0x04, 0x04);
} else {
snd_soc_update_bits(codec, WCD934X_SOC_MAD_AUDIO_CTL_2,
0x03, 0x00);
@@ -2605,6 +2850,8 @@
/* Turn off MAD clk */
snd_soc_update_bits(codec, WCD934X_CPE_SS_MAD_CTL,
0x01, 0x00);
+ snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+ 0x04, 0x00);
}
done:
return rc;
@@ -3157,6 +3404,15 @@
}
EXPORT_SYMBOL(tavil_codec_enable_interp_clk);
+static int tavil_anc_out_switch_cb(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ tavil_codec_enable_interp_clk(codec, event, w->shift);
+
+ return 0;
+}
static int tavil_codec_set_idle_detect_thr(struct snd_soc_codec *codec,
int interp, int path_type)
{
@@ -3611,8 +3867,8 @@
{
int adc_mux_n = w->shift;
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
int amic_n;
- u16 amic_reg;
dev_dbg(codec->dev, "%s: event: %d\n", __func__, event);
@@ -3620,8 +3876,13 @@
case SND_SOC_DAPM_POST_PMU:
amic_n = tavil_codec_find_amic_input(codec, adc_mux_n);
if (amic_n) {
- amic_reg = WCD934X_ANA_AMIC1 + amic_n - 1;
- tavil_codec_set_tx_hold(codec, amic_reg, false);
+ /*
+ * Prevent ANC Rx pop by leaving Tx FE in HOLD
+ * state until PA is up. Track AMIC being used
+ * so we can release the HOLD later.
+ */
+ set_bit(ANC_MIC_AMIC1 + amic_n - 1,
+ &tavil->status_mask);
}
break;
default:
@@ -5123,19 +5384,18 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- u16 amic_reg;
+ u16 amic_reg = 0;
if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE"))
amic_reg = WCD934X_ANA_AMIC1;
if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE"))
amic_reg = WCD934X_ANA_AMIC3;
- else
- goto ret;
- ucontrol->value.integer.value[0] =
- (snd_soc_read(codec, amic_reg) & WCD934X_AMIC_PWR_LVL_MASK) >>
- WCD934X_AMIC_PWR_LVL_SHIFT;
-ret:
+ if (amic_reg)
+ ucontrol->value.integer.value[0] =
+ (snd_soc_read(codec, amic_reg) &
+ WCD934X_AMIC_PWR_LVL_MASK) >>
+ WCD934X_AMIC_PWR_LVL_SHIFT;
return 0;
}
@@ -5144,7 +5404,7 @@
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
u32 mode_val;
- u16 amic_reg;
+ u16 amic_reg = 0;
mode_val = ucontrol->value.enumerated.item[0];
@@ -5154,12 +5414,10 @@
amic_reg = WCD934X_ANA_AMIC1;
if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE"))
amic_reg = WCD934X_ANA_AMIC3;
- else
- goto ret;
- snd_soc_update_bits(codec, amic_reg, WCD934X_AMIC_PWR_LVL_MASK,
- mode_val << WCD934X_AMIC_PWR_LVL_SHIFT);
-ret:
+ if (amic_reg)
+ snd_soc_update_bits(codec, amic_reg, WCD934X_AMIC_PWR_LVL_MASK,
+ mode_val << WCD934X_AMIC_PWR_LVL_SHIFT);
return 0;
}
@@ -6447,6 +6705,12 @@
static const struct snd_kcontrol_new anc_spkr_pa_switch =
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+static const struct snd_kcontrol_new anc_hphl_pa_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_hphr_pa_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
static const struct snd_kcontrol_new mad_cpe1_switch =
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
@@ -7086,6 +7350,14 @@
SND_SOC_DAPM_PGA_E("ANC SPK1 PA", SND_SOC_NOPM, 0, 0, NULL, 0,
tavil_codec_enable_spkr_anc,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+ tavil_codec_enable_hphl_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+ tavil_codec_enable_hphr_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUTPUT("EAR"),
SND_SOC_DAPM_OUTPUT("HPHL"),
@@ -7095,6 +7367,8 @@
SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
SND_SOC_DAPM_OUTPUT("ANC EAR"),
+ SND_SOC_DAPM_OUTPUT("ANC HPHL"),
+ SND_SOC_DAPM_OUTPUT("ANC HPHR"),
SND_SOC_DAPM_SWITCH("ANC OUT EAR Enable", SND_SOC_NOPM, 0, 0,
&anc_ear_switch),
@@ -7103,6 +7377,13 @@
SND_SOC_DAPM_SWITCH("ANC SPKR PA Enable", SND_SOC_NOPM, 0, 0,
&anc_spkr_pa_switch),
+ SND_SOC_DAPM_SWITCH_E("ANC OUT HPHL Enable", SND_SOC_NOPM, INTERP_HPHL,
+ 0, &anc_hphl_pa_switch, tavil_anc_out_switch_cb,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SWITCH_E("ANC OUT HPHR Enable", SND_SOC_NOPM, INTERP_HPHR,
+ 0, &anc_hphr_pa_switch, tavil_anc_out_switch_cb,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
tavil_codec_enable_rx_bias,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -7839,9 +8120,9 @@
snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
- snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
snd_soc_update_bits(codec, WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
snd_soc_update_bits(codec, WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
+ snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
wcd9xxx_set_power_state(tavil->wcd9xxx,
WCD_REGION_POWER_COLLAPSE_REMOVE,
@@ -8799,13 +9080,8 @@
WCD9XXX_DIG_CORE_REGION_1);
mutex_lock(&tavil->codec_mutex);
- /*
- * Codec hardware by default comes up in SVS mode.
- * Initialize the svs_ref_cnt to 1 to reflect the hardware
- * state in the driver.
- */
- tavil->svs_ref_cnt = 1;
+ tavil_vote_svs(tavil, true);
tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la =
control->slim_slave->laddr;
tavil_slimbus_slave_port_cfg.slave_dev_pgd_la =
@@ -8813,17 +9089,9 @@
tavil_init_slim_slave_cfg(codec);
snd_soc_card_change_online_state(codec->component.card, 1);
- /* Class-H Init */
- wcd_clsh_init(&tavil->clsh_d);
- /* Default HPH Mode to Class-H LOHiFi */
- tavil->hph_mode = CLS_H_LOHIFI;
-
for (i = 0; i < TAVIL_MAX_MICBIAS; i++)
tavil->micb_ref[i] = 0;
- for (i = 0; i < COMPANDER_MAX; i++)
- tavil->comp_enabled[i] = 0;
-
dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
__func__, control->mclk_rate);
@@ -9017,6 +9285,10 @@
mutex_lock(&tavil->codec_mutex);
snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA");
mutex_unlock(&tavil->codec_mutex);
diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c
index ad62d18..9ac38c2 100644
--- a/sound/soc/codecs/wcd9xxx-common-v2.c
+++ b/sound/soc/codecs/wcd9xxx-common-v2.c
@@ -130,6 +130,81 @@
},
};
+static const struct wcd_reg_mask_val imped_table_tavil[][MAX_IMPED_PARAMS] = {
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf2},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf2},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf2},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf4},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf4},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf4},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+};
+
static const struct wcd_imped_val imped_index[] = {
{4, 0},
{5, 1},
@@ -185,12 +260,26 @@
{
int i;
int index = 0;
+ int table_size;
+
+ static const struct wcd_reg_mask_val
+ (*imped_table_ptr)[MAX_IMPED_PARAMS];
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+ if (IS_CODEC_TYPE(wcd9xxx, WCD934X)) {
+ table_size = ARRAY_SIZE(imped_table_tavil);
+ imped_table_ptr = imped_table_tavil;
+ } else {
+ table_size = ARRAY_SIZE(imped_table);
+ imped_table_ptr = imped_table;
+ }
/* reset = 1, which means request is to reset the register values */
if (reset) {
for (i = 0; i < MAX_IMPED_PARAMS; i++)
- snd_soc_update_bits(codec, imped_table[index][i].reg,
- imped_table[index][i].mask, 0);
+ snd_soc_update_bits(codec,
+ imped_table_ptr[index][i].reg,
+ imped_table_ptr[index][i].mask, 0);
return;
}
index = get_impedance_index(imped);
@@ -198,15 +287,16 @@
pr_debug("%s, impedance not in range = %d\n", __func__, imped);
return;
}
- if (index >= ARRAY_SIZE(imped_table)) {
+ if (index >= table_size) {
pr_debug("%s, impedance index not in range = %d\n", __func__,
index);
return;
}
for (i = 0; i < MAX_IMPED_PARAMS; i++)
- snd_soc_update_bits(codec, imped_table[index][i].reg,
- imped_table[index][i].mask,
- imped_table[index][i].val);
+ snd_soc_update_bits(codec,
+ imped_table_ptr[index][i].reg,
+ imped_table_ptr[index][i].mask,
+ imped_table_ptr[index][i].val);
}
EXPORT_SYMBOL(wcd_clsh_imped_config);
@@ -579,6 +669,11 @@
static void wcd_clsh_set_flyback_vneg_ctl(struct snd_soc_codec *codec,
bool enable)
{
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+ if (!TASHA_IS_2_0(wcd9xxx))
+ return;
+
if (enable) {
snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0,
0x00);
@@ -758,35 +853,35 @@
dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
is_enable ? "enable" : "disable");
- if (is_enable && (req_state == WCD_CLSH_STATE_LO)) {
- wcd_clsh_set_buck_regulator_mode(codec, CLS_AB);
- } else {
- if (req_state == WCD_CLSH_STATE_EAR)
- goto end;
-
- /* LO powerdown.
- * If EAR Class-H is already enabled, just
- * turn on regulator other enable Class-H
- * configuration
+ if (is_enable) {
+ /* LO powerup is taken care in PA sequence.
+ * No need to change to class AB here.
*/
- if (wcd_clsh_enable_status(codec)) {
- wcd_clsh_set_buck_regulator_mode(codec,
- CLS_H_NORMAL);
- goto end;
+ if (req_state == WCD_CLSH_STATE_EAR) {
+ /* EAR powerup.*/
+ if (!wcd_clsh_enable_status(codec)) {
+ wcd_enable_clsh_block(codec, clsh_d, true);
+ wcd_clsh_set_buck_mode(codec, mode);
+ wcd_clsh_set_flyback_mode(codec, mode);
+ }
+ snd_soc_update_bits(codec,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x40);
}
- wcd_enable_clsh_block(codec, clsh_d, true);
- snd_soc_update_bits(codec,
- WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
- 0x40, 0x40);
- wcd_clsh_set_buck_regulator_mode(codec,
- CLS_H_NORMAL);
- wcd_clsh_set_buck_mode(codec, mode);
- wcd_clsh_set_flyback_mode(codec, mode);
- wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
- wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
+ } else {
+ if (req_state == WCD_CLSH_STATE_EAR) {
+ /* EAR powerdown.*/
+ wcd_enable_clsh_block(codec, clsh_d, false);
+ wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+ wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+ snd_soc_update_bits(codec,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x00);
+ }
+ /* LO powerdown is taken care in PA sequence.
+ * No need to change to class H here.
+ */
}
-end:
- return;
}
static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec,
@@ -1135,6 +1230,7 @@
case WCD_CLSH_STATE_HPHL_LO:
case WCD_CLSH_STATE_HPHR_LO:
case WCD_CLSH_STATE_HPH_ST_LO:
+ case WCD_CLSH_STATE_EAR_LO:
return true;
default:
return false;
diff --git a/sound/soc/codecs/wcd9xxx-common-v2.h b/sound/soc/codecs/wcd9xxx-common-v2.h
index ee7e587..53c9a84 100644
--- a/sound/soc/codecs/wcd9xxx-common-v2.h
+++ b/sound/soc/codecs/wcd9xxx-common-v2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -34,7 +34,12 @@
#define WCD_CLSH_STATE_HPHL (0x01 << 1)
#define WCD_CLSH_STATE_HPHR (0x01 << 2)
#define WCD_CLSH_STATE_LO (0x01 << 3)
-#define WCD_CLSH_STATE_MAX 4
+
+/*
+ * Though number of CLSH states are 4, max state shoulbe be 5
+ * because state array index starts from 1.
+ */
+#define WCD_CLSH_STATE_MAX 5
#define NUM_CLSH_STATES_V2 (0x01 << WCD_CLSH_STATE_MAX)
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index fde13d2..8780888 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -247,9 +247,15 @@
* to CLK_SYS_MCLK_PRG
*/
wcd_resmgr_codec_reg_update_bits(resmgr,
+ WCD934X_CLK_SYS_MCLK_PRG, 0x80, 0x80);
+ wcd_resmgr_codec_reg_update_bits(resmgr,
+ WCD934X_CLK_SYS_MCLK_PRG, 0x30, 0x10);
+ wcd_resmgr_codec_reg_update_bits(resmgr,
WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00);
wcd_resmgr_codec_reg_update_bits(resmgr,
- WCD934X_CLK_SYS_MCLK_PRG, 0x91, 0x91);
+ WCD934X_CLK_SYS_MCLK_PRG, 0x01, 0x01);
+ wcd_resmgr_codec_reg_update_bits(resmgr,
+ WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00);
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
0x01, 0x01);
@@ -257,9 +263,6 @@
WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x01);
wcd_resmgr_codec_reg_update_bits(resmgr,
- WCD934X_CODEC_RPM_CLK_MCLK_CFG,
- 0x04, 0x04);
- wcd_resmgr_codec_reg_update_bits(resmgr,
WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x01);
wcd_resmgr_codec_reg_update_bits(resmgr,
@@ -305,6 +308,9 @@
0x08, 0x08);
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x02);
+ /* Disable clock buffer */
+ wcd_resmgr_codec_reg_update_bits(resmgr,
+ WCD934X_CLK_SYS_MCLK_PRG, 0x80, 0x00);
resmgr->clk_type = WCD_CLK_RCO;
} else {
wcd_resmgr_codec_reg_update_bits(resmgr,
diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c
index c98fdc9..cf014d7 100644
--- a/sound/soc/codecs/wcd_cpe_core.c
+++ b/sound/soc/codecs/wcd_cpe_core.c
@@ -887,14 +887,7 @@
* instead SSR handler will control CPE.
*/
wcd_cpe_enable_cpe_clks(core, false);
- /*
- * During BUS_DOWN event, possibly the
- * irq driver is under cleanup, do not request
- * cleanup of irqs here, rather cleanup irqs
- * once BUS_UP event is received.
- */
- if (core->ssr_type != WCD_CPE_BUS_DOWN_EVENT)
- wcd_cpe_cleanup_irqs(core);
+ wcd_cpe_cleanup_irqs(core);
goto done;
}
@@ -1145,7 +1138,6 @@
break;
case WCD_CPE_BUS_UP_EVENT:
- wcd_cpe_cleanup_irqs(core);
wcd_cpe_set_and_complete(core, WCD_CPE_BUS_READY);
/*
* In case of bus up event ssr_type will be changed
@@ -3024,7 +3016,7 @@
static int wcd_cpe_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 *data, uint32_t param_type)
{
struct wcd_cpe_core *core = core_handle;
int rc = 0;
@@ -3039,25 +3031,9 @@
rc = wcd_cpe_send_param_epd_thres(core, session,
data, &ids);
break;
- case LSM_OPERATION_MODE: {
- struct cpe_lsm_ids connectport_ids;
-
- rc = wcd_cpe_send_param_opmode(core, session,
- data, &ids);
- if (rc)
- break;
-
- connectport_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
- connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
-
- rc = wcd_cpe_send_param_connectport(core, session, NULL,
- &connectport_ids, CPE_AFE_PORT_1_TX);
- if (rc)
- dev_err(core->dev,
- "%s: send_param_connectport failed, err %d\n",
- __func__, rc);
+ case LSM_OPERATION_MODE:
+ rc = wcd_cpe_send_param_opmode(core, session, data, &ids);
break;
- }
case LSM_GAIN:
rc = wcd_cpe_send_param_gain(core, session, data, &ids);
break;
@@ -3076,13 +3052,13 @@
break;
default:
pr_err("%s: wrong param_type 0x%x\n",
- __func__, p_info->param_type);
+ __func__, param_type);
}
if (rc)
dev_err(core->dev,
"%s: send_param(%d) failed, err %d\n",
- __func__, p_info->param_type, rc);
+ __func__, param_type, rc);
return rc;
}
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index e689570..fe15a57 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -757,15 +757,13 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
wsa881x_resource_acquire(codec, ENABLE);
- if (wsa881x->boost_enable)
- wsa881x_boost_ctrl(codec, ENABLE);
+ wsa881x_boost_ctrl(codec, ENABLE);
break;
case SND_SOC_DAPM_POST_PMD:
swr_slvdev_datapath_control(wsa881x->swr_slave,
wsa881x->swr_slave->dev_num,
false);
- if (wsa881x->boost_enable)
- wsa881x_boost_ctrl(codec, DISABLE);
+ wsa881x_boost_ctrl(codec, DISABLE);
wsa881x_resource_acquire(codec, DISABLE);
break;
}
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 5f9d42c..8f8ab44 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -108,7 +108,7 @@
listen on codec.
config SND_SOC_INT_CODEC
- tristate "SoC Machine driver for MSMFALCON_INT"
+ tristate "SoC Machine driver for SDM660_INT"
depends on ARCH_QCOM
select SND_SOC_QDSP6V2
select SND_SOC_MSM_STUB
@@ -119,17 +119,18 @@
select MSM_QDSP6_PDR
select MSM_QDSP6_NOTIFIER
select MSM_QDSP6V2_CODECS
- select SND_SOC_MSM_SWR
- select SND_SOC_MSM8X16_WCD
+ select MSM_CDC_PINCTRL
+ select SND_SOC_MSM_SDW
+ select SND_SOC_SDM660_CDC
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_SDM660_COMMON
select SND_SOC_COMPRESS
+ select PINCTRL_LPI
help
To add support for SoC audio on MSM_INT.
This will enable sound soc drivers which
@@ -138,7 +139,7 @@
DAI-links
config SND_SOC_EXT_CODEC
- tristate "SoC Machine driver for MSMFALCON_EXT"
+ tristate "SoC Machine driver for SDM660_EXT"
depends on ARCH_QCOM
select SND_SOC_QDSP6V2
select SND_SOC_MSM_STUB
@@ -155,15 +156,15 @@
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_SDM660_COMMON
select SND_SOC_COMPRESS
+ select PINCTRL_LPI
help
To add support for SoC audio on MSM_EXT.
This will enable sound soc drivers which
@@ -230,13 +231,13 @@
the machine driver and the corresponding
DAI-links
-config SND_SOC_FALCON
- tristate "SoC Machine driver for MSMFALCON boards"
- depends on ARCH_MSMFALCON
+config SND_SOC_660
+ tristate "SoC Machine driver for SDM660 boards"
+ depends on ARCH_SDM660
select SND_SOC_INT_CODEC
select SND_SOC_EXT_CODEC
help
- To add support for SoC audio on MSMFALCON.
+ To add support for SoC audio on SDM660.
This will enable sound soc drivers which
interfaces with DSP, also it will enable
the machine driver and the corresponding
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index e0544fc..5105cd9 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -20,18 +20,18 @@
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 SDM660 sound card driver
+snd-soc-sdm660-common-objs := sdm660-common.o
+obj-$(CONFIG_SND_SOC_SDM660_COMMON) += snd-soc-sdm660-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
+# for SDM660 sound card driver
+snd-soc-int-codec-objs := sdm660-internal.o
+obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-sdm660-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
+# for SDM660 sound card driver
+snd-soc-ext-codec-objs := sdm660-external.o sdm660-ext-dai-links.o
+obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-sdm660-common.o
obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-ext-codec.o
# for SDM845 sound card driver
diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c
index 44927c8..4f83e79 100644
--- a/sound/soc/msm/msm-cpe-lsm.c
+++ b/sound/soc/msm/msm-cpe-lsm.c
@@ -1046,7 +1046,6 @@
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;
@@ -1176,13 +1175,6 @@
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));
@@ -1320,19 +1312,21 @@
break;
case SNDRV_LSM_EVENT_STATUS:
+ case SNDRV_LSM_EVENT_STATUS_V3: {
+ struct snd_lsm_event_status *user;
+ struct snd_lsm_event_status_v3 *user_v3;
+
dev_dbg(rtd->dev,
"%s: %s\n",
- __func__, "SNDRV_LSM_EVENT_STATUS");
+ __func__, "SNDRV_LSM_EVENT_STATUS(_V3)");
if (!arg) {
dev_err(rtd->dev,
"%s: Invalid argument to ioctl %s\n",
__func__,
- "SNDRV_LSM_EVENT_STATUS");
+ "SNDRV_LSM_EVENT_STATUS(_V3)");
return -EINVAL;
}
- user = arg;
-
/*
* Release the api lock before wait to allow
* other IOCTLs to be invoked while waiting
@@ -1352,31 +1346,62 @@
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;
+
+ if (cmd == SNDRV_LSM_EVENT_STATUS) {
+ user = arg;
+ 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 {
+ user_v3 = arg;
+ if (lsm_d->ev_det_pld_size >
+ user_v3->payload_size) {
+ dev_err(rtd->dev,
+ "%s: avail pld_bytes = %u, needed = %u\n",
+ __func__,
+ user_v3->payload_size,
+ lsm_d->ev_det_pld_size);
+ return -EINVAL;
+ }
+ /* event status timestamp not supported
+ * on CPE mode. Set msw and lsw to 0.
+ */
+ user_v3->timestamp_lsw = 0;
+ user_v3->timestamp_msw = 0;
+ user_v3->status = lsm_d->ev_det_status;
+ user_v3->payload_size =
+ lsm_d->ev_det_pld_size;
+ memcpy(user_v3->payload,
+ lsm_d->ev_det_payload,
+ lsm_d->ev_det_pld_size);
}
-
- 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;
+ if (cmd == SNDRV_LSM_EVENT_STATUS) {
+ user = arg;
+ user->payload_size = 0;
+ } else {
+ user_v3 = arg;
+ user_v3->payload_size = 0;
+ }
rc = 0;
}
}
-
+ }
break;
case SNDRV_LSM_ABORT_EVENT:
@@ -1432,12 +1457,6 @@
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) {
@@ -1514,6 +1533,20 @@
}
break;
+ case SNDRV_LSM_SET_PORT: {
+ u32 port_id = cpe->input_port_id;
+
+ dev_dbg(rtd->dev, "%s: %s\n", __func__, "SNDRV_LSM_SET_PORT");
+ rc = lsm_ops->lsm_set_port(cpe->core_handle, session, &port_id);
+ if (rc) {
+ dev_err(rtd->dev,
+ "%s: lsm_set_port failed, err = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+ break;
+
default:
dev_dbg(rtd->dev,
"%s: Default snd_lib_ioctl cmd 0x%x\n",
@@ -1525,7 +1558,7 @@
}
static int msm_cpe_lsm_lab_start(struct snd_pcm_substream *substream,
- struct snd_lsm_event_status *event_status)
+ u16 event_det_status)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
@@ -1578,7 +1611,7 @@
reinit_completion(&lab_d->thread_complete);
if (session->lab_enable &&
- event_status->status ==
+ event_det_status ==
LSM_VOICE_WAKEUP_STATUS_DETECTED) {
out_port = &session->afe_out_port_cfg;
out_port->port_id = session->afe_out_port_id;
@@ -1873,6 +1906,13 @@
lsm_ops->lsm_get_snd_model_offset(cpe->core_handle,
session, &offset);
+ /* Check if 'p_info->param_size + offset' crosses U32_MAX. */
+ if (p_info->param_size > U32_MAX - offset) {
+ dev_err(rtd->dev,
+ "%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ return -EINVAL;
+ }
session->snd_model_size = p_info->param_size + offset;
session->snd_model_data = vzalloc(session->snd_model_size);
@@ -2173,7 +2213,60 @@
goto done;
}
- msm_cpe_lsm_lab_start(substream, event_status);
+ msm_cpe_lsm_lab_start(substream, event_status->status);
+ msm_cpe_process_event_status_done(lsm_d);
+ kfree(event_status);
+ }
+ break;
+ case SNDRV_LSM_EVENT_STATUS_V3: {
+ struct snd_lsm_event_status_v3 u_event_status;
+ struct snd_lsm_event_status_v3 *event_status = NULL;
+ int u_pld_size = 0;
+
+ if (copy_from_user(&u_event_status, (void *)arg,
+ sizeof(struct snd_lsm_event_status_v3))) {
+ dev_err(rtd->dev,
+ "%s: event status copy from user failed, size %zd\n",
+ __func__,
+ sizeof(struct snd_lsm_event_status_v3));
+ 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_v3) +
+ 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->status);
msm_cpe_process_event_status_done(lsm_d);
kfree(event_status);
}
@@ -2282,12 +2375,6 @@
}
#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;
@@ -2309,7 +2396,7 @@
u32 param_id;
u32 param_size;
compat_uptr_t param_data;
- enum LSM_PARAM_TYPE param_type;
+ uint32_t param_type;
};
struct snd_lsm_module_params_32 {
@@ -2319,8 +2406,6 @@
};
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 =
@@ -2414,7 +2499,7 @@
err);
}
break;
- case SNDRV_LSM_EVENT_STATUS32: {
+ case SNDRV_LSM_EVENT_STATUS: {
struct snd_lsm_event_status *event_status = NULL;
struct snd_lsm_event_status u_event_status32;
struct snd_lsm_event_status *udata_32 = NULL;
@@ -2456,7 +2541,6 @@
} 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)
@@ -2495,7 +2579,97 @@
goto done;
}
- msm_cpe_lsm_lab_start(substream, event_status);
+ msm_cpe_lsm_lab_start(substream, event_status->status);
+ msm_cpe_process_event_status_done(lsm_d);
+ kfree(event_status);
+ kfree(udata_32);
+ }
+ break;
+ case SNDRV_LSM_EVENT_STATUS_V3: {
+ struct snd_lsm_event_status_v3 *event_status = NULL;
+ struct snd_lsm_event_status_v3 u_event_status32;
+ struct snd_lsm_event_status_v3 *udata_32 = NULL;
+ int u_pld_size = 0;
+
+ dev_dbg(rtd->dev,
+ "%s: ioctl %s\n", __func__,
+ "SNDRV_LSM_EVENT_STATUS_V3_32");
+
+ if (copy_from_user(&u_event_status32, (void *)arg,
+ sizeof(struct snd_lsm_event_status_v3))) {
+ dev_err(rtd->dev,
+ "%s: event status copy from user failed, size %zd\n",
+ __func__,
+ sizeof(struct snd_lsm_event_status_v3));
+ 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_v3) +
+ 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;
+ 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_STATUS_V3_32",
+ 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->timestamp_lsw =
+ event_status->timestamp_lsw;
+ udata_32->timestamp_msw =
+ event_status->timestamp_msw;
+ 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->status);
msm_cpe_process_event_status_done(lsm_d);
kfree(event_status);
kfree(udata_32);
@@ -2556,13 +2730,6 @@
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,
@@ -2640,6 +2807,19 @@
kfree(params32);
break;
}
+ case SNDRV_LSM_REG_SND_MODEL_V2:
+ case SNDRV_LSM_SET_PARAMS:
+ case SNDRV_LSM_SET_MODULE_PARAMS:
+ /*
+ * In ideal cases, the compat_ioctl should never be called
+ * with the above unlocked ioctl commands. Print error
+ * and return error if it does.
+ */
+ dev_err(rtd->dev,
+ "%s: Invalid cmd for compat_ioctl\n",
+ __func__);
+ err = -EINVAL;
+ break;
default:
err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg);
break;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 081f8b4..782fa9a 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -506,6 +506,33 @@
},
{
.playback = {
+ .stream_name = "SLIMBUS7_HOSTLESS Playback",
+ .aif_name = "SLIM7_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 = "SLIMBUS7_HOSTLESS Capture",
+ .aif_name = "SLIM7_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 = "SLIMBUS7_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
.stream_name = "SLIMBUS8_HOSTLESS Playback",
.aif_name = "SLIM8_DL_HL",
.rates = SNDRV_PCM_RATE_8000_384000,
@@ -583,6 +610,49 @@
},
{
.playback = {
+ .stream_name = "USBAUDIO_HOSTLESS Playback",
+ .aif_name = "USBAUDIO_DL_HL",
+ .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_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "USBAUDIO_HOSTLESS Capture",
+ .aif_name = "USBAUDIO_UL_HL",
+ .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_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "USBAUDIO_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
.stream_name = "AFE Playback",
.aif_name = "PCM_RX",
.rates = (SNDRV_PCM_RATE_8000 |
@@ -902,6 +972,22 @@
.name = "INT4_MI2S_RX_HOSTLESS",
.probe = fe_dai_probe,
},
+ {
+ .capture = {
+ .stream_name = "INT3 MI2S_TX Hostless Capture",
+ .aif_name = "INT3_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 = "INT3_MI2S_TX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
/* TDM Hostless */
{
.capture = {
@@ -2117,12 +2203,14 @@
.capture = {
.stream_name = "Listen 1 Audio Service Capture",
.aif_name = "LSM1_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
.name = "LSM1",
@@ -2132,12 +2220,14 @@
.capture = {
.stream_name = "Listen 2 Audio Service Capture",
.aif_name = "LSM2_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
.name = "LSM2",
@@ -2147,12 +2237,14 @@
.capture = {
.stream_name = "Listen 3 Audio Service Capture",
.aif_name = "LSM3_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
.name = "LSM3",
@@ -2162,12 +2254,14 @@
.capture = {
.stream_name = "Listen 4 Audio Service Capture",
.aif_name = "LSM4_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
.name = "LSM4",
@@ -2177,12 +2271,14 @@
.capture = {
.stream_name = "Listen 5 Audio Service Capture",
.aif_name = "LSM5_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
.name = "LSM5",
@@ -2192,12 +2288,14 @@
.capture = {
.stream_name = "Listen 6 Audio Service Capture",
.aif_name = "LSM6_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
.name = "LSM6",
@@ -2207,12 +2305,14 @@
.capture = {
.stream_name = "Listen 7 Audio Service Capture",
.aif_name = "LSM7_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
.name = "LSM7",
@@ -2222,12 +2322,14 @@
.capture = {
.stream_name = "Listen 8 Audio Service Capture",
.aif_name = "LSM8_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
.name = "LSM8",
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 54e72e0..ac31ca3 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -3321,6 +3321,18 @@
134, 135, 136, 137, 138, 139,
140, 141, 142, 143};
+ /* Tavil Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch_tavil[WCD934X_RX_MAX] = {144, 145, 146, 147, 148,
+ 149, 150, 151};
+ unsigned int tx_ch_tavil[WCD934X_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;
@@ -3369,20 +3381,27 @@
snd_soc_dapm_ignore_suspend(dapm, "HPHR");
snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
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")) {
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch_tavil),
+ tx_ch_tavil, ARRAY_SIZE(rx_ch_tavil),
+ rx_ch_tavil);
+ } else {
+ 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;
@@ -4970,6 +4989,22 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
},
+ {
+ .name = "USB Audio Hostless",
+ .stream_name = "USB Audio Hostless",
+ .cpu_dai_name = "USBAUDIO_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,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
};
static struct snd_soc_dai_link msm_common_be_dai_links[] = {
diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
index f88087b..5d4a0ba 100644
--- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c
+++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
@@ -119,6 +119,9 @@
case AFE_SIDETONE_CAL_TYPE:
size = sizeof(struct audio_cal_info_sidetone);
break;
+ case AFE_SIDETONE_IIR_CAL_TYPE:
+ size = sizeof(struct audio_cal_info_sidetone_iir);
+ break;
case LSM_CUST_TOPOLOGY_CAL_TYPE:
size = 0;
break;
@@ -265,6 +268,9 @@
case AFE_SIDETONE_CAL_TYPE:
size = sizeof(struct audio_cal_type_sidetone);
break;
+ case AFE_SIDETONE_IIR_CAL_TYPE:
+ size = sizeof(struct audio_cal_type_sidetone_iir);
+ break;
case LSM_CUST_TOPOLOGY_CAL_TYPE:
size = sizeof(struct audio_cal_type_basic);
break;
@@ -598,7 +604,6 @@
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) {
@@ -630,6 +635,7 @@
goto err;
}
cal_block->buffer_number = basic_cal->cal_hdr.buffer_number;
+ list_add_tail(&cal_block->list, &cal_type->cal_blocks);
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,
@@ -639,6 +645,8 @@
done:
return cal_block;
err:
+ kfree(cal_block->cal_info);
+ kfree(cal_block->client_info);
kfree(cal_block);
cal_block = NULL;
return cal_block;
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 48f58f1..9cd233c 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -760,7 +760,7 @@
COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
prtd->compr_cap.max_fragments =
COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
- prtd->compr_cap.num_codecs = 14;
+ prtd->compr_cap.num_codecs = 15;
prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
@@ -775,6 +775,7 @@
prtd->compr_cap.codecs[11] = SND_AUDIOCODEC_APE;
prtd->compr_cap.codecs[12] = SND_AUDIOCODEC_DTS;
prtd->compr_cap.codecs[13] = SND_AUDIOCODEC_DSD;
+ prtd->compr_cap.codecs[14] = SND_AUDIOCODEC_APTX;
}
static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -794,6 +795,7 @@
struct asm_alac_cfg alac_cfg;
struct asm_ape_cfg ape_cfg;
struct asm_dsd_cfg dsd_cfg;
+ struct aptx_dec_bt_addr_cfg aptx_cfg;
union snd_codec_options *codec_options;
int ret = 0;
@@ -869,6 +871,9 @@
if (prtd->codec_param.codec.format ==
SND_AUDIOSTREAMFORMAT_MP4ADTS)
aac_cfg.format = 0x0;
+ else if (prtd->codec_param.codec.format ==
+ SND_AUDIOSTREAMFORMAT_MP4LATM)
+ aac_cfg.format = 0x04;
else
aac_cfg.format = 0x03;
aac_cfg.ch_cfg = prtd->num_channels;
@@ -1025,6 +1030,24 @@
pr_err("%s: CMD DSD Format block failed ret %d\n",
__func__, ret);
break;
+ case FORMAT_APTX:
+ pr_debug("SND_AUDIOCODEC_APTX\n");
+ memset(&aptx_cfg, 0x0, sizeof(struct aptx_dec_bt_addr_cfg));
+ ret = q6asm_stream_media_format_block_aptx_dec(
+ prtd->audio_client,
+ prtd->sample_rate,
+ stream_id);
+ if (ret >= 0) {
+ aptx_cfg.nap = codec_options->aptx_dec.nap;
+ aptx_cfg.uap = codec_options->aptx_dec.uap;
+ aptx_cfg.lap = codec_options->aptx_dec.lap;
+ q6asm_set_aptx_dec_bt_addr(prtd->audio_client,
+ &aptx_cfg);
+ } else {
+ pr_err("%s: CMD Format block failed ret %d\n",
+ __func__, ret);
+ }
+ break;
default:
pr_debug("%s, unsupported format, skip", __func__);
break;
@@ -1247,8 +1270,13 @@
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 (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) {
+ ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
+ bits_per_sample, true);
+ } else {
+ ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
+ bits_per_sample, false);
+ }
if (ret < 0) {
pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret);
return ret;
@@ -1791,6 +1819,12 @@
break;
}
+ case SND_AUDIOCODEC_APTX: {
+ pr_debug("%s: SND_AUDIOCODEC_APTX\n", __func__);
+ prtd->codec = FORMAT_APTX;
+ break;
+ }
+
default:
pr_err("codec not supported, id =%d\n", params->codec.id);
return -EINVAL;
@@ -2664,6 +2698,7 @@
case SND_AUDIOCODEC_DTS:
break;
case SND_AUDIOCODEC_DSD:
+ case SND_AUDIOCODEC_APTX:
break;
default:
pr_err("%s: Unsupported audio codec %d\n",
@@ -3078,6 +3113,7 @@
switch (prtd->codec) {
case FORMAT_MP3:
case FORMAT_MPEG4_AAC:
+ case FORMAT_APTX:
pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
prtd->codec);
break;
@@ -3144,6 +3180,7 @@
case FORMAT_APE:
case FORMAT_DTS:
case FORMAT_DSD:
+ case FORMAT_APTX:
pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
prtd->codec);
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 52c2296..9abe04a 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -51,6 +51,11 @@
ENC_FMT_APTX_HD = ASM_MEDIA_FMT_APTX_HD,
};
+enum {
+ SPKR_1,
+ SPKR_2,
+};
+
static const struct afe_clk_set lpass_clk_set_default = {
AFE_API_VERSION_CLOCK_SET,
Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT,
@@ -175,6 +180,7 @@
u16 afe_in_bitformat;
struct afe_enc_config enc_config;
union afe_port_config port_config;
+ u16 vi_feed_mono;
};
struct msm_dai_q6_spdif_dai_data {
@@ -230,8 +236,14 @@
"Compr-60958"
};
+static const char *const mi2s_vi_feed_mono[] = {
+ "Left",
+ "Right",
+};
+
static const struct soc_enum mi2s_config_enum[] = {
SOC_ENUM_SINGLE_EXT(4, mi2s_format),
+ SOC_ENUM_SINGLE_EXT(2, mi2s_vi_feed_mono),
};
static const char *const sb_format[] = {
@@ -1882,6 +1894,11 @@
pr_err("%s: rx slot not found\n", __func__);
return -EINVAL;
}
+ if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+ pr_err("%s: invalid rx num %d\n", __func__, rx_num);
+ return -EINVAL;
+ }
+
for (i = 0; i < rx_num; i++) {
dai_data->port_config.slim_sch.shared_ch_mapping[i] =
rx_slot[i];
@@ -1914,6 +1931,11 @@
pr_err("%s: tx slot not found\n", __func__);
return -EINVAL;
}
+ if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+ pr_err("%s: invalid tx num %d\n", __func__, tx_num);
+ return -EINVAL;
+ }
+
for (i = 0; i < tx_num; i++) {
dai_data->port_config.slim_sch.shared_ch_mapping[i] =
tx_slot[i];
@@ -3308,6 +3330,26 @@
return 0;
}
+static int msm_dai_q6_mi2s_vi_feed_mono_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->vi_feed_mono = value;
+ pr_debug("%s: value = %d\n", __func__, value);
+ return 0;
+}
+
+static int msm_dai_q6_mi2s_vi_feed_mono_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->vi_feed_mono;
+ 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,
@@ -3342,6 +3384,15 @@
SOC_ENUM_EXT("SENARY MI2S TX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("INT5 MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+};
+
+static const struct snd_kcontrol_new mi2s_vi_feed_controls[] = {
+ SOC_ENUM_EXT("INT5 MI2S VI MONO", mi2s_config_enum[1],
+ msm_dai_q6_mi2s_vi_feed_mono_get,
+ msm_dai_q6_mi2s_vi_feed_mono_put),
};
static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
@@ -3353,6 +3404,7 @@
struct snd_kcontrol *kcontrol = NULL;
int rc = 0;
const struct snd_kcontrol_new *ctrl = NULL;
+ const struct snd_kcontrol_new *vi_feed_ctrl = NULL;
dai->id = mi2s_pdata->intf_id;
@@ -3394,6 +3446,8 @@
ctrl = &mi2s_config_controls[9];
if (dai->id == MSM_SENARY_MI2S)
ctrl = &mi2s_config_controls[10];
+ if (dai->id == MSM_INT5_MI2S)
+ ctrl = &mi2s_config_controls[11];
}
if (ctrl) {
@@ -3408,6 +3462,21 @@
__func__, dai->name);
}
}
+
+ if (dai->id == MSM_INT5_MI2S)
+ vi_feed_ctrl = &mi2s_vi_feed_controls[0];
+
+ if (vi_feed_ctrl) {
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(vi_feed_ctrl,
+ &mi2s_dai_data->tx_dai.mi2s_dai_data));
+
+ if (rc < 0) {
+ dev_err(dai->dev, "%s: err add TX vi feed channel ctl DAI = %s\n",
+ __func__, dai->name);
+ }
+ }
+
rc = msm_dai_q6_dai_add_route(dai);
rtn:
return rc;
@@ -3654,8 +3723,12 @@
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;
+ if (dai_data->vi_feed_mono == SPKR_1)
+ dai_data->port_config.i2s.channel_mode =
+ AFE_PORT_I2S_SD0;
+ else
+ dai_data->port_config.i2s.channel_mode =
+ AFE_PORT_I2S_SD1;
break;
case AFE_PORT_I2S_QUAD23:
dai_data->port_config.i2s.channel_mode =
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-slim.c b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
index 77fb8d4..779a2e6 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-slim.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
@@ -313,7 +313,7 @@
struct msm_slim_dai_data *dai_data = NULL;
struct slim_ch prop;
int rc;
- u8 i, j;
+ u8 i;
dai_data = msm_slim_get_dai_data(drv_data, dai);
if (!dai_data) {
@@ -330,6 +330,13 @@
return -EINVAL;
}
+ if (dai_data->status & DAI_STATE_PREPARED) {
+ dev_dbg(dai->dev,
+ "%s: dai id (%d) has already prepared.\n",
+ __func__, dai->id);
+ return 0;
+ }
+
dma_data = &dai_data->dma_data;
snd_soc_dai_set_dma_data(dai, substream, dma_data);
@@ -343,6 +350,10 @@
}
}
+ /* To decrement the channel ref count*/
+ for (i = 0; i < dai_data->ch_cnt; i++)
+ slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
+
prop.prot = SLIM_AUTO_ISO;
prop.baser = SLIM_RATE_4000HZ;
prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
@@ -366,8 +377,6 @@
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;
}
@@ -377,7 +386,6 @@
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);
@@ -396,15 +404,6 @@
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);
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index 29a1b3d..41cb983 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 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.
@@ -18,6 +18,10 @@
#include "msm-dolby-dap-config.h"
+#ifndef DOLBY_PARAM_VCNB_MAX_LENGTH
+#define DOLBY_PARAM_VCNB_MAX_LENGTH 40
+#endif
+
/* dolby endp based parameters */
struct dolby_dap_endp_params_s {
int device;
@@ -679,7 +683,7 @@
struct snd_ctl_elem_value *ucontrol)
{
int rc = 0, port_id, copp_idx;
- uint32_t idx, j;
+ uint32_t idx, j, current_offset;
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];
@@ -756,6 +760,19 @@
default: {
/* cache the parameters */
dolby_dap_params_modified[idx] += 1;
+ current_offset = dolby_dap_params_offset[idx] + offset;
+ if (current_offset >= TOTAL_LENGTH_DOLBY_PARAM) {
+ pr_err("%s: invalid offset %d at idx %d\n",
+ __func__, offset, idx);
+ return -EINVAL;
+ }
+ if ((length == 0) || (current_offset + length - 1
+ < current_offset) || (current_offset + length
+ > TOTAL_LENGTH_DOLBY_PARAM)) {
+ pr_err("%s: invalid length %d at idx %d\n",
+ __func__, length, idx);
+ return -EINVAL;
+ }
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);
@@ -801,7 +818,11 @@
__func__, copp_idx);
return -EINVAL;
}
- params_value = kzalloc(params_length, GFP_KERNEL);
+ if (dolby_dap_params_get.length > 128 - DOLBY_PARAM_PAYLOAD_SIZE) {
+ pr_err("%s: Incorrect parameter length", __func__);
+ return -EINVAL;
+ }
+ params_value = kzalloc(params_length + param_payload_len, GFP_KERNEL);
if (!params_value)
return -ENOMEM;
@@ -819,8 +840,7 @@
pr_err("%s: invalid param id to set", __func__);
rc = -EINVAL;
} else {
- params_length = (dolby_dap_params_length[i] +
- DOLBY_PARAM_PAYLOAD_SIZE) *
+ params_length = dolby_dap_params_length[i] *
sizeof(uint32_t);
rc = adm_get_params(port_id, copp_idx,
DOLBY_BUNDLE_MODULE_ID,
@@ -899,6 +919,11 @@
DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
int port_id, copp_idx, idx;
+ if (length > DOLBY_PARAM_VCNB_MAX_LENGTH || length <= 0) {
+ pr_err("%s Incorrect VCNB length", __func__);
+ ucontrol->value.integer.value[0] = 0;
+ return -EINVAL;
+ }
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];
diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
index 0ba1661..b7e69fa 100644
--- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
@@ -198,7 +198,8 @@
uint32_t param_payload_len = PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
int rc = 0;
- update_params_value = kzalloc(params_length, GFP_KERNEL);
+ update_params_value = kzalloc(params_length + param_payload_len,
+ GFP_KERNEL);
if (!update_params_value)
goto end;
@@ -999,6 +1000,20 @@
copp_idx, rc);
}
}
+ /* Turn on 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 enable %d\n",
+ __func__, mod_list[j]);
+ adm_param_enable(port_id, copp_idx,
+ mod_list[j],
+ MODULE_ENABLE);
+ }
+
/* Add adm api to resend calibration on port */
rc = msm_ds2_dap_send_cal_data(i);
if (rc < 0) {
@@ -1642,6 +1657,7 @@
ret = 0;
dolby_data->length = 0;
pr_err("%s Incorrect VCNB length", __func__);
+ return -EINVAL;
}
params_length = (2*length + DOLBY_VIS_PARAM_HEADER_SIZE) *
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index e283aa9..695c02d 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
+ * 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
@@ -35,7 +35,7 @@
#define CAPTURE_MIN_NUM_PERIODS 2
#define CAPTURE_MAX_NUM_PERIODS 8
-#define CAPTURE_MAX_PERIOD_SIZE 4096
+#define CAPTURE_MAX_PERIOD_SIZE 61440
#define CAPTURE_MIN_PERIOD_SIZE 320
#define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256
@@ -47,12 +47,14 @@
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,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .rates = (SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000),
.rate_min = 16000,
- .rate_max = 16000,
+ .rate_max = 48000,
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 4,
.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
CAPTURE_MAX_PERIOD_SIZE,
.period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
@@ -64,7 +66,7 @@
/* Conventional and unconventional sample rate supported */
static unsigned int supported_sample_rates[] = {
- 16000,
+ 16000, 48000,
};
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -76,7 +78,7 @@
struct lsm_priv {
struct snd_pcm_substream *substream;
struct lsm_client *lsm_client;
- struct snd_lsm_event_status *event_status;
+ struct snd_lsm_event_status_v3 *event_status;
spinlock_t event_lock;
wait_queue_head_t event_wait;
unsigned long event_avail;
@@ -88,6 +90,11 @@
int dma_write;
};
+enum { /* lsm session states */
+ IDLE = 0,
+ RUNNING,
+};
+
static int msm_lsm_queue_lab_buffer(struct lsm_priv *prtd, int i)
{
int rc = 0;
@@ -193,10 +200,12 @@
struct lsm_priv *prtd = priv;
struct snd_pcm_substream *substream = prtd->substream;
struct snd_soc_pcm_runtime *rtd;
- struct snd_lsm_event_status *temp;
+ struct snd_lsm_event_status_v3 *temp;
uint16_t status = 0;
uint16_t payload_size = 0;
uint16_t index = 0;
+ uint32_t event_ts_lsw = 0;
+ uint32_t event_ts_msw = 0;
if (!substream || !substream->private_data) {
pr_err("%s: Invalid %s\n", __func__,
@@ -271,25 +280,45 @@
"%s: event detect status = %d payload size = %d\n",
__func__, status, payload_size);
break;
+
+ case LSM_SESSION_EVENT_DETECTION_STATUS_V3:
+ event_ts_lsw = ((uint32_t *)payload)[0];
+ event_ts_msw = ((uint32_t *)payload)[1];
+ status = (uint16_t)((uint8_t *)payload)[8];
+ payload_size = (uint16_t)((uint8_t *)payload)[9];
+ index = 10;
+ dev_dbg(rtd->dev,
+ "%s: ts_msw = %u, ts_lsw = %u, event detect status = %d payload size = %d\n",
+ __func__, event_ts_msw, event_ts_lsw, status,
+ payload_size);
+ break;
+
default:
break;
}
if (opcode == LSM_SESSION_EVENT_DETECTION_STATUS ||
- opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2) {
+ opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2 ||
+ opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V3) {
spin_lock_irqsave(&prtd->event_lock, flags);
temp = krealloc(prtd->event_status,
- sizeof(struct snd_lsm_event_status) +
+ sizeof(struct snd_lsm_event_status_v3) +
payload_size, GFP_ATOMIC);
if (!temp) {
dev_err(rtd->dev, "%s: no memory for event status\n",
__func__);
return;
}
-
+ /*
+ * event status timestamp will be non-zero and valid if
+ * opcode is LSM_SESSION_EVENT_DETECTION_STATUS_V3
+ */
prtd->event_status = temp;
+ prtd->event_status->timestamp_lsw = event_ts_lsw;
+ prtd->event_status->timestamp_msw = event_ts_msw;
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],
@@ -641,6 +670,54 @@
return rc;
}
+static int msm_lsm_set_poll_enable(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_poll_enable poll_enable;
+ int rc = 0;
+
+ if (p_info->param_size != sizeof(poll_enable)) {
+ dev_err(rtd->dev,
+ "%s: Invalid param_size %d\n",
+ __func__, p_info->param_size);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(&poll_enable, p_info->param_data,
+ sizeof(poll_enable))) {
+ dev_err(rtd->dev,
+ "%s: copy_from_user failed, size = %zd\n",
+ __func__, sizeof(poll_enable));
+ rc = -EFAULT;
+ goto done;
+ }
+
+ if (prtd->lsm_client->poll_enable == poll_enable.poll_en) {
+ dev_dbg(rtd->dev,
+ "%s: Polling for session %d already %s\n",
+ __func__, prtd->lsm_client->session,
+ (poll_enable.poll_en ? "enabled" : "disabled"));
+ rc = 0;
+ goto done;
+ }
+
+ rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+ &poll_enable, LSM_POLLING_ENABLE);
+ if (!rc) {
+ prtd->lsm_client->poll_enable = poll_enable.poll_en;
+ } else {
+ dev_err(rtd->dev,
+ "%s: Failed to set poll enable, err = %d\n",
+ __func__, rc);
+ }
+done:
+ return rc;
+}
+
static int msm_lsm_process_params(struct snd_pcm_substream *substream,
struct snd_lsm_module_params *p_data,
void *params)
@@ -681,6 +758,9 @@
case LSM_CUSTOM_PARAMS:
rc = msm_lsm_set_custom(substream, p_info);
break;
+ case LSM_POLLING_ENABLE:
+ rc = msm_lsm_set_poll_enable(substream, p_info);
+ break;
default:
dev_err(rtd->dev,
"%s: Invalid param_type %d\n",
@@ -710,10 +790,8 @@
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;
@@ -870,6 +948,10 @@
break;
case SNDRV_LSM_EVENT_STATUS:
+ case SNDRV_LSM_EVENT_STATUS_V3: {
+ uint32_t ts_lsw, ts_msw;
+ uint16_t status = 0, payload_size = 0;
+
dev_dbg(rtd->dev, "%s: Get event status\n", __func__);
atomic_set(&prtd->event_wait_stop, 0);
rc = wait_event_freezable(prtd->event_wait,
@@ -882,9 +964,12 @@
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;
+ payload_size = prtd->event_status->payload_size;
+ ts_lsw = prtd->event_status->timestamp_lsw;
+ ts_msw = prtd->event_status->timestamp_msw;
+ status = prtd->event_status->status;
spin_unlock_irqrestore(&prtd->event_lock,
flags);
} else {
@@ -896,15 +981,43 @@
__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;
+
+ if (cmd == SNDRV_LSM_EVENT_STATUS) {
+ struct snd_lsm_event_status *user = arg;
+
+ if (user->payload_size < payload_size) {
+ dev_dbg(rtd->dev,
+ "%s: provided %d bytes isn't enough, needs %d bytes\n",
+ __func__, user->payload_size,
+ payload_size);
+ rc = -ENOMEM;
+ } else {
+ user->status = status;
+ user->payload_size = payload_size;
+ memcpy(user->payload,
+ prtd->event_status->payload,
+ payload_size);
+ }
} else {
- memcpy(user, prtd->event_status, size);
+ struct snd_lsm_event_status_v3 *user_v3 = arg;
+
+ if (user_v3->payload_size < payload_size) {
+ dev_dbg(rtd->dev,
+ "%s: provided %d bytes isn't enough, needs %d bytes\n",
+ __func__, user_v3->payload_size,
+ payload_size);
+ rc = -ENOMEM;
+ } else {
+ user_v3->timestamp_lsw = ts_lsw;
+ user_v3->timestamp_msw = ts_msw;
+ user_v3->status = status;
+ user_v3->payload_size = payload_size;
+ memcpy(user_v3->payload,
+ prtd->event_status->payload,
+ payload_size);
+ }
+ }
+ if (!rc) {
if (prtd->lsm_client->lab_enable
&& !prtd->lsm_client->lab_started
&& prtd->event_status->status ==
@@ -929,6 +1042,7 @@
rc = 0;
}
break;
+ }
case SNDRV_LSM_ABORT_EVENT:
dev_dbg(rtd->dev, "%s: Aborting event status wait\n",
@@ -1035,6 +1149,43 @@
prtd->lsm_client->lab_started = false;
}
break;
+
+ case SNDRV_LSM_SET_PORT:
+ dev_dbg(rtd->dev, "%s: set LSM port\n", __func__);
+ rc = q6lsm_set_port_connected(prtd->lsm_client);
+ break;
+
+ case SNDRV_LSM_SET_FWK_MODE_CONFIG: {
+ u32 *mode = NULL;
+
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: Invalid param arg for ioctl %s session %d\n",
+ __func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG",
+ prtd->lsm_client->session);
+ rc = -EINVAL;
+ break;
+ }
+ mode = (u32 *)arg;
+ if (prtd->lsm_client->event_mode == *mode) {
+ dev_dbg(rtd->dev,
+ "%s: mode for %d already set to %d\n",
+ __func__, prtd->lsm_client->session, *mode);
+ rc = 0;
+ } else {
+ dev_dbg(rtd->dev, "%s: Event mode = %d\n",
+ __func__, *mode);
+ rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, *mode);
+ if (!rc)
+ prtd->lsm_client->event_mode = *mode;
+ else
+ dev_err(rtd->dev,
+ "%s: set event mode failed %d\n",
+ __func__, rc);
+ }
+ break;
+ }
+
default:
dev_dbg(rtd->dev,
"%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
@@ -1053,6 +1204,21 @@
return rc;
}
#ifdef CONFIG_COMPAT
+
+struct snd_lsm_event_status32 {
+ u16 status;
+ u16 payload_size;
+ u8 payload[0];
+};
+
+struct snd_lsm_event_status_v3_32 {
+ u32 timestamp_lsw;
+ u32 timestamp_msw;
+ u16 status;
+ u16 payload_size;
+ u8 payload[0];
+};
+
struct snd_lsm_sound_model_v2_32 {
compat_uptr_t data;
compat_uptr_t confidence_level;
@@ -1074,7 +1240,7 @@
u32 param_id;
u32 param_size;
compat_uptr_t param_data;
- enum LSM_PARAM_TYPE param_type;
+ uint32_t param_type;
};
struct snd_lsm_module_params_32 {
@@ -1090,6 +1256,8 @@
_IOW('U', 0x0A, struct snd_lsm_detection_params_32),
SNDRV_LSM_SET_MODULE_PARAMS_32 =
_IOW('U', 0x0B, struct snd_lsm_module_params_32),
+ SNDRV_LSM_EVENT_STATUS_V3_32 =
+ _IOW('U', 0x0F, struct snd_lsm_event_status_v3_32),
};
static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
@@ -1180,6 +1348,73 @@
break;
}
+ case SNDRV_LSM_EVENT_STATUS_V3_32: {
+ struct snd_lsm_event_status_v3_32 userarg32, *user32 = NULL;
+ struct snd_lsm_event_status_v3 *user = NULL;
+
+ if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
+ dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
+ __func__, "SNDRV_LSM_EVENT_STATUS_V3_32");
+ 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;
+ }
+ cmd = SNDRV_LSM_EVENT_STATUS_V3;
+ 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->timestamp_lsw = user->timestamp_lsw;
+ user32->timestamp_msw = user->timestamp_msw;
+ 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;
@@ -1568,6 +1803,67 @@
"%s: lsmevent failed %d", __func__, err);
return err;
}
+
+ case SNDRV_LSM_EVENT_STATUS_V3: {
+ struct snd_lsm_event_status_v3 *user = NULL;
+ struct snd_lsm_event_status_v3 userarg;
+
+ dev_dbg(rtd->dev,
+ "%s: SNDRV_LSM_EVENT_STATUS_V3\n", __func__);
+ if (!arg) {
+ dev_err(rtd->dev,
+ "%s: Invalid params event_status_v3\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (copy_from_user(&userarg, arg, sizeof(userarg))) {
+ dev_err(rtd->dev,
+ "%s: err copyuser event_status_v3\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_v3) +
+ 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: lsm_event_v3 failed %d", __func__, err);
+ break;
+ }
+
default:
err = msm_lsm_ioctl_shared(substream, cmd, arg);
break;
@@ -1635,6 +1931,11 @@
return -ENOMEM;
}
prtd->lsm_client->opened = false;
+ prtd->lsm_client->session_state = IDLE;
+ prtd->lsm_client->poll_enable = true;
+ prtd->lsm_client->perf_mode = 0;
+ prtd->lsm_client->event_mode = LSM_EVENT_NON_TIME_STAMP_MODE;
+
return 0;
}
@@ -1643,6 +1944,7 @@
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__);
@@ -1656,9 +1958,30 @@
"%s: LSM client data ptr is NULL\n", __func__);
return -EINVAL;
}
+
+ if (q6lsm_set_media_fmt_params(prtd->lsm_client))
+ dev_dbg(rtd->dev,
+ "%s: failed to set lsm media fmt params\n", __func__);
+
+ if (prtd->lsm_client->session_state == IDLE) {
+ ret = msm_pcm_routing_reg_phy_compr_stream(
+ rtd->dai_link->id,
+ prtd->lsm_client->perf_mode,
+ prtd->lsm_client->session,
+ SNDRV_PCM_STREAM_CAPTURE,
+ LISTEN);
+ if (ret) {
+ dev_err(rtd->dev,
+ "%s: register phy compr stream failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ prtd->lsm_client->session_state = RUNNING;
prtd->lsm_client->started = false;
runtime->private_data = prtd;
- return 0;
+ return ret;
}
static int msm_lsm_close(struct snd_pcm_substream *substream)
@@ -1707,6 +2030,9 @@
__func__);
}
+ msm_pcm_routing_dereg_phy_stream(rtd->dai_link->id,
+ SNDRV_PCM_STREAM_CAPTURE);
+
if (prtd->lsm_client->opened) {
q6lsm_close(prtd->lsm_client);
prtd->lsm_client->opened = false;
@@ -1728,7 +2054,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data;
- struct lsm_lab_hw_params *hw_params = NULL;
+ struct lsm_hw_params *hw_params = NULL;
struct snd_soc_pcm_runtime *rtd;
if (!substream->private_data) {
@@ -1744,25 +2070,36 @@
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->num_chs = params_channels(params);
hw_params->period_count = params_periods(params);
- if (hw_params->sample_rate != 16000 || hw_params->sample_size != 16 ||
- hw_params->period_count == 0) {
+ hw_params->sample_rate = params_rate(params);
+ if (((hw_params->sample_rate != 16000) &&
+ (hw_params->sample_rate != 48000)) ||
+ (hw_params->period_count == 0)) {
dev_err(rtd->dev,
- "%s: Invalid params sample rate %d sample size %d period count %d",
+ "%s: Invalid Params sample rate %d period count %d\n",
__func__, hw_params->sample_rate,
- hw_params->sample_size,
- hw_params->period_count);
+ hw_params->period_count);
return -EINVAL;
}
+
+ 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 {
+ dev_err(rtd->dev, "%s: Invalid Format 0x%x\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
hw_params->buf_sz = params_buffer_bytes(params) /
- hw_params->period_count;
+ 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);
+ "%s: channels %d sample rate %d sample size %d buffer size %d period count %d\n",
+ __func__, hw_params->num_chs, hw_params->sample_rate,
+ hw_params->sample_size, hw_params->buf_sz,
+ hw_params->period_count);
return 0;
}
@@ -1858,6 +2195,109 @@
return 0;
}
+static int msm_lsm_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;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if ((fe_id < MSM_FRONTEND_DAI_LSM1) ||
+ (fe_id > MSM_FRONTEND_DAI_LSM8)) {
+ 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];
+ 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_lsm_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_LSM1) ||
+ (fe_id > MSM_FRONTEND_DAI_LSM8)) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ 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_lsm_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 *mixer_ctl_name = "Listen Stream";
+ const char *deviceNo = "NN";
+ const char *suffix = "App Type Cfg";
+ int ctl_len, ret = 0;
+
+ ctl_len = strlen(mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Listen app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ NULL, 1, ctl_len, rtd->dai_link->id,
+ &app_type_info);
+ if (ret < 0) {
+ pr_err("%s: Listen 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",
+ mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_lsm_app_type_cfg_ctl_put;
+ kctl->get = msm_lsm_app_type_cfg_ctl_get;
+ return 0;
+}
+
+static int msm_lsm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+
+ ret = msm_lsm_add_app_type_controls(rtd);
+ if (ret)
+ pr_err("%s, add app type controls failed:%d\n", __func__, ret);
+
+ return ret;
+}
+
static const struct snd_pcm_ops msm_lsm_ops = {
.open = msm_lsm_open,
.close = msm_lsm_close,
@@ -1872,11 +2312,16 @@
static int msm_asoc_lsm_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 0;
+ ret = msm_lsm_add_controls(rtd);
+ if (ret)
+ pr_err("%s, kctl add failed:%d\n", __func__, ret);
+
+ return ret;
}
static int msm_asoc_lsm_probe(struct snd_soc_platform *platform)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index 15809ce..c22f348 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -25,6 +25,7 @@
#include <sound/control.h>
#include <sound/tlv.h>
#include <asm/dma.h>
+#include <sound/q6audio-v2.h>
#include "msm-pcm-routing-v2.h"
@@ -67,6 +68,10 @@
static u32 hfp_tx_mute;
+struct msm_pcm_pdata {
+ int perf_mode;
+};
+
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);
@@ -245,6 +250,7 @@
struct msm_pcm_routing_evt event;
struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
uint32_t param_id;
+ struct msm_pcm_pdata *pdata;
ret = msm_pcm_loopback_get_session(rtd, &pcm);
if (ret)
@@ -270,6 +276,15 @@
if (pcm->audio_client != NULL)
stop_pcm(pcm);
+ pdata = (struct msm_pcm_pdata *)
+ dev_get_drvdata(rtd->platform->dev);
+ if (!pdata) {
+ dev_err(rtd->platform->dev,
+ "%s: platform data not populated\n", __func__);
+ mutex_unlock(&pcm->lock);
+ return -EINVAL;
+ }
+
pcm->audio_client = q6asm_audio_client_alloc(
(app_cb)msm_pcm_loopback_event_handler, pcm);
if (!pcm->audio_client) {
@@ -279,7 +294,7 @@
return -ENOMEM;
}
pcm->session_id = pcm->audio_client->session;
- pcm->audio_client->perf_mode = false;
+ pcm->audio_client->perf_mode = pdata->perf_mode;
ret = q6asm_open_loopback_v2(pcm->audio_client,
bits_per_sample);
if (ret < 0) {
@@ -746,9 +761,23 @@
static int msm_pcm_probe(struct platform_device *pdev)
{
+ struct msm_pcm_pdata *pdata;
+
dev_dbg(&pdev->dev, "%s: dev name %s\n",
__func__, dev_name(&pdev->dev));
+ pdata = kzalloc(sizeof(struct msm_pcm_pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (of_property_read_bool(pdev->dev.of_node,
+ "qcom,msm-pcm-loopback-low-latency"))
+ pdata->perf_mode = LOW_LATENCY_PCM_MODE;
+ else
+ pdata->perf_mode = LEGACY_PCM_MODE;
+
+ dev_set_drvdata(&pdev->dev, pdata);
+
return snd_soc_register_platform(&pdev->dev,
&msm_soc_platform);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index e899f5e..45a3ce9 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -424,7 +424,7 @@
prtd->audio_client->perf_mode);
ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
- bits_per_sample);
+ bits_per_sample, false);
if (ret < 0) {
pr_err("%s: q6asm_open_read failed\n", __func__);
q6asm_audio_client_free(prtd->audio_client);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 4f91a87..a9e00cd 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -64,14 +64,20 @@
static int fm_switch_enable;
static int hfp_switch_enable;
+static int int0_mi2s_switch_enable;
+static int int4_mi2s_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 usb_switch_enable;
+static int lsm_port_index;
static int slim0_rx_aanc_fb_port;
static int msm_route_ec_ref_rx;
+static int msm_ec_ref_ch = 4;
+static int msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int msm_ec_ref_sampling_rate = 48000;
static uint32_t voc_session_id = ALL_SESSION_VSID;
static int msm_route_ext_ec_ref;
static bool is_custom_stereo_on;
@@ -85,6 +91,8 @@
MADSWAUDIO,
};
+#define ADM_LSM_PORT_INDEX 9
+
#define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
#define SLIMBUS_1_TX_TEXT "SLIMBUS_1_TX"
#define SLIMBUS_2_TX_TEXT "SLIMBUS_2_TX"
@@ -92,12 +100,14 @@
#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 QUAT_MI2S_TX_TEXT "QUAT_MI2S_TX"
+#define ADM_LSM_TX_TEXT "ADM_LSM_TX"
#define LSM_FUNCTION_TEXT "LSM Function"
-static const char * const mad_audio_mux_text[] = {
+static const char * const lsm_port_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
+ TERT_MI2S_TX_TEXT, QUAT_MI2S_TX_TEXT, ADM_LSM_TX_TEXT
};
struct msm_pcm_route_bdai_pp_params {
@@ -265,253 +275,261 @@
#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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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 */
+/* Track ASM playback & capture sessions of DAI
+ * Track LSM listen sessions
+ */
static struct msm_pcm_routing_fdai_data
- fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+ fe_dai_map[MSM_FRONTEND_DAI_MAX][2] = {
/* MULTIMEDIA1 */
{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
@@ -569,13 +587,80 @@
/* MULTIMEDIA19 */
{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* CS_VOICE */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOIP */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* AFE_RX */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* AFE_TX */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOICE_STUB */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOLTE */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* DTMF_RX */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOICE2 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* QCHAT */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOLTE_STUB */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* LSM1 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* LSM2 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* LSM3 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* LSM4 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* LSM5 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* LSM6 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* LSM7 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* LSM8 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOICE2_STUB */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOWLAN */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOICEMMODE1 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* VOICEMMODE2 */
+ {{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]
+static unsigned long session_copp_map[MSM_FRONTEND_DAI_MAX][2]
[MSM_BACKEND_DAI_MAX];
static struct msm_pcm_routing_app_type_data app_type_cfg[MAX_APP_TYPES];
+static struct msm_pcm_routing_app_type_data lsm_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];
+ fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MAX][2];
/* The caller of this should aqcuire routing lock */
void msm_pcm_routing_get_bedai_info(int be_idx,
@@ -618,13 +703,39 @@
return 0;
}
+static int msm_pcm_routing_get_lsm_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 (lsm_app_type_cfg[idx].app_type == app_type)
+ return idx;
+ }
+ pr_debug("%s: App type not available, fallback to default\n", __func__);
+ return 0;
+}
+
+static bool is_mm_lsm_fe_id(int fe_id)
+{
+ bool rc = true;
+
+ if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID &&
+ ((fe_id < MSM_FRONTEND_DAI_LSM1) ||
+ (fe_id > MSM_FRONTEND_DAI_LSM8))) {
+ rc = false;
+ }
+ return rc;
+}
+
+
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) {
+ if (!is_mm_lsm_fe_id(fedai_id)) {
pr_err("%s: Invalid machine driver ID %d\n",
__func__, fedai_id);
return;
@@ -671,7 +782,7 @@
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) {
+ } else if (!is_mm_lsm_fe_id(fedai_id)) {
pr_err("%s: Invalid FE ID %d\n",
__func__, fedai_id);
ret = -EINVAL;
@@ -719,8 +830,7 @@
static struct cal_block_data *msm_routing_find_topology(int path,
int app_type,
- int acdb_id,
- int sample_rate)
+ int acdb_id)
{
struct list_head *ptr, *next;
struct cal_block_data *cal_block = NULL;
@@ -738,13 +848,12 @@
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)) {
+ (cal_info->acdb_id == acdb_id)) {
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);
+ pr_debug("%s: Can't find topology for path %d, app %d, acdb_id %d defaulting to search by path\n",
+ __func__, path, app_type, acdb_id);
return msm_routing_find_topology_by_path(path);
}
@@ -753,7 +862,7 @@
{
int topology = NULL_COPP_TOPOLOGY;
struct cal_block_data *cal_block = NULL;
- int app_type = 0, acdb_dev_id = 0, sample_rate = 0;
+ int app_type = 0, acdb_dev_id = 0;
pr_debug("%s\n", __func__);
@@ -765,10 +874,8 @@
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);
+ cal_block = msm_routing_find_topology(path, app_type, acdb_dev_id);
if (cal_block == NULL)
goto unlock;
@@ -792,7 +899,8 @@
}
static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
- int path_type, int perf_mode)
+ int path_type, int perf_mode,
+ uint32_t passthr_mode)
{
int i, port_type, j, num_copps = 0;
struct route_payload payload;
@@ -805,7 +913,7 @@
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))) {
+ (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))) {
for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
unsigned long copp =
session_copp_map[fedai_id][sess_type][i];
@@ -828,7 +936,7 @@
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);
+ adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
}
@@ -862,7 +970,7 @@
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))) {
+ (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))) {
mode = afe_get_port_type(msm_bedais[i].port_id);
adm_connect_afe_port(mode, dspst_id,
msm_bedais[i].port_id);
@@ -872,28 +980,51 @@
mutex_unlock(&routing_lock);
}
+static bool route_check_fe_id_adm_support(int fe_id)
+{
+ bool rc = true;
+
+ if ((fe_id >= MSM_FRONTEND_DAI_LSM1) &&
+ (fe_id <= MSM_FRONTEND_DAI_LSM8)) {
+ /* fe id is listen while port is set to afe */
+ if (lsm_port_index != ADM_LSM_PORT_INDEX) {
+ pr_debug("%s: fe_id %d, lsm mux slim port %d\n",
+ __func__, fe_id, lsm_port_index);
+ rc = false;
+ }
+ }
+
+ return rc;
+}
+
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)
+ uint32_t 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;
+ bool is_lsm;
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) {
+ stream_type, passthr_mode);
+ if (!is_mm_lsm_fe_id(fe_id)) {
/* bad ID assigned in machine driver */
pr_err("%s: bad MM ID %d\n", __func__, fe_id);
return -EINVAL;
}
+ if (!route_check_fe_id_adm_support(fe_id)) {
+ /* ignore adm open if not supported for fe_id */
+ pr_debug("%s: No ADM support for fe id %d\n", __func__, fe_id);
+ return 0;
+ }
+
if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
session_type = SESSION_TYPE_RX;
- if (compr_passthr_mode != LEGACY_PCM)
+ if (passthr_mode != LEGACY_PCM)
path_type = ADM_PATH_COMPRESSED_RX;
else
path_type = ADM_PATH_PLAYBACK;
@@ -907,6 +1038,8 @@
return -EINVAL;
}
+ is_lsm = (fe_id >= MSM_FRONTEND_DAI_LSM1) &&
+ (fe_id <= MSM_FRONTEND_DAI_LSM8);
mutex_lock(&routing_lock);
payload.num_copps = 0; /* only RX needs to use payload */
@@ -914,14 +1047,14 @@
/* 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 (test_bit(fe_id, &msm_bedais[i].fe_sessions[0]))
+ msm_bedais[i].passthr_mode = 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))) {
+ (test_bit(fe_id, &msm_bedais[i].fe_sessions[0]))) {
int app_type, app_type_idx, copp_idx, acdb_dev_id;
/*
@@ -937,7 +1070,15 @@
msm_bedais[i].format);
app_type =
fe_dai_app_type_cfg[fe_id][session_type].app_type;
- if (app_type) {
+ if (app_type && is_lsm) {
+ app_type_idx =
+ msm_pcm_routing_get_lsm_app_type_idx(app_type);
+ sample_rate =
+ fe_dai_app_type_cfg[fe_id][session_type].
+ sample_rate;
+ bit_width =
+ lsm_app_type_cfg[app_type_idx].bit_width;
+ } else if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(
app_type);
@@ -952,9 +1093,10 @@
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)
+
+ if (passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
topology = COMPRESS_PASSTHROUGH_NONE_TOPOLOGY;
- pr_err("%s: Before adm open topology %d\n", __func__,
+ pr_debug("%s: Before adm open topology %d\n", __func__,
topology);
copp_idx =
@@ -991,7 +1133,7 @@
num_copps++;
}
}
- if (compr_passthr_mode != COMPRESSED_PASSTHROUGH_DSD) {
+ if (passthr_mode != COMPRESSED_PASSTHROUGH_DSD) {
msm_routing_send_device_pp_params(
msm_bedais[i].port_id,
copp_idx);
@@ -1005,7 +1147,9 @@
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);
+ payload.sample_rate =
+ fe_dai_app_type_cfg[fe_id][session_type].sample_rate;
+ adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
mutex_unlock(&routing_lock);
@@ -1056,6 +1200,7 @@
struct route_payload payload;
u32 channels, sample_rate;
uint16_t bits_per_sample = 16;
+ uint32_t passthr_mode = LEGACY_PCM;
if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
/* bad ID assigned in machine driver */
@@ -1085,7 +1230,7 @@
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))) {
+ (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))) {
int app_type, app_type_idx, copp_idx, acdb_dev_id;
/*
* check if ADM needs to be configured with different
@@ -1095,7 +1240,7 @@
channels = msm_bedais[i].channel;
else
channels = msm_bedais[i].adm_override_ch;
- msm_bedais[i].compr_passthr_mode =
+ msm_bedais[i].passthr_mode =
LEGACY_PCM;
bits_per_sample = msm_routing_get_bit_width(
@@ -1152,7 +1297,7 @@
}
}
if ((perf_mode == LEGACY_PCM_MODE) &&
- (msm_bedais[i].compr_passthr_mode ==
+ (msm_bedais[i].passthr_mode ==
LEGACY_PCM))
msm_pcm_routing_cfg_pp(msm_bedais[i].port_id,
copp_idx, topology,
@@ -1168,7 +1313,7 @@
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);
+ adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
mutex_unlock(&routing_lock);
@@ -1197,7 +1342,7 @@
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) {
+ if (!is_mm_lsm_fe_id(fedai_id)) {
/* bad ID assigned in machine driver */
pr_err("%s: bad MM ID\n", __func__);
return;
@@ -1218,7 +1363,7 @@
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))) {
+ (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))) {
int idx;
unsigned long copp =
session_copp_map[fedai_id][session_type][i];
@@ -1243,7 +1388,7 @@
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 ==
+ (msm_bedais[i].passthr_mode ==
LEGACY_PCM))
msm_pcm_routing_deinit_pp(msm_bedais[i].port_id,
topology);
@@ -1260,13 +1405,13 @@
{
bool rc = false;
- if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ if (!is_mm_lsm_fe_id(fe_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))
+ if (test_bit(fe_id, &msm_bedais[be_id].fe_sessions[0]))
rc = true;
return rc;
@@ -1278,19 +1423,27 @@
u32 channels, sample_rate;
uint16_t bits_per_sample = 16;
struct msm_pcm_routing_fdai_data *fdai;
+ uint32_t passthr_mode = msm_bedais[reg].passthr_mode;
+ bool is_lsm;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
- if (val > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ if (!is_mm_lsm_fe_id(val)) {
/* recheck FE ID in the mixer control defined in this file */
pr_err("%s: bad MM ID\n", __func__);
return;
}
+ if (!route_check_fe_id_adm_support(val)) {
+ /* ignore adm open if not supported for fe_id */
+ pr_debug("%s: No ADM support for fe id %d\n", __func__, val);
+ 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)
+ if (passthr_mode != LEGACY_PCM)
path_type = ADM_PATH_COMPRESSED_RX;
else
path_type = ADM_PATH_PLAYBACK;
@@ -1298,15 +1451,17 @@
session_type = SESSION_TYPE_TX;
path_type = ADM_PATH_LIVE_REC;
}
+ is_lsm = (val >= MSM_FRONTEND_DAI_LSM1) &&
+ (val <= MSM_FRONTEND_DAI_LSM8);
mutex_lock(&routing_lock);
if (set) {
- if (!test_bit(val, &msm_bedais[reg].fe_sessions) &&
+ if (!test_bit(val, &msm_bedais[reg].fe_sessions[0]) &&
((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);
+ set_bit(val, &msm_bedais[reg].fe_sessions[0]);
fdai = &fe_dai_map[val][session_type];
if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
@@ -1337,7 +1492,15 @@
app_type =
fe_dai_app_type_cfg[val][session_type].app_type;
- if (app_type) {
+ if (app_type && is_lsm) {
+ app_type_idx =
+ msm_pcm_routing_get_lsm_app_type_idx(app_type);
+ sample_rate =
+ fe_dai_app_type_cfg[val][session_type].
+ sample_rate;
+ bits_per_sample =
+ lsm_app_type_cfg[app_type_idx].bit_width;
+ } else if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
@@ -1382,20 +1545,20 @@
msm_pcm_routing_build_matrix(val, session_type,
path_type,
- fdai->perf_mode);
+ fdai->perf_mode,
+ passthr_mode);
if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
- (msm_bedais[reg].compr_passthr_mode ==
- LEGACY_PCM))
+ (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) &&
+ if (test_bit(val, &msm_bedais[reg].fe_sessions[0]) &&
((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);
+ clear_bit(val, &msm_bedais[reg].fe_sessions[0]);
fdai = &fe_dai_map[val][session_type];
if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
@@ -1420,14 +1583,14 @@
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))
+ (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);
+ fdai->perf_mode,
+ passthr_mode);
}
}
if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
@@ -1443,7 +1606,7 @@
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+ if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]))
ucontrol->value.integer.value[0] = 1;
else
ucontrol->value.integer.value[0] = 0;
@@ -1479,6 +1642,51 @@
return 1;
}
+static int msm_routing_get_listen_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[0]))
+ 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_listen_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;
+
+ pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+ ucontrol->value.integer.value[0]);
+
+ if (ucontrol->value.integer.value[0]) {
+ if (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]) {
+ if (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;
@@ -1495,9 +1703,9 @@
mutex_lock(&routing_lock);
if (set)
- set_bit(val, &msm_bedais[reg].fe_sessions);
+ set_bit(val, &msm_bedais[reg].fe_sessions[0]);
else
- clear_bit(val, &msm_bedais[reg].fe_sessions);
+ clear_bit(val, &msm_bedais[reg].fe_sessions[0]);
if (val == MSM_FRONTEND_DAI_DTMF_RX &&
afe_get_port_type(msm_bedais[reg].port_id) ==
@@ -1556,7 +1764,7 @@
mutex_lock(&routing_lock);
- if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+ if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]))
ucontrol->value.integer.value[0] = 1;
else
ucontrol->value.integer.value[0] = 0;
@@ -1600,7 +1808,7 @@
mutex_lock(&routing_lock);
- if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+ if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]))
ucontrol->value.integer.value[0] = 1;
else
ucontrol->value.integer.value[0] = 0;
@@ -1625,14 +1833,14 @@
if (ucontrol->value.integer.value[0]) {
mutex_lock(&routing_lock);
- set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+ set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]);
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);
+ clear_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]);
mutex_unlock(&routing_lock);
snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
@@ -1703,6 +1911,93 @@
return 1;
}
+static int msm_routing_get_int0_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = int0_mi2s_switch_enable;
+ pr_debug("%s: INT0 MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_int0_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: INT0 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);
+ int0_mi2s_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_get_int4_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = int4_mi2s_switch_enable;
+ pr_debug("%s: INT4 MI2S Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_int4_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: INT4 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);
+ int4_mi2s_switch_enable = ucontrol->value.integer.value[0];
+ return 1;
+}
+
+static int msm_routing_get_usb_switch_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = usb_switch_enable;
+ pr_debug("%s: HFP Switch enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_routing_put_usb_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: USB 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);
+ usb_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)
{
@@ -1852,23 +2147,24 @@
return 1;
}
-static int msm_routing_lsm_mux_get(struct snd_kcontrol *kcontrol,
+static int msm_routing_lsm_port_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = lsm_mux_slim_port;
+ ucontrol->value.integer.value[0] = lsm_port_index;
return 0;
}
-static int msm_routing_lsm_mux_put(struct snd_kcontrol *kcontrol,
+static int msm_routing_lsm_port_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;
+
+ if (mux >= e->items) {
+ pr_err("%s: Invalid mux value %d\n", __func__, mux);
+ return -EINVAL;
+ }
pr_debug("%s: LSM enable %ld\n", __func__,
ucontrol->value.integer.value[0]);
@@ -1894,21 +2190,18 @@
case 7:
lsm_port = AFE_PORT_ID_TERTIARY_MI2S_TX;
break;
+ case 8:
+ lsm_port = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
+ case 9:
+ lsm_port = ADM_LSM_PORT_ID;
+ 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];
- }
+ lsm_port_index = ucontrol->value.integer.value[0];
return 0;
}
@@ -1921,22 +2214,27 @@
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]))
+ for (i = 0; i < ARRAY_SIZE(lsm_port_text); i++)
+ if (!strnstr(kcontrol->id.name, lsm_port_text[i],
+ strlen(lsm_port_text[i])))
break;
- if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+ if (i-- == ARRAY_SIZE(lsm_port_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])) {
+ if (!strcmp(kcontrol->id.name, lsm_port_text[7])) {
ucontrol->value.integer.value[0] = MADSWAUDIO;
return 0;
}
port_id = i * 2 + 1 + SLIMBUS_0_RX;
+
+ if (!strcmp(kcontrol->id.name, lsm_port_text[8]))
+ port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+
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);
@@ -1971,11 +2269,12 @@
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]))
+ for (i = 0; i < ARRAY_SIZE(lsm_port_text); i++)
+ if (strnstr(kcontrol->id.name, lsm_port_text[i],
+ strlen(lsm_port_text[i])))
break;
- if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+ if (i-- == ARRAY_SIZE(lsm_port_text)) {
WARN(1, "Invalid id name %s\n", kcontrol->id.name);
return -EINVAL;
}
@@ -2003,11 +2302,16 @@
}
/*Check for Tertiary TX port*/
- if (!strcmp(kcontrol->id.name, mad_audio_mux_text[7])) {
+ if (strnstr(kcontrol->id.name, lsm_port_text[7],
+ strlen(lsm_port_text[7]))) {
port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
mad_type = MAD_SW_AUDIO;
}
+ if (strnstr(kcontrol->id.name, lsm_port_text[8],
+ strlen(lsm_port_text[8])))
+ port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+
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);
@@ -2172,6 +2476,144 @@
return 1;
}
+static int msm_ec_ref_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_ec_ref_ch;
+ pr_debug("%s: msm_ec_ref_ch = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_ec_ref_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_ec_ref_ch = ucontrol->value.integer.value[0];
+ pr_debug("%s: msm_ec_ref_ch = %d\n", __func__, msm_ec_ref_ch);
+ adm_num_ec_ref_rx_chans(msm_ec_ref_ch);
+ return 0;
+}
+
+static const char *const ec_ref_ch_text[] = {"Zero", "One", "Two", "Three",
+ "Four", "Five", "Six", "Seven", "Eight"};
+
+static int msm_ec_ref_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (msm_ec_ref_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: msm_ec_ref_bit_format = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_ec_ref_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 bit_width = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 1:
+ msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ default:
+ msm_ec_ref_bit_format = 0;
+ break;
+ }
+
+ if (msm_ec_ref_bit_format == SNDRV_PCM_FORMAT_S16_LE)
+ bit_width = 16;
+ else if (msm_ec_ref_bit_format == SNDRV_PCM_FORMAT_S24_LE)
+ bit_width = 24;
+
+ pr_debug("%s: msm_ec_ref_bit_format = %d\n",
+ __func__, msm_ec_ref_bit_format);
+ adm_ec_ref_rx_bit_width(bit_width);
+ return 0;
+}
+
+static char const *ec_ref_bit_format_text[] = {"0", "S16_LE", "S24_LE"};
+
+static int msm_ec_ref_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_ec_ref_sampling_rate;
+ pr_debug("%s: msm_ec_ref_sampling_rate = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_ec_ref_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm_ec_ref_sampling_rate = 0;
+ break;
+ case 1:
+ msm_ec_ref_sampling_rate = 8000;
+ break;
+ case 2:
+ msm_ec_ref_sampling_rate = 16000;
+ break;
+ case 3:
+ msm_ec_ref_sampling_rate = 32000;
+ break;
+ case 4:
+ msm_ec_ref_sampling_rate = 44100;
+ break;
+ case 5:
+ msm_ec_ref_sampling_rate = 48000;
+ break;
+ case 6:
+ msm_ec_ref_sampling_rate = 96000;
+ break;
+ case 7:
+ msm_ec_ref_sampling_rate = 192000;
+ break;
+ case 8:
+ msm_ec_ref_sampling_rate = 384000;
+ break;
+ default:
+ msm_ec_ref_sampling_rate = 48000;
+ break;
+ }
+ pr_debug("%s: msm_ec_ref_sampling_rate = %d\n",
+ __func__, msm_ec_ref_sampling_rate);
+ adm_ec_ref_rx_sampling_rate(msm_ec_ref_sampling_rate);
+ return 0;
+}
+
+static const char *const ec_ref_rate_text[] = {"0", "8000", "16000",
+ "32000", "44100", "48000", "96000", "192000", "384000"};
+
+static const struct soc_enum msm_route_ec_ref_params_enum[] = {
+ SOC_ENUM_SINGLE_EXT(9, ec_ref_ch_text),
+ SOC_ENUM_SINGLE_EXT(3, ec_ref_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(9, ec_ref_rate_text),
+};
+
+static const struct snd_kcontrol_new ec_ref_param_controls[] = {
+ SOC_ENUM_EXT("EC Reference Channels", msm_route_ec_ref_params_enum[0],
+ msm_ec_ref_ch_get, msm_ec_ref_ch_put),
+ SOC_ENUM_EXT("EC Reference Bit Format", msm_route_ec_ref_params_enum[1],
+ msm_ec_ref_bit_format_get, msm_ec_ref_bit_format_put),
+ SOC_ENUM_EXT("EC Reference SampleRate", msm_route_ec_ref_params_enum[2],
+ msm_ec_ref_rate_get, msm_ec_ref_rate_put),
+};
+
static int msm_routing_ec_ref_rx_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2193,6 +2635,11 @@
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
+ if (mux >= e->items) {
+ pr_err("%s: Invalid mux value %d\n", __func__, mux);
+ return -EINVAL;
+ }
+
mutex_lock(&routing_lock);
switch (ucontrol->value.integer.value[0]) {
case 0:
@@ -2271,6 +2718,18 @@
msm_route_ec_ref_rx = 19;
ec_ref_port_id = AFE_PORT_ID_USB_RX;
break;
+ case 20:
+ msm_route_ec_ref_rx = 20;
+ ec_ref_port_id = AFE_PORT_ID_INT0_MI2S_RX;
+ break;
+ case 21:
+ msm_route_ec_ref_rx = 21;
+ ec_ref_port_id = AFE_PORT_ID_INT4_MI2S_RX;
+ break;
+ case 22:
+ msm_route_ec_ref_rx = 22;
+ ec_ref_port_id = AFE_PORT_ID_INT3_MI2S_TX;
+ break;
default:
msm_route_ec_ref_rx = 0; /* NONE */
pr_err("%s EC ref rx %ld not valid\n",
@@ -2291,7 +2750,8 @@
"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"};
+ "TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0", "USB_AUDIO_RX",
+ "INT0_MI2S_RX", "INT4_MI2S_RX", "INT3_MI2S_TX"};
static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_rx), ec_ref_rx),
@@ -2376,6 +2836,11 @@
uint16_t ext_ec_ref_port_id;
struct snd_soc_dapm_update *update = NULL;
+ if (mux >= e->items) {
+ pr_err("%s: Invalid mux value %d\n", __func__, mux);
+ return -EINVAL;
+ }
+
mutex_lock(&routing_lock);
msm_route_ext_ec_ref = ucontrol->value.integer.value[0];
@@ -4061,6 +4526,159 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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 pri_tdm_rx_2_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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 pri_tdm_rx_3_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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 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,
@@ -4163,6 +4781,159 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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 sec_tdm_rx_2_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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 sec_tdm_rx_3_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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 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,
@@ -4788,6 +5559,30 @@
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("PRI_TDM_TX_0", 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("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", 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("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ 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),
@@ -4851,9 +5646,39 @@
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("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_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("PRI_TDM_TX_0", 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("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", 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("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ 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),
@@ -4926,6 +5751,30 @@
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("PRI_TDM_TX_0", 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("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", 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("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ 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),
@@ -4977,6 +5826,30 @@
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("PRI_TDM_TX_0", 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("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", 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("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ 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),
@@ -5058,6 +5931,30 @@
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("PRI_TDM_TX_0", 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("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", 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("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ 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),
@@ -5136,6 +6033,30 @@
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("PRI_TDM_TX_0", 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("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", 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("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ 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),
@@ -5205,6 +6126,30 @@
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("PRI_TDM_TX_0", 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("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", 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("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ 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),
@@ -5237,6 +6182,57 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul9_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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_MULTIMEDIA9, 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,
@@ -6064,6 +7060,12 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new quat_tdm_rx_2_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
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,
@@ -6329,6 +7331,9 @@
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),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0_MMode1",
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 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[] = {
@@ -6622,6 +7627,66 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new int0_mi2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_INT0_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_INT0_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_INT0_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_INT0_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_BACKEND_DAI_INT3_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ 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_INT0_MI2S_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_INT0_MI2S_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_INT0_MI2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new int4_mi2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_INT4_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_INT4_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_INT4_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_INT4_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_BACKEND_DAI_INT3_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ 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_INT4_MI2S_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_INT4_MI2S_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_INT4_MI2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_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,
@@ -6884,6 +7949,12 @@
msm_routing_put_port_mixer),
};
+static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_RX,
+ MSM_BACKEND_DAI_USB_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,
@@ -6908,6 +7979,542 @@
msm_routing_put_port_mixer),
};
+static const struct snd_kcontrol_new pri_tdm_rx_0_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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 pri_tdm_rx_1_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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 pri_tdm_rx_2_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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 pri_tdm_rx_3_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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_PRI_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_BACKEND_DAI_PRI_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_PRI_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_PRI_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_PRI_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_PRI_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 sec_tdm_rx_0_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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 sec_tdm_rx_1_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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 sec_tdm_rx_2_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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 sec_tdm_rx_3_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_SEC_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0,
+ msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_BACKEND_DAI_SEC_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_SEC_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_SEC_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_SEC_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_SEC_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_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,
@@ -7483,6 +9090,198 @@
msm_routing_put_port_mixer),
};
+static const struct snd_kcontrol_new lsm1_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm2_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm3_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm4_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm5_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm6_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm7_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm8_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_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,
@@ -7513,6 +9312,16 @@
0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
msm_routing_put_fm_pcmrx_switch_mixer);
+static const struct snd_kcontrol_new int0_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_int0_mi2s_switch_mixer,
+ msm_routing_put_int0_mi2s_switch_mixer);
+
+static const struct snd_kcontrol_new int4_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_int4_mi2s_switch_mixer,
+ msm_routing_put_int4_mi2s_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,
@@ -7548,53 +9357,27 @@
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 hfp_slim7_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 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 usb_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_usb_switch_mixer,
+ msm_routing_put_usb_switch_mixer);
-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 struct soc_enum lsm_port_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_port_text), lsm_port_text);
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[] = {
+
+static const struct snd_kcontrol_new lsm_controls[] = {
+ /* kcontrol of 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,
@@ -7609,6 +9392,33 @@
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),
+ SOC_ENUM_EXT(QUAT_MI2S_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ /* kcontrol of lsm_port */
+ SOC_ENUM_EXT("LSM1 Port", lsm_port_enum,
+ msm_routing_lsm_port_get,
+ msm_routing_lsm_port_put),
+ SOC_ENUM_EXT("LSM2 Port", lsm_port_enum,
+ msm_routing_lsm_port_get,
+ msm_routing_lsm_port_put),
+ SOC_ENUM_EXT("LSM3 Port", lsm_port_enum,
+ msm_routing_lsm_port_get,
+ msm_routing_lsm_port_put),
+ SOC_ENUM_EXT("LSM4 Port", lsm_port_enum,
+ msm_routing_lsm_port_get,
+ msm_routing_lsm_port_put),
+ SOC_ENUM_EXT("LSM5 Port", lsm_port_enum,
+ msm_routing_lsm_port_get,
+ msm_routing_lsm_port_put),
+ SOC_ENUM_EXT("LSM6 Port", lsm_port_enum,
+ msm_routing_lsm_port_get,
+ msm_routing_lsm_port_put),
+ SOC_ENUM_EXT("LSM7 Port", lsm_port_enum,
+ msm_routing_lsm_port_get,
+ msm_routing_lsm_port_put),
+ SOC_ENUM_EXT("LSM8 Port", lsm_port_enum,
+ msm_routing_lsm_port_get,
+ msm_routing_lsm_port_put),
};
static const char * const aanc_slim_0_rx_text[] = {
@@ -7662,10 +9472,11 @@
continue;
if ((port_id != SLIMBUS_0_RX) &&
(port_id != RT_PROXY_PORT_001_RX) &&
- (port_id != AFE_PORT_ID_PRIMARY_MI2S_RX))
+ (port_id != AFE_PORT_ID_PRIMARY_MI2S_RX) &&
+ (port_id != AFE_PORT_ID_INT4_MI2S_RX))
continue;
- for_each_set_bit(i, &msm_bedais[be_index].fe_sessions,
+ for_each_set_bit(i, &msm_bedais[be_index].fe_sessions[0],
MSM_FRONTEND_DAI_MM_SIZE) {
if (fe_dai_map[i][SESSION_TYPE_RX].perf_mode !=
LEGACY_PCM_MODE)
@@ -7771,6 +9582,45 @@
msm_routing_put_app_type_cfg_control),
};
+static int msm_routing_get_lsm_app_type_cfg_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 0;
+}
+
+static int msm_routing_put_lsm_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++];
+
+ memset(lsm_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++) {
+ lsm_app_type_cfg[j].app_type =
+ ucontrol->value.integer.value[i++];
+ lsm_app_type_cfg[j].sample_rate =
+ ucontrol->value.integer.value[i++];
+ lsm_app_type_cfg[j].bit_width =
+ ucontrol->value.integer.value[i++];
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new lsm_app_type_cfg_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Listen App Type Config", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, 128, msm_routing_get_lsm_app_type_cfg_control,
+ msm_routing_put_lsm_app_type_cfg_control),
+};
+
static int msm_routing_get_use_ds1_or_ds2_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -7802,7 +9652,7 @@
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);
+ param_value = kzalloc(param_length + param_payload_len, GFP_KERNEL);
if (!param_value)
return -ENOMEM;
@@ -7966,7 +9816,7 @@
goto done;
}
- for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions,
+ for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0],
MSM_FRONTEND_DAI_MM_SIZE) {
for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
copp = session_copp_map[i]
@@ -8319,6 +10169,14 @@
"ZERO", "SENARY_TX"
};
+static const char * const int4_mi2s_rx_vi_fb_tx_mono_mux_text[] = {
+ "ZERO", "INT5_MI2S_TX"
+};
+
+static const char * const int4_mi2s_rx_vi_fb_tx_stereo_mux_text[] = {
+ "ZERO", "INT5_MI2S_TX"
+};
+
static const int const slim0_rx_vi_fb_tx_lch_value[] = {
MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SLIMBUS_4_TX
};
@@ -8331,6 +10189,14 @@
MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SENARY_MI2S_TX
};
+static const int const int4_mi2s_rx_vi_fb_tx_mono_ch_value[] = {
+ MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_INT5_MI2S_TX
+};
+
+static const int const int4_mi2s_rx_vi_fb_tx_stereo_ch_value[] = {
+ MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_INT5_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),
@@ -8346,6 +10212,18 @@
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 soc_enum int4_mi2s_rx_vi_fb_mono_ch_mux_enum =
+ SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0,
+ ARRAY_SIZE(int4_mi2s_rx_vi_fb_tx_mono_mux_text),
+ int4_mi2s_rx_vi_fb_tx_mono_mux_text,
+ int4_mi2s_rx_vi_fb_tx_mono_ch_value);
+
+static const struct soc_enum int4_mi2s_rx_vi_fb_stereo_ch_mux_enum =
+ SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0,
+ ARRAY_SIZE(int4_mi2s_rx_vi_fb_tx_stereo_mux_text),
+ int4_mi2s_rx_vi_fb_tx_stereo_mux_text,
+ int4_mi2s_rx_vi_fb_tx_stereo_ch_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,
@@ -8361,6 +10239,16 @@
mi2s_rx_vi_fb_mux_enum, spkr_prot_get_vi_lch_port,
spkr_prot_put_vi_lch_port);
+static const struct snd_kcontrol_new int4_mi2s_rx_vi_fb_mono_ch_mux =
+ SOC_DAPM_ENUM_EXT("INT4_MI2S_RX_VI_FB_MONO_CH_MUX",
+ int4_mi2s_rx_vi_fb_mono_ch_mux_enum, spkr_prot_get_vi_lch_port,
+ spkr_prot_put_vi_lch_port);
+
+static const struct snd_kcontrol_new int4_mi2s_rx_vi_fb_stereo_ch_mux =
+ SOC_DAPM_ENUM_EXT("INT4_MI2S_RX_VI_FB_STEREO_CH_MUX",
+ int4_mi2s_rx_vi_fb_stereo_ch_mux_enum, spkr_prot_get_vi_rch_port,
+ spkr_prot_put_vi_rch_port);
+
static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
/* Frontend AIF */
/* Widget name equals to Front-End DAI name<Need confirmation>,
@@ -8433,6 +10321,10 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIM6_UL_HL", "SLIMBUS6_HOSTLESS Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM7_DL_HL", "SLIMBUS7_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIM7_UL_HL", "SLIMBUS7_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",
@@ -8444,6 +10336,10 @@
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("USBAUDIO_DL_HL", "USBAUDIO_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("USBAUDIO_UL_HL", "USBAUDIO_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",
@@ -8473,6 +10369,9 @@
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("INT3_MI2S_UL_HL",
+ "INT3 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),
@@ -8909,6 +10808,8 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SENARY_TX", "Senary_mi2s Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT5_MI2S_TX", "INT5 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),
@@ -8965,6 +10866,10 @@
&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("INT0_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &int0_mi2s_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("INT4_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &int4_mi2s_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,
@@ -8979,16 +10884,10 @@
&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),
+ SND_SOC_DAPM_SWITCH("HFP_SLIM7_UL_HL", SND_SOC_NOPM, 0, 0,
+ &hfp_slim7_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("USB_DL_HL", SND_SOC_NOPM, 0, 0,
+ &usb_switch_mixer_controls),
/* Mixer definitions */
SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -9038,12 +10937,30 @@
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_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_3_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_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_3_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)),
@@ -9091,6 +11008,8 @@
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("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul9_mixer_controls, ARRAY_SIZE(mmul9_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,
@@ -9195,6 +11114,10 @@
SND_SOC_NOPM, 0, 0,
quin_mi2s_rx_voice_mixer_controls,
ARRAY_SIZE(quin_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_2_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_2_voice_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_2_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)),
@@ -9302,6 +11225,30 @@
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("PRI_TDM_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_0_port_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_0_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_RX_1 Port Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_1_port_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_1_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_RX_2 Port Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_2_port_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_2_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_RX_3 Port Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_3_port_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_3_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_0_port_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_0_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_1 Port Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_1_port_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_1_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_2 Port Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_2_port_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_2_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_3 Port Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_3_port_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_3_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)),
@@ -9326,12 +11273,38 @@
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("INT0_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ int0_mi2s_rx_port_mixer_controls,
+ ARRAY_SIZE(int0_mi2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT4_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ int4_mi2s_rx_port_mixer_controls,
+ ARRAY_SIZE(int4_mi2s_rx_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)),
+ SND_SOC_DAPM_MIXER("USB_AUDIO_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, usb_rx_port_mixer_controls,
+ ARRAY_SIZE(usb_rx_port_mixer_controls)),
+ /* lsm mixer definitions */
+ SND_SOC_DAPM_MIXER("LSM1 Mixer", SND_SOC_NOPM, 0, 0,
+ lsm1_mixer_controls, ARRAY_SIZE(lsm1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LSM2 Mixer", SND_SOC_NOPM, 0, 0,
+ lsm2_mixer_controls, ARRAY_SIZE(lsm2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LSM3 Mixer", SND_SOC_NOPM, 0, 0,
+ lsm3_mixer_controls, ARRAY_SIZE(lsm3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LSM4 Mixer", SND_SOC_NOPM, 0, 0,
+ lsm4_mixer_controls, ARRAY_SIZE(lsm4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LSM5 Mixer", SND_SOC_NOPM, 0, 0,
+ lsm5_mixer_controls, ARRAY_SIZE(lsm5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LSM6 Mixer", SND_SOC_NOPM, 0, 0,
+ lsm6_mixer_controls, ARRAY_SIZE(lsm6_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LSM7 Mixer", SND_SOC_NOPM, 0, 0,
+ lsm7_mixer_controls, ARRAY_SIZE(lsm7_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LSM8 Mixer", SND_SOC_NOPM, 0, 0,
+ lsm8_mixer_controls, ARRAY_SIZE(lsm8_mixer_controls)),
/* Virtual Pins to force backends ON atm */
SND_SOC_DAPM_OUTPUT("BE_OUT"),
SND_SOC_DAPM_INPUT("BE_IN"),
@@ -9342,6 +11315,10 @@
&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("INT4_MI2S_RX_VI_FB_MONO_CH_MUX", SND_SOC_NOPM, 0, 0,
+ &int4_mi2s_rx_vi_fb_mono_ch_mux),
+ SND_SOC_DAPM_MUX("INT4_MI2S_RX_VI_FB_STEREO_CH_MUX", SND_SOC_NOPM, 0, 0,
+ &int4_mi2s_rx_vi_fb_stereo_ch_mux),
SND_SOC_DAPM_MUX("VOC_EXT_EC MUX", SND_SOC_NOPM, 0, 0,
&voc_ext_ec_mux),
@@ -9605,6 +11582,7 @@
{"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_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"},
@@ -9770,6 +11748,60 @@
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Audio Mixer"},
+
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Audio Mixer"},
+
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 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"},
@@ -9806,6 +11838,60 @@
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Audio Mixer"},
+
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Audio Mixer"},
+
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 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"},
@@ -10034,6 +12120,8 @@
{"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_6_TX", "SLIMBUS_6_TX"},
+ {"MultiMedia2 Mixer", "SLIM_1_TX", "SLIMBUS_1_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"},
@@ -10051,6 +12139,14 @@
{"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia6 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"MultiMedia1 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia1 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia1 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia1 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia1 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia1 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia1 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia1 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
{"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"},
@@ -10060,6 +12156,14 @@
{"MultiMedia1 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia1 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia2 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia2 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia2 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia2 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia2 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia2 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia2 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia2 Mixer", "SEC_TDM_TX_3", "SEC_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"},
@@ -10069,6 +12173,14 @@
{"MultiMedia2 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia2 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia3 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia3 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia3 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia3 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia3 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia3 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia3 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia3 Mixer", "SEC_TDM_TX_3", "SEC_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"},
@@ -10078,6 +12190,14 @@
{"MultiMedia3 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia3 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia4 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia4 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia4 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia4 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia4 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia4 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia4 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia4 Mixer", "SEC_TDM_TX_3", "SEC_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"},
@@ -10087,6 +12207,14 @@
{"MultiMedia4 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia4 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia5 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia5 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia5 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia5 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia5 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia5 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia5 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia5 Mixer", "SEC_TDM_TX_3", "SEC_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"},
@@ -10096,6 +12224,14 @@
{"MultiMedia5 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia5 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia6 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia6 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia6 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia6 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia6 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia6 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia6 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia6 Mixer", "SEC_TDM_TX_3", "SEC_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"},
@@ -10105,6 +12241,14 @@
{"MultiMedia6 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia6 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia8 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia8 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia8 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia8 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia8 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia8 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia8 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia8 Mixer", "SEC_TDM_TX_3", "SEC_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"},
@@ -10114,6 +12258,15 @@
{"MultiMedia8 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia8 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia9 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia9 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia9 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia9 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia9 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia9 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia9 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia9 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"},
@@ -10228,6 +12381,7 @@
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
{"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+ {"MM_UL9", NULL, "MultiMedia9 Mixer"},
{"MM_UL17", NULL, "MultiMedia17 Mixer"},
{"MM_UL18", NULL, "MultiMedia18 Mixer"},
{"MM_UL19", NULL, "MultiMedia19 Mixer"},
@@ -10552,6 +12706,9 @@
{"QUIN_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
{"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX_Voice Mixer"},
+ {"QUAT_TDM_RX_2_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_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"},
@@ -10717,6 +12874,7 @@
{"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_Tx Mixer", "QUAT_TDM_TX_0_MMode1", "QUAT_TDM_TX_0"},
{"VOICEMMODE1_UL", NULL, "VoiceMMode1_Tx Mixer"},
{"VoiceMMode2_Tx Mixer", "PRI_TX_MMode2", "PRI_I2S_TX"},
@@ -10769,70 +12927,77 @@
{"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"},
+ {"LSM1 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM1 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM1 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM1 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM1 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM1_UL_HL", NULL, "LSM1 Mixer"},
+
+ {"LSM2 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM2 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM2 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM2 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM2 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM2 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM2_UL_HL", NULL, "LSM2 Mixer"},
- {"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"},
+ {"LSM3 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM3 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM3 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM3 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM3 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM3 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM3_UL_HL", NULL, "LSM3 Mixer"},
- {"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"},
+ {"LSM4 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM4 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM4 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM4 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM4 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM4 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM4 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM4_UL_HL", NULL, "LSM4 Mixer"},
- {"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"},
+ {"LSM5 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM5 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM5 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM5 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM5 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"LSM5 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM5_UL_HL", NULL, "LSM5 Mixer"},
- {"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"},
+ {"LSM6 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM6 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM6 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM6 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM6 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM6_UL_HL", NULL, "LSM6 Mixer"},
+ {"LSM7 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM7 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM7 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM7 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM7 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM7 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM7_UL_HL", NULL, "LSM7 Mixer"},
- {"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"},
+ {"LSM8 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM8 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM8 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM8 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM8 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM8 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM8_UL_HL", NULL, "LSM8 Mixer"},
{"CPE_LSM_UL_HL", NULL, "BE_IN"},
@@ -10861,13 +13026,17 @@
{"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"},
+ {"SLIM7_UL_HL", NULL, "HFP_SLIM7_UL_HL"},
+ {"HFP_SLIM7_UL_HL", "Switch", "SLIMBUS_7_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"},
+
+ /* connect to INT4_MI2S_DL_HL since same pcm_id */
+ {"INT0_MI2S_RX_DL_HL", "Switch", "INT4_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"},
@@ -10881,26 +13050,40 @@
{"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"},
+ {"INT3_MI2S_UL_HL", NULL, "INT3_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_UL_HL", NULL, "SEC_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_TX_1_UL_HL", NULL, "PRI_TDM_TX_1"},
+ {"PRI_TDM_TX_2_UL_HL", NULL, "PRI_TDM_TX_2"},
+ {"PRI_TDM_TX_3_UL_HL", NULL, "PRI_TDM_TX_3"},
{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0_DL_HL"},
+ {"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1_DL_HL"},
+ {"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2_DL_HL"},
+ {"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3_DL_HL"},
{"SEC_TDM_TX_0_UL_HL", NULL, "SEC_TDM_TX_0"},
+ {"SEC_TDM_TX_1_UL_HL", NULL, "SEC_TDM_TX_1"},
+ {"SEC_TDM_TX_2_UL_HL", NULL, "SEC_TDM_TX_2"},
+ {"SEC_TDM_TX_3_UL_HL", NULL, "SEC_TDM_TX_3"},
{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0_DL_HL"},
+ {"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1_DL_HL"},
+ {"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2_DL_HL"},
+ {"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3_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"},
+ {"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1_DL_HL"},
+ {"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2_DL_HL"},
+ {"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3_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"},
@@ -10910,6 +13093,150 @@
{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_DL_HL"},
{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3_DL_HL"},
+ {"PRI_TDM_RX_0 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"PRI_TDM_RX_0 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"PRI_TDM_RX_0 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"PRI_TDM_RX_0 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"PRI_TDM_RX_0 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"PRI_TDM_RX_0 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"PRI_TDM_RX_0 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"PRI_TDM_RX_0 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"PRI_TDM_RX_0 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"PRI_TDM_RX_0 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"PRI_TDM_RX_0 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"PRI_TDM_RX_0 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"PRI_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"PRI_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"PRI_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"PRI_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Port Mixer"},
+
+ {"PRI_TDM_RX_1 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"PRI_TDM_RX_1 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"PRI_TDM_RX_1 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"PRI_TDM_RX_1 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"PRI_TDM_RX_1 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"PRI_TDM_RX_1 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"PRI_TDM_RX_1 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"PRI_TDM_RX_1 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"PRI_TDM_RX_1 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"PRI_TDM_RX_1 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"PRI_TDM_RX_1 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"PRI_TDM_RX_1 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"PRI_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"PRI_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"PRI_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"PRI_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Port Mixer"},
+
+ {"PRI_TDM_RX_2 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"PRI_TDM_RX_2 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"PRI_TDM_RX_2 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"PRI_TDM_RX_2 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"PRI_TDM_RX_2 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"PRI_TDM_RX_2 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"PRI_TDM_RX_2 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"PRI_TDM_RX_2 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"PRI_TDM_RX_2 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"PRI_TDM_RX_2 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"PRI_TDM_RX_2 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"PRI_TDM_RX_2 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"PRI_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"PRI_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"PRI_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"PRI_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Port Mixer"},
+
+ {"PRI_TDM_RX_3 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"PRI_TDM_RX_3 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"PRI_TDM_RX_3 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"PRI_TDM_RX_3 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"PRI_TDM_RX_3 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"PRI_TDM_RX_3 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"PRI_TDM_RX_3 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"PRI_TDM_RX_3 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"PRI_TDM_RX_3 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"PRI_TDM_RX_3 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"PRI_TDM_RX_3 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"PRI_TDM_RX_3 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"PRI_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"PRI_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"PRI_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"PRI_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 Port Mixer"},
+
+ {"SEC_TDM_RX_0 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SEC_TDM_RX_0 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"SEC_TDM_RX_0 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"SEC_TDM_RX_0 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"SEC_TDM_RX_0 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"SEC_TDM_RX_0 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"SEC_TDM_RX_0 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SEC_TDM_RX_0 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"SEC_TDM_RX_0 Port Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"SEC_TDM_RX_0 Port Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"SEC_TDM_RX_0 Port Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"SEC_TDM_RX_0 Port Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"SEC_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"SEC_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"SEC_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"SEC_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Port Mixer"},
+
+ {"SEC_TDM_RX_1 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SEC_TDM_RX_1 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"SEC_TDM_RX_1 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"SEC_TDM_RX_1 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"SEC_TDM_RX_1 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"SEC_TDM_RX_1 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"SEC_TDM_RX_1 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SEC_TDM_RX_1 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"SEC_TDM_RX_1 Port Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"SEC_TDM_RX_1 Port Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"SEC_TDM_RX_1 Port Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"SEC_TDM_RX_1 Port Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"SEC_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"SEC_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"SEC_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"SEC_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Port Mixer"},
+
+ {"SEC_TDM_RX_2 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SEC_TDM_RX_2 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"SEC_TDM_RX_2 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"SEC_TDM_RX_2 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"SEC_TDM_RX_2 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"SEC_TDM_RX_2 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"SEC_TDM_RX_2 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SEC_TDM_RX_2 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"SEC_TDM_RX_2 Port Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"SEC_TDM_RX_2 Port Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"SEC_TDM_RX_2 Port Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"SEC_TDM_RX_2 Port Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"SEC_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"SEC_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"SEC_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"SEC_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Port Mixer"},
+
+ {"SEC_TDM_RX_3 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SEC_TDM_RX_3 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"SEC_TDM_RX_3 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"SEC_TDM_RX_3 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"SEC_TDM_RX_3 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"SEC_TDM_RX_3 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"SEC_TDM_RX_3 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SEC_TDM_RX_3 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"SEC_TDM_RX_3 Port Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"SEC_TDM_RX_3 Port Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"SEC_TDM_RX_3 Port Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"SEC_TDM_RX_3 Port Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"SEC_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"SEC_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"SEC_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"SEC_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 Port Mixer"},
+
{"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"},
@@ -11054,6 +13381,28 @@
{"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"},
+ {"INT0_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"INT0_MI2S_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"INT0_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"INT0_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"INT0_MI2S_RX Port Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"INT0_MI2S_RX Port Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"INT0_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"INT0_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"INT0_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX Port Mixer"},
+
+ {"INT4_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"INT4_MI2S_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"INT4_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"INT4_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"INT4_MI2S_RX Port Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"INT4_MI2S_RX Port Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"INT4_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"INT4_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"INT4_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX 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"},
@@ -11073,6 +13422,12 @@
{"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"},
+ {"USB_AUDIO_RX Port Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"USB_AUDIO_RX", NULL, "USB_AUDIO_RX Port Mixer"},
+ {"USB_DL_HL", "Switch", "USBAUDIO_DL_HL"},
+ {"USB_AUDIO_RX", NULL, "USB_DL_HL"},
+ {"USBAUDIO_UL_HL", NULL, "USB_AUDIO_TX"},
+
{"AUX_PCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"AUX_PCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -11301,7 +13656,13 @@
{"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
{"BE_OUT", NULL, "VOICE2_PLAYBACK_TX"},
{"BE_OUT", NULL, "PRI_TDM_RX_0"},
+ {"BE_OUT", NULL, "PRI_TDM_RX_1"},
+ {"BE_OUT", NULL, "PRI_TDM_RX_2"},
+ {"BE_OUT", NULL, "PRI_TDM_RX_3"},
{"BE_OUT", NULL, "SEC_TDM_RX_0"},
+ {"BE_OUT", NULL, "SEC_TDM_RX_1"},
+ {"BE_OUT", NULL, "SEC_TDM_RX_2"},
+ {"BE_OUT", NULL, "SEC_TDM_RX_3"},
{"BE_OUT", NULL, "TERT_TDM_RX_0"},
{"BE_OUT", NULL, "TERT_TDM_RX_1"},
{"BE_OUT", NULL, "TERT_TDM_RX_2"},
@@ -11319,6 +13680,7 @@
{"TERT_MI2S_TX", NULL, "BE_IN"},
{"INT2_MI2S_TX", NULL, "BE_IN"},
{"INT3_MI2S_TX", NULL, "BE_IN"},
+ {"INT5_MI2S_TX", NULL, "BE_IN"},
{"SEC_MI2S_TX", NULL, "BE_IN"},
{"SENARY_MI2S_TX", NULL, "BE_IN" },
{"SLIMBUS_0_TX", NULL, "BE_IN" },
@@ -11347,11 +13709,21 @@
{"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"},
+ {"INT4_MI2S_RX_VI_FB_MONO_CH_MUX", "INT5_MI2S_TX", "INT5_MI2S_TX"},
+ {"INT4_MI2S_RX_VI_FB_STEREO_CH_MUX", "INT5_MI2S_TX", "INT5_MI2S_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"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_VI_FB_MONO_CH_MUX"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_VI_FB_STEREO_CH_MUX"},
{"PRI_TDM_TX_0", NULL, "BE_IN"},
+ {"PRI_TDM_TX_1", NULL, "BE_IN"},
+ {"PRI_TDM_TX_2", NULL, "BE_IN"},
+ {"PRI_TDM_TX_3", NULL, "BE_IN"},
{"SEC_TDM_TX_0", NULL, "BE_IN"},
+ {"SEC_TDM_TX_1", NULL, "BE_IN"},
+ {"SEC_TDM_TX_2", NULL, "BE_IN"},
+ {"SEC_TDM_TX_3", NULL, "BE_IN"},
{"TERT_TDM_TX_0", NULL, "BE_IN"},
{"TERT_TDM_TX_1", NULL, "BE_IN"},
{"TERT_TDM_TX_2", NULL, "BE_IN"},
@@ -11409,7 +13781,9 @@
path_type = ADM_PATH_LIVE_REC;
mutex_lock(&routing_lock);
- for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+ for_each_set_bit(i, &bedai->fe_sessions[0], MSM_FRONTEND_DAI_MAX) {
+ if (!is_mm_lsm_fe_id(i))
+ continue;
fdai = &fe_dai_map[i][session_type];
if (fdai->strm_id != INVALID_SESSION) {
int idx;
@@ -11430,13 +13804,12 @@
clear_bit(idx,
&session_copp_map[i][session_type][be_id]);
if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
- (bedai->compr_passthr_mode == LEGACY_PCM))
+ (bedai->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;
@@ -11456,6 +13829,7 @@
struct msm_pcm_routing_fdai_data *fdai;
u32 session_id;
struct media_format_info voc_be_media_format;
+ bool is_lsm;
pr_debug("%s: substream->pcm->id:%s\n",
__func__, substream->pcm->id);
@@ -11468,7 +13842,7 @@
bedai = &msm_bedais[be_id];
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (bedai->compr_passthr_mode != LEGACY_PCM)
+ if (bedai->passthr_mode != LEGACY_PCM)
path_type = ADM_PATH_COMPRESSED_RX;
else
path_type = ADM_PATH_PLAYBACK;
@@ -11489,7 +13863,13 @@
*/
bedai->active = 1;
- for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+ for_each_set_bit(i, &bedai->fe_sessions[0], MSM_FRONTEND_DAI_MAX) {
+ if (!(is_mm_lsm_fe_id(i) &&
+ route_check_fe_id_adm_support(i)))
+ continue;
+
+ is_lsm = (i >= MSM_FRONTEND_DAI_LSM1) &&
+ (i <= MSM_FRONTEND_DAI_LSM8);
fdai = &fe_dai_map[i][session_type];
if (fdai->strm_id != INVALID_SESSION) {
int app_type, app_type_idx, copp_idx, acdb_dev_id;
@@ -11512,7 +13892,15 @@
app_type =
fe_dai_app_type_cfg[i][session_type].app_type;
- if (app_type) {
+ if (app_type && is_lsm) {
+ app_type_idx =
+ msm_pcm_routing_get_lsm_app_type_idx(app_type);
+ sample_rate =
+ fe_dai_app_type_cfg[i][session_type].
+ sample_rate;
+ bits_per_sample =
+ lsm_app_type_cfg[app_type_idx].bit_width;
+ } else if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
@@ -11557,16 +13945,16 @@
bedai->sample_rate);
msm_pcm_routing_build_matrix(i, session_type, path_type,
- fdai->perf_mode);
+ fdai->perf_mode,
+ bedai->passthr_mode);
if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
- (bedai->compr_passthr_mode ==
- LEGACY_PCM))
+ (bedai->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) {
+ for_each_set_bit(i, &bedai->fe_sessions[0], MSM_FRONTEND_DAI_MAX) {
session_id = msm_pcm_routing_get_voc_sessionid(i);
if (session_id) {
pr_debug("%s voice session_id: 0x%x\n", __func__,
@@ -11631,6 +14019,7 @@
unsigned long pp_config = 0;
bool mute_on;
int latency;
+ bool compr_passthr_mode = true;
pr_debug("%s: port_id %d, copp_idx %d\n", __func__, port_id, copp_idx);
@@ -11667,14 +14056,16 @@
return -EINVAL;
}
+ if ((msm_bedais[be_idx].passthr_mode == LEGACY_PCM) ||
+ (msm_bedais[be_idx].passthr_mode == LISTEN))
+ compr_passthr_mode = false;
+
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))
+ if ((msm_bedais[be_idx].active) && compr_passthr_mode)
adm_send_compressed_device_mute(port_id,
copp_idx,
mute_on);
@@ -11684,9 +14075,7 @@
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))
+ if ((msm_bedais[be_idx].active) && compr_passthr_mode)
adm_send_compressed_device_latency(port_id,
copp_idx,
latency);
@@ -11702,6 +14091,7 @@
int index, be_idx, i, topo_id, idx;
bool mute;
int latency;
+ bool compr_passthr_mode = true;
pr_debug("%s: pp_id: 0x%x\n", __func__, pp_id);
@@ -11726,7 +14116,11 @@
return -EINVAL;
}
- for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions,
+ if ((msm_bedais[be_idx].passthr_mode == LEGACY_PCM) ||
+ (msm_bedais[be_idx].passthr_mode == LISTEN))
+ compr_passthr_mode = false;
+
+ for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0],
MSM_FRONTEND_DAI_MM_SIZE) {
for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
unsigned long copp =
@@ -11740,7 +14134,7 @@
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);
+ msm_bedais[be_idx].passthr_mode);
switch (pp_id) {
case ADM_PP_PARAM_MUTE_ID:
pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__);
@@ -11748,9 +14142,7 @@
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))
+ if ((msm_bedais[be_idx].active) && compr_passthr_mode)
adm_send_compressed_device_mute(port_id,
idx, mute);
break;
@@ -11762,9 +14154,7 @@
&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))
+ if ((msm_bedais[be_idx].active) && compr_passthr_mode)
adm_send_compressed_device_latency(port_id,
idx, latency);
break;
@@ -11791,6 +14181,33 @@
msm_routing_put_device_pp_params_mixer),
};
+static int msm_aptx_dec_license_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ core_get_license_status(ASM_MEDIA_FMT_APTX);
+ pr_debug("%s: status %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_aptx_dec_license_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int32_t status = 0;
+
+ status = core_set_license(ucontrol->value.integer.value[0],
+ APTX_CLASSIC_DEC_LICENSE_ID);
+ pr_debug("%s: status %d\n", __func__, status);
+ return status;
+}
+
+static const struct snd_kcontrol_new aptx_dec_license_controls[] = {
+ SOC_SINGLE_EXT("APTX Dec License", SND_SOC_NOPM, 0,
+ 0xFFFF, 0, msm_aptx_dec_license_control_get,
+ msm_aptx_dec_license_control_put),
+};
+
static const struct snd_pcm_ops msm_routing_pcm_ops = {
.hw_params = msm_pcm_routing_hw_params,
.close = msm_pcm_routing_close,
@@ -11807,8 +14224,8 @@
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, lsm_controls,
+ ARRAY_SIZE(lsm_controls));
snd_soc_add_platform_controls(platform, aanc_slim_0_rx_mux,
ARRAY_SIZE(aanc_slim_0_rx_mux));
@@ -11819,10 +14236,16 @@
snd_soc_add_platform_controls(platform, app_type_cfg_controls,
ARRAY_SIZE(app_type_cfg_controls));
+ snd_soc_add_platform_controls(platform, lsm_app_type_cfg_controls,
+ ARRAY_SIZE(lsm_app_type_cfg_controls));
+
snd_soc_add_platform_controls(platform,
stereo_to_custom_stereo_controls,
ARRAY_SIZE(stereo_to_custom_stereo_controls));
+ snd_soc_add_platform_controls(platform, ec_ref_param_controls,
+ ARRAY_SIZE(ec_ref_param_controls));
+
msm_qti_pp_add_controls(platform);
msm_dts_srs_tm_add_controls(platform);
@@ -11843,6 +14266,9 @@
ARRAY_SIZE(msm_source_tracking_controls));
snd_soc_add_platform_controls(platform, adm_channel_config_controls,
ARRAY_SIZE(adm_channel_config_controls));
+
+ snd_soc_add_platform_controls(platform, aptx_dec_license_controls,
+ ARRAY_SIZE(aptx_dec_license_controls));
return 0;
}
@@ -11903,7 +14329,7 @@
return 0;
}
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+ if (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))
return msm_bedais[i].active;
}
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index d64fd64..dc1d0e0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, 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
@@ -390,6 +390,7 @@
#define ADM_PP_PARAM_LATENCY_ID 1
#define ADM_PP_PARAM_LATENCY_BIT 2
#define BE_DAI_PORT_SESSIONS_IDX_MAX 4
+#define BE_DAI_FE_SESSIONS_IDX_MAX 2
struct msm_pcm_routing_evt {
void (*event_func)(enum msm_pcm_routing_event, void *);
@@ -399,7 +400,9 @@
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 */
+
+ /* Front-end sessions */
+ unsigned long fe_sessions[BE_DAI_FE_SESSIONS_IDX_MAX];
/*
* Track Tx BE ports -> Rx BE ports.
* port_sessions[0] used to track BE 0 to BE 63.
@@ -413,7 +416,7 @@
unsigned int channel;
unsigned int format;
unsigned int adm_override_ch;
- u32 compr_passthr_mode;
+ u32 passthr_mode;
char *name;
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index fa71eea..e39e642 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-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
@@ -390,6 +390,32 @@
return ret;
}
+static int msm_voice_sidetone_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ bool sidetone_enable = ucontrol->value.integer.value[0];
+ uint32_t session_id = ALL_SESSION_VSID;
+
+ if (sidetone_enable < 0) {
+ pr_err("%s: Invalid arguments sidetone enable %d\n",
+ __func__, sidetone_enable);
+ ret = -EINVAL;
+ return ret;
+ }
+ ret = voc_set_afe_sidetone(session_id, sidetone_enable);
+ pr_debug("%s: AFE Sidetone enable=%d session_id=0x%x ret=%d\n",
+ __func__, sidetone_enable, session_id, ret);
+ return ret;
+}
+
+static int msm_voice_sidetone_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = voc_get_afe_sidetone();
+ return 0;
+}
+
static int msm_voice_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -632,6 +658,8 @@
.info = msm_voice_cvd_version_info,
.get = msm_voice_cvd_version_get,
},
+ SOC_SINGLE_MULTI_EXT("Voice Sidetone Enable", SND_SOC_NOPM, 0, 1, 0, 1,
+ msm_voice_sidetone_get, msm_voice_sidetone_put),
};
static const struct snd_pcm_ops msm_pcm_ops = {
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index 9276231..4815895 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -81,6 +81,10 @@
static const DECLARE_TLV_DB_LINEAR(hfp_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
+static int msm_route_icc_vol_control;
+static const DECLARE_TLV_DB_LINEAR(icc_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);
@@ -89,6 +93,8 @@
static const DECLARE_TLV_DB_LINEAR(sec_auxpcm_lb_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
+static int msm_multichannel_ec_primary_mic_ch;
+
static void msm_qti_pp_send_eq_values_(int eq_idx)
{
int result;
@@ -342,7 +348,7 @@
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);
+ param_value = kzalloc(param_length + param_payload_len, GFP_KERNEL);
if (!param_value)
return -ENOMEM;
@@ -495,6 +501,23 @@
return ret;
}
+static int msm_qti_pp_get_icc_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_route_icc_vol_control;
+ return 0;
+}
+
+static int msm_qti_pp_set_icc_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ adm_set_mic_gain(AFE_PORT_ID_QUATERNARY_TDM_TX,
+ adm_get_default_copp_idx(AFE_PORT_ID_QUATERNARY_TDM_TX),
+ ucontrol->value.integer.value[0]);
+ msm_route_icc_vol_control = ucontrol->value.integer.value[0];
+ return 0;
+}
+
static int msm_qti_pp_get_quat_mi2s_fm_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -581,7 +604,7 @@
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];
+ char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL] = {0};
int i;
adm_get_multi_ch_map(channel_map, ADM_PATH_PLAYBACK);
@@ -774,6 +797,43 @@
return 0;
}
+static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int copp_idx = 0;
+ int port_id = AFE_PORT_ID_QUATERNARY_TDM_TX;
+
+ msm_multichannel_ec_primary_mic_ch = ucontrol->value.integer.value[0];
+ pr_debug("%s: msm_multichannel_ec_primary_mic_ch = %u\n",
+ __func__, msm_multichannel_ec_primary_mic_ch);
+ copp_idx = adm_get_default_copp_idx(port_id);
+ if ((copp_idx < 0) || (copp_idx > MAX_COPPS_PER_PORT)) {
+ pr_err("%s : no active copp to query multichannel ec copp_idx: %u\n",
+ __func__, copp_idx);
+ return -EINVAL;
+ }
+ adm_send_set_multichannel_ec_primary_mic_ch(port_id, copp_idx,
+ msm_multichannel_ec_primary_mic_ch);
+
+ return ret;
+}
+
+static int msm_multichannel_ec_primary_mic_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_multichannel_ec_primary_mic_ch;
+ pr_debug("%s: msm_multichannel_ec_primary_mic_ch = %lu\n",
+ __func__, ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static const struct snd_kcontrol_new msm_multichannel_ec_controls[] = {
+ SOC_SINGLE_EXT("Multichannel EC Primary Mic Ch", SND_SOC_NOPM, 0,
+ 0xFFFFFFFF, 0, msm_multichannel_ec_primary_mic_ch_get,
+ msm_multichannel_ec_primary_mic_ch_put),
+};
+
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,
@@ -813,6 +873,12 @@
msm_qti_pp_set_hfp_vol_mixer, hfp_rx_vol_gain),
};
+static const struct snd_kcontrol_new int_icc_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("Internal ICC Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_qti_pp_get_icc_vol_mixer,
+ msm_qti_pp_set_icc_vol_mixer, icc_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,
@@ -1005,6 +1071,9 @@
snd_soc_add_platform_controls(platform, int_hfp_vol_mixer_controls,
ARRAY_SIZE(int_hfp_vol_mixer_controls));
+ snd_soc_add_platform_controls(platform, int_icc_vol_mixer_controls,
+ ARRAY_SIZE(int_icc_vol_mixer_controls));
+
snd_soc_add_platform_controls(platform,
pri_auxpcm_lb_vol_mixer_controls,
ARRAY_SIZE(pri_auxpcm_lb_vol_mixer_controls));
@@ -1031,5 +1100,8 @@
snd_soc_add_platform_controls(platform, asphere_mixer_controls,
ARRAY_SIZE(asphere_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, msm_multichannel_ec_controls,
+ ARRAY_SIZE(msm_multichannel_ec_controls));
}
#endif /* CONFIG_QTI_PP */
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 62e4a4d..113fdae 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -102,6 +102,9 @@
int set_custom_topology;
int ec_ref_rx;
+ int num_ec_ref_rx_chans;
+ int ec_ref_rx_bit_width;
+ int ec_ref_rx_sampling_rate;
};
static struct adm_ctl this_adm;
@@ -986,9 +989,10 @@
char *params, uint32_t client_id)
{
struct adm_cmd_get_pp_params_v5 *adm_params = NULL;
- int sz, rc = 0, i = 0;
+ int rc = 0, i = 0;
int port_idx, idx;
int *params_data = (int *)params;
+ uint64_t sz = 0;
port_id = afe_convert_virtual_to_portid(port_id);
port_idx = adm_validate_and_get_port_index(port_id);
@@ -997,7 +1001,16 @@
return -EINVAL;
}
- sz = sizeof(struct adm_cmd_get_pp_params_v5) + params_length;
+ sz = (uint64_t)sizeof(struct adm_cmd_get_pp_params_v5) +
+ (uint64_t)params_length;
+ /*
+ * Check if the value of "sz" (which is ultimately assigned to
+ * "hdr.pkt_size") crosses U16_MAX.
+ */
+ if (sz > U16_MAX) {
+ pr_err("%s: Invalid params_length\n", __func__);
+ return -EINVAL;
+ }
adm_params = kzalloc(sz, GFP_KERNEL);
if (!adm_params) {
pr_err("%s: adm params memory alloc failed", __func__);
@@ -1367,6 +1380,7 @@
*/
case ADM_CMD_DEVICE_OPEN_V5:
case ADM_CMD_DEVICE_CLOSE_V5:
+ case ADM_CMD_DEVICE_OPEN_V6:
pr_debug("%s: Basic callback received, wake up.\n",
__func__);
atomic_set(&this_adm.copp.stat[port_idx]
@@ -1462,7 +1476,8 @@
}
switch (data->opcode) {
- case ADM_CMDRSP_DEVICE_OPEN_V5: {
+ case ADM_CMDRSP_DEVICE_OPEN_V5:
+ case ADM_CMDRSP_DEVICE_OPEN_V6: {
struct adm_cmd_rsp_device_open_v5 *open =
(struct adm_cmd_rsp_device_open_v5 *)data->payload;
@@ -2271,10 +2286,64 @@
return rc;
}
+int adm_arrange_mch_ep2_map(struct adm_cmd_device_open_v6 *open_v6,
+ int channel_mode)
+{
+ int rc = 0;
+
+ memset(open_v6->dev_channel_mapping_eid2, 0,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (channel_mode == 1) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FC;
+ } else if (channel_mode == 2) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ } else if (channel_mode == 3) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
+ } else if (channel_mode == 4) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LS;
+ open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 5) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
+ open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_LS;
+ open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 6) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
+ open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
+ open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
+ open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 8) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
+ open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
+ open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
+ open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
+ open_v6->dev_channel_mapping_eid2[6] = PCM_CHANNEL_LB;
+ open_v6->dev_channel_mapping_eid2[7] = PCM_CHANNEL_RB;
+ } else {
+ pr_err("%s: invalid num_chan %d\n", __func__,
+ channel_mode);
+ rc = -EINVAL;
+ }
+
+ 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;
+ struct adm_cmd_device_open_v6 open_v6;
int ret = 0;
int port_idx, copp_idx, flags;
int tmp_port = q6audio_get_port_id(port_id);
@@ -2409,6 +2478,7 @@
pr_err("%s: DTS_EAGLE mmap did not work!",
__func__);
}
+ memset(&open, 0, sizeof(struct adm_cmd_device_open_v5));
open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
APR_PKT_VER);
@@ -2424,10 +2494,9 @@
open.flags = flags;
open.mode_of_operation = path;
open.endpoint_id_1 = tmp_port;
+ open.endpoint_id_2 = 0xFFFF;
- if (this_adm.ec_ref_rx == -1) {
- open.endpoint_id_2 = 0xFFFF;
- } else if (this_adm.ec_ref_rx && (path != 1)) {
+ if (this_adm.ec_ref_rx && (path != 1)) {
open.endpoint_id_2 = this_adm.ec_ref_rx;
this_adm.ec_ref_rx = -1;
}
@@ -2451,7 +2520,49 @@
atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
- ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+ if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
+ (open.endpoint_id_2 != 0xFFFF)) {
+ memset(&open_v6, 0,
+ sizeof(struct adm_cmd_device_open_v6));
+ memcpy(&open_v6, &open,
+ sizeof(struct adm_cmd_device_open_v5));
+ open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
+ open_v6.hdr.pkt_size = sizeof(open_v6);
+ open_v6.dev_num_channel_eid2 =
+ this_adm.num_ec_ref_rx_chans;
+ this_adm.num_ec_ref_rx_chans = 0;
+
+ if (this_adm.ec_ref_rx_bit_width != 0) {
+ open_v6.bit_width_eid2 =
+ this_adm.ec_ref_rx_bit_width;
+ this_adm.ec_ref_rx_bit_width = 0;
+ } else {
+ open_v6.bit_width_eid2 = bit_width;
+ }
+
+ if (this_adm.ec_ref_rx_sampling_rate != 0) {
+ open_v6.sample_rate_eid2 =
+ this_adm.ec_ref_rx_sampling_rate;
+ this_adm.ec_ref_rx_sampling_rate = 0;
+ } else {
+ open_v6.sample_rate_eid2 = rate;
+ }
+
+ pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
+ __func__, open_v6.dev_num_channel_eid2,
+ open_v6.bit_width_eid2,
+ open_v6.sample_rate_eid2);
+
+ ret = adm_arrange_mch_ep2_map(&open_v6,
+ open_v6.dev_num_channel_eid2);
+
+ if (ret)
+ return ret;
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
+ } else {
+ 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);
@@ -2481,7 +2592,6 @@
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;
@@ -2584,8 +2694,43 @@
return;
}
+static void route_set_opcode_matrix_id(
+ struct adm_cmd_matrix_map_routings_v5 **route_addr,
+ int path, uint32_t passthr_mode)
+{
+ struct adm_cmd_matrix_map_routings_v5 *route = *route_addr;
-int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode)
+ switch (path) {
+ case ADM_PATH_PLAYBACK:
+ route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
+ route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
+ break;
+ case ADM_PATH_LIVE_REC:
+ if (passthr_mode == LISTEN) {
+ route->hdr.opcode =
+ ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
+ route->matrix_id = ADM_MATRIX_ID_LISTEN_TX;
+ break;
+ }
+ /* fall through to set matrix id for non-listen case */
+ case ADM_PATH_NONLIVE_REC:
+ route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
+ route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
+ break;
+ case ADM_PATH_COMPRESSED_RX:
+ route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
+ route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
+ break;
+ default:
+ pr_err("%s: Wrong path set[%d]\n", __func__, path);
+ break;
+ }
+ pr_debug("%s: opcode 0x%x, matrix id %d\n",
+ __func__, route->hdr.opcode, route->matrix_id);
+}
+
+int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
+ uint32_t passthr_mode)
{
struct adm_cmd_matrix_map_routings_v5 *route;
struct adm_session_map_node_v5 *node;
@@ -2618,32 +2763,9 @@
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;
+ route_set_opcode_matrix_id(&route, path, passthr_mode);
- 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;
@@ -2744,7 +2866,28 @@
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);
+ pr_debug("%s: ec_ref_rx:%d\n", __func__, this_adm.ec_ref_rx);
+}
+
+void adm_num_ec_ref_rx_chans(int num_chans)
+{
+ this_adm.num_ec_ref_rx_chans = num_chans;
+ pr_debug("%s: num_ec_ref_rx_chans:%d\n",
+ __func__, this_adm.num_ec_ref_rx_chans);
+}
+
+void adm_ec_ref_rx_bit_width(int bit_width)
+{
+ this_adm.ec_ref_rx_bit_width = bit_width;
+ pr_debug("%s: ec_ref_rx_bit_width:%d\n",
+ __func__, this_adm.ec_ref_rx_bit_width);
+}
+
+void adm_ec_ref_rx_sampling_rate(int sampling_rate)
+{
+ this_adm.ec_ref_rx_sampling_rate = sampling_rate;
+ pr_debug("%s: ec_ref_rx_sampling_rate:%d\n",
+ __func__, this_adm.ec_ref_rx_sampling_rate);
}
int adm_close(int port_id, int perf_mode, int copp_idx)
@@ -3491,6 +3634,172 @@
return rc;
}
+int adm_set_mic_gain(int port_id, int copp_idx, int volume)
+{
+ struct adm_set_mic_gain_params mic_gain_params;
+ 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_set_mic_gain_params);
+
+ mic_gain_params.params.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mic_gain_params.params.hdr.pkt_size = sz;
+ mic_gain_params.params.hdr.src_svc = APR_SVC_ADM;
+ mic_gain_params.params.hdr.src_domain = APR_DOMAIN_APPS;
+ mic_gain_params.params.hdr.src_port = port_id;
+ mic_gain_params.params.hdr.dest_svc = APR_SVC_ADM;
+ mic_gain_params.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ mic_gain_params.params.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ mic_gain_params.params.hdr.token = port_idx << 16 | copp_idx;
+ mic_gain_params.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ mic_gain_params.params.payload_addr_lsw = 0;
+ mic_gain_params.params.payload_addr_msw = 0;
+ mic_gain_params.params.mem_map_handle = 0;
+ mic_gain_params.params.payload_size =
+ sizeof(struct adm_param_data_v5) +
+ sizeof(struct admx_mic_gain);
+ mic_gain_params.data.module_id = ADM_MODULE_IDX_MIC_GAIN_CTRL;
+ mic_gain_params.data.param_id = ADM_PARAM_IDX_MIC_GAIN;
+ mic_gain_params.data.param_size =
+ sizeof(struct admx_mic_gain);
+ mic_gain_params.data.reserved = 0;
+ mic_gain_params.mic_gain_data.tx_mic_gain = volume;
+ mic_gain_params.mic_gain_data.reserved = 0;
+ pr_debug("%s: Mic Gain set to %d at port_id 0x%x\n",
+ __func__, volume, port_id);
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)&mic_gain_params);
+ 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: Mic Gain 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_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx,
+ int primary_mic_ch)
+{
+ struct adm_set_sec_primary_ch_params sec_primary_ch_params;
+ int rc = 0;
+ int sz, port_idx;
+
+ pr_debug("%s port_id 0x%x, copp_idx 0x%x, primary_mic_ch %d\n",
+ __func__, port_id, copp_idx, primary_mic_ch);
+ 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_idx 0x%x\n", __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ sz = sizeof(struct adm_set_sec_primary_ch_params);
+
+ sec_primary_ch_params.params.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ sec_primary_ch_params.params.hdr.pkt_size = sz;
+ sec_primary_ch_params.params.hdr.src_svc = APR_SVC_ADM;
+ sec_primary_ch_params.params.hdr.src_domain = APR_DOMAIN_APPS;
+ sec_primary_ch_params.params.hdr.src_port = port_id;
+ sec_primary_ch_params.params.hdr.dest_svc = APR_SVC_ADM;
+ sec_primary_ch_params.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ sec_primary_ch_params.params.hdr.dest_port =
+ atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+ sec_primary_ch_params.params.hdr.token = port_idx << 16 | copp_idx;
+ sec_primary_ch_params.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ sec_primary_ch_params.params.payload_addr_lsw = 0;
+ sec_primary_ch_params.params.payload_addr_msw = 0;
+ sec_primary_ch_params.params.mem_map_handle = 0;
+ sec_primary_ch_params.params.payload_size =
+ sizeof(struct adm_param_data_v5) +
+ sizeof(struct admx_sec_primary_mic_ch);
+ sec_primary_ch_params.data.module_id =
+ AUDPROC_MODULE_ID_VOICE_TX_SECNS;
+ sec_primary_ch_params.data.param_id =
+ AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH;
+ sec_primary_ch_params.data.param_size =
+ sizeof(struct admx_sec_primary_mic_ch);
+ sec_primary_ch_params.data.reserved = 0;
+ sec_primary_ch_params.sec_primary_mic_ch_data.version = 0;
+ sec_primary_ch_params.sec_primary_mic_ch_data.reserved = 0;
+ sec_primary_ch_params.sec_primary_mic_ch_data.sec_primary_mic_ch =
+ primary_mic_ch;
+ sec_primary_ch_params.sec_primary_mic_ch_data.reserved1 = 0;
+
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+ rc = apr_send_pkt(this_adm.apr, (uint32_t *)&sec_primary_ch_params);
+ 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: Mic 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;
@@ -4365,6 +4674,9 @@
this_adm.apr = NULL;
this_adm.ec_ref_rx = -1;
+ this_adm.num_ec_ref_rx_chans = 0;
+ this_adm.ec_ref_rx_bit_width = 0;
+ this_adm.ec_ref_rx_sampling_rate = 0;
atomic_set(&this_adm.matrix_map_stat, 0);
init_waitqueue_head(&this_adm.matrix_map_wait);
atomic_set(&this_adm.adm_stat, 0);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index b0249f4..af91731 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -36,6 +36,7 @@
AFE_FB_SPKR_PROT_CAL,
AFE_HW_DELAY_CAL,
AFE_SIDETONE_CAL,
+ AFE_SIDETONE_IIR_CAL,
AFE_TOPOLOGY_CAL,
AFE_CUST_TOPOLOGY_CAL,
AFE_FB_SPKR_PROT_TH_VI_CAL,
@@ -144,7 +145,7 @@
int topology;
int port_index = afe_get_port_index(port_id);
- if ((port_index < 0) || (port_index > AFE_MAX_PORTS)) {
+ if ((port_index < 0) || (port_index >= AFE_MAX_PORTS)) {
pr_err("%s: Invalid port index %d\n", __func__, port_index);
topology = -EINVAL;
goto done;
@@ -726,7 +727,7 @@
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
result = -EINVAL;
@@ -870,7 +871,7 @@
goto fail_cmd;
}
index = q6audio_get_port_index(port);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
ret = -EINVAL;
@@ -951,7 +952,7 @@
goto fail_cmd;
}
index = q6audio_get_port_index(src_port);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
ret = -EINVAL;
@@ -1197,7 +1198,7 @@
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
ret = -EINVAL;
@@ -1319,7 +1320,7 @@
u32 topology_id = 0;
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS - 1) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -1677,7 +1678,7 @@
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) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -1731,7 +1732,7 @@
}
index = q6audio_get_port_index(tx_port);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -1816,7 +1817,7 @@
}
index = q6audio_get_port_index(tx_port);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2039,7 +2040,7 @@
return ret;
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2125,7 +2126,7 @@
return ret;
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2199,7 +2200,7 @@
pr_debug("%s: enter\n", __func__);
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2270,7 +2271,7 @@
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) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2345,7 +2346,7 @@
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) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2424,7 +2425,7 @@
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) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2504,7 +2505,7 @@
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) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2626,7 +2627,7 @@
goto exit;
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ 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;
@@ -2820,7 +2821,7 @@
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) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -2934,6 +2935,20 @@
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_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:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
case HDMI_RX:
@@ -3311,6 +3326,34 @@
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_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:
pr_err("%s: port 0x%x\n", __func__, port_id);
return -EINVAL;
@@ -3335,7 +3378,7 @@
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) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -3503,7 +3546,7 @@
}
index = q6audio_get_port_index(rx_port);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -3569,7 +3612,7 @@
goto fail_cmd;
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -3672,7 +3715,7 @@
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -3715,7 +3758,7 @@
return -EINVAL;
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -3876,7 +3919,7 @@
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -4162,7 +4205,7 @@
rtac_set_afe_handle(this_afe.apr);
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -4426,7 +4469,7 @@
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -4766,7 +4809,7 @@
goto fail_cmd;
}
index = q6audio_get_port_index(this_afe.dtmf_gen_rx_portid);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
ret = -EINVAL;
@@ -4795,58 +4838,249 @@
return ret;
}
-int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
+static int afe_sidetone_iir(u16 tx_port_id)
{
- struct afe_loopback_cfg_v1 cmd_sidetone;
- int ret = 0;
+ struct afe_loopback_iir_cfg_v2 iir_sidetone;
+ int ret;
int index = 0;
+ uint16_t size = 0;
+ int cal_index = AFE_SIDETONE_IIR_CAL;
+ int iir_pregain = 0;
+ int iir_num_biquad_stages = 0;
+ int iir_enable;
+ struct cal_block_data *cal_block;
+ int mid;
- 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;
+ memset(&iir_sidetone, 0, sizeof(iir_sidetone));
+ index = q6audio_get_port_index(tx_port_id);
+ iir_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ iir_sidetone.hdr.pkt_size = sizeof(iir_sidetone);
+ iir_sidetone.hdr.src_port = 0;
+ iir_sidetone.hdr.dest_port = 0;
+ iir_sidetone.hdr.token = index;
+ iir_sidetone.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ iir_sidetone.param.port_id = tx_port_id;
+ iir_sidetone.param.payload_address_lsw = 0x00;
+ iir_sidetone.param.payload_address_msw = 0x00;
+ iir_sidetone.param.mem_map_handle = 0x00;
+
+ if (this_afe.cal_data[cal_index] == NULL) {
+ pr_err("%s: cal data is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
}
- 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;
+ 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__);
+ mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+ ret = -EINVAL;
+ goto done;
}
+ iir_pregain = ((struct audio_cal_info_sidetone_iir *)
+ cal_block->cal_info)->pregain;
+ iir_enable = ((struct audio_cal_info_sidetone_iir *)
+ cal_block->cal_info)->iir_enable;
+ iir_num_biquad_stages = ((struct audio_cal_info_sidetone_iir *)
+ cal_block->cal_info)->num_biquad_stages;
+ mid = ((struct audio_cal_info_sidetone_iir *)
+ cal_block->cal_info)->mid;
+
+ /*
+ * calculate the actual size of payload based on no of stages
+ * enabled in calibration
+ */
+ size = (MAX_SIDETONE_IIR_DATA_SIZE / MAX_NO_IIR_FILTER_STAGE) *
+ iir_num_biquad_stages;
+ /*
+ * For an odd number of stages, 2 bytes of padding are
+ * required at the end of the payload.
+ */
+ if (iir_num_biquad_stages % 2) {
+ pr_debug("%s: adding 2 to size:%d\n", __func__, size);
+ size = size + 2;
+ }
+ memcpy(&iir_sidetone.st_iir_filter_config_data.iir_config,
+ &((struct audio_cal_info_sidetone_iir *)
+ cal_block->cal_info)->iir_config,
+ sizeof(iir_sidetone.st_iir_filter_config_data.iir_config));
+ mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+
+ /*
+ * Calculate the payload size for setparams command
+ */
+ iir_sidetone.param.payload_size = (sizeof(iir_sidetone) -
+ sizeof(struct apr_hdr) -
+ sizeof(struct afe_port_cmd_set_param_v2) -
+ (MAX_SIDETONE_IIR_DATA_SIZE - size));
+
+ pr_debug("%s: payload size :%d\n", __func__,
+ iir_sidetone.param.payload_size);
+
+ /*
+ * Set IIR enable params
+ */
+ iir_sidetone.st_iir_enable_pdata.module_id = mid;
+ iir_sidetone.st_iir_enable_pdata.param_id =
+ AFE_PARAM_ID_ENABLE;
+ iir_sidetone.st_iir_enable_pdata.param_size =
+ sizeof(iir_sidetone.st_iir_mode_enable_data);
+ iir_sidetone.st_iir_mode_enable_data.enable = iir_enable;
+
+ /*
+ * Set IIR filter config params
+ */
+ iir_sidetone.st_iir_filter_config_pdata.module_id = mid;
+ iir_sidetone.st_iir_filter_config_pdata.param_id =
+ AFE_PARAM_ID_SIDETONE_IIR_FILTER_CONFIG;
+ iir_sidetone.st_iir_filter_config_pdata.param_size =
+ sizeof(iir_sidetone.st_iir_filter_config_data.num_biquad_stages)
+ +
+ sizeof(iir_sidetone.st_iir_filter_config_data.pregain) + size;
+ iir_sidetone.st_iir_filter_config_pdata.reserved = 0;
+ iir_sidetone.st_iir_filter_config_data.num_biquad_stages =
+ iir_num_biquad_stages;
+ iir_sidetone.st_iir_filter_config_data.pregain = iir_pregain;
+ pr_debug("%s: tx(0x%x)mid(0x%x)iir_en(%d)stg(%d)gain(0x%x)size(%d)\n",
+ __func__, tx_port_id, mid,
+ iir_sidetone.st_iir_mode_enable_data.enable,
+ iir_sidetone.st_iir_filter_config_data.num_biquad_stages,
+ iir_sidetone.st_iir_filter_config_data.pregain,
+ iir_sidetone.st_iir_filter_config_pdata.param_size);
+ ret = afe_apr_send_pkt(&iir_sidetone, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE sidetone failed for tx_port(0x%x)\n",
+ __func__, tx_port_id);
+
+done:
+ return ret;
+
+}
+
+static int afe_sidetone(u16 tx_port_id, u16 rx_port_id, bool enable)
+{
+ struct afe_st_loopback_cfg_v1 cmd_sidetone;
+ int ret;
+ int index;
+ int cal_index = AFE_SIDETONE_CAL;
+ int sidetone_gain;
+ int sidetone_enable;
+ struct cal_block_data *cal_block;
+ int mid = 0;
+
+ memset(&cmd_sidetone, 0, sizeof(cmd_sidetone));
+ if (this_afe.cal_data[cal_index] == NULL) {
+ pr_err("%s: cal data is NULL\n", __func__);
+ ret = -EINVAL;
+ 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__);
+ mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+ ret = -EINVAL;
+ goto done;
+ }
+ sidetone_gain = ((struct audio_cal_info_sidetone *)
+ cal_block->cal_info)->gain;
+ sidetone_enable = ((struct audio_cal_info_sidetone *)
+ cal_block->cal_info)->enable;
+ mid = ((struct audio_cal_info_sidetone *)
+ cal_block->cal_info)->mid;
+ mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+
+ index = q6audio_get_port_index(tx_port_id);
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.token = index;
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.gain_pdata.module_id = AFE_MODULE_LOOPBACK;
+ cmd_sidetone.gain_pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+ /*
+ * size of actual payload only
+ */
+ cmd_sidetone.gain_pdata.param_size = sizeof(
+ struct afe_loopback_sidetone_gain);
+ cmd_sidetone.gain_data.rx_port_id = rx_port_id;
+ cmd_sidetone.gain_data.gain = sidetone_gain;
- cmd_sidetone.loopback_cfg_minor_version =
+ cmd_sidetone.cfg_pdata.module_id = AFE_MODULE_LOOPBACK;
+ cmd_sidetone.cfg_pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+ /*
+ * size of actual payload only
+ */
+ cmd_sidetone.cfg_pdata.param_size = sizeof(struct loopback_cfg_data);
+ cmd_sidetone.cfg_data.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;
+ cmd_sidetone.cfg_data.dst_port_id = rx_port_id;
+ cmd_sidetone.cfg_data.routing_mode = LB_MODE_SIDETONE;
+ cmd_sidetone.cfg_data.enable = ((enable == 1) ? sidetone_enable : 0);
+
+ pr_debug("%s rx(0x%x) tx(0x%x) enable(%d) mid(0x%x) gain(%d) sidetone_enable(%d)\n",
+ __func__, rx_port_id, tx_port_id,
+ enable, mid, sidetone_gain, sidetone_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);
+ pr_err("%s: AFE sidetone send failed for tx_port:%d rx_port:%d ret:%d\n",
+ __func__, tx_port_id, rx_port_id, ret);
+done:
+ return ret;
+}
+
+int afe_sidetone_enable(u16 tx_port_id, u16 rx_port_id, bool enable)
+{
+ int ret;
+ int index;
+
+ 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);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (q6audio_validate_port(rx_port_id) < 0) {
+ pr_err("%s: Invalid port 0x%x\n",
+ __func__, rx_port_id);
+ ret = -EINVAL;
+ goto done;
+ }
+ index = q6audio_get_port_index(tx_port_id);
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: AFE port index[%d] invalid!\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (q6audio_validate_port(tx_port_id) < 0) {
+ pr_err("%s: Invalid port 0x%x\n",
+ __func__, tx_port_id);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (enable) {
+ ret = afe_sidetone_iir(tx_port_id);
+ if (ret)
+ goto done;
+ }
+
+ ret = afe_sidetone(tx_port_id, rx_port_id, enable);
+
+done:
return ret;
}
@@ -4979,6 +5213,20 @@
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_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:
+ 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 = 0;
break;
@@ -5099,7 +5347,7 @@
port_id = q6audio_convert_virtual_to_portid(port_id);
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -5257,7 +5505,7 @@
return ret;
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -5423,7 +5671,7 @@
int ret = 0;
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -5456,7 +5704,7 @@
return ret;
}
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -5537,7 +5785,7 @@
int ret = 0;
index = q6audio_get_port_index(port_id);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
@@ -5817,7 +6065,7 @@
goto fail_cmd;
}
index = q6audio_get_port_index(port);
- if (index < 0 || index > AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
ret = -EINVAL;
@@ -5946,6 +6194,9 @@
case AFE_SIDETONE_CAL_TYPE:
ret = AFE_SIDETONE_CAL;
break;
+ case AFE_SIDETONE_IIR_CAL_TYPE:
+ ret = AFE_SIDETONE_IIR_CAL;
+ break;
case AFE_TOPOLOGY_CAL_TYPE:
ret = AFE_TOPOLOGY_CAL;
break;
@@ -6476,6 +6727,11 @@
afe_set_cal, NULL, NULL} },
{NULL, NULL, cal_utils_match_buf_num} },
+ {{AFE_SIDETONE_IIR_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} },
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 78f70be..ccb4038 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1703,6 +1703,7 @@
case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ:
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
+ case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
@@ -2431,13 +2432,14 @@
* @ac: Client session handle
* @format: encoder format
* @bits_per_sample: bit width of capture session
+ * @ts_mode: timestamp mode
*/
int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
- uint16_t bits_per_sample)
+ uint16_t bits_per_sample, bool ts_mode)
{
return __q6asm_open_read(ac, format, bits_per_sample,
PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
- true/*ts_mode*/);
+ ts_mode);
}
EXPORT_SYMBOL(q6asm_open_read_v4);
@@ -2651,6 +2653,9 @@
case FORMAT_DSD:
open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
break;
+ case FORMAT_APTX:
+ open.dec_fmt_id = ASM_MEDIA_FMT_APTX;
+ break;
default:
pr_err("%s: Invalid format 0x%x\n", __func__, format);
rc = -EINVAL;
@@ -2868,6 +2873,7 @@
break;
case FORMAT_DSD:
open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
+ break;
case FORMAT_G711_ALAW_FS:
open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS;
break;
@@ -2973,7 +2979,6 @@
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__);
@@ -2985,29 +2990,67 @@
}
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;
+ if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
+ struct asm_stream_cmd_open_transcode_loopback_t open;
- open.mode_flags = 0;
- open.src_endpointype = 0;
- open.sink_endpointype = 0;
- /* source endpoint : matrix */
- open.postprocopo_id = q6asm_get_asm_topology_cal();
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
- ac->app_type = q6asm_get_asm_app_type_cal();
- ac->topology = open.postprocopo_id;
- open.bits_per_sample = bits_per_sample;
- open.reserved = 0;
+ open.mode_flags = 0;
+ open.src_endpoint_type = 0;
+ open.sink_endpoint_type = 0;
+ open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+ open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+ /* source endpoint : matrix */
+ open.audproc_topo_id = q6asm_get_asm_topology_cal();
- 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;
+ ac->app_type = q6asm_get_asm_app_type_cal();
+ if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+ open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
+ else
+ open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
+ ac->topology = open.audproc_topo_id;
+ open.bits_per_sample = bits_per_sample;
+ open.reserved = 0;
+ pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
+ __func__, open.mode_flags, ac->session);
+
+ 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;
+ }
+ } else {/*if(ac->perf_mode == LEGACY_PCM_MODE)*/
+ struct asm_stream_cmd_open_loopback_v2 open;
+
+ 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;
+ pr_debug("%s: opening a loopback_v2 with mode_flags =[%d] session[%d]\n",
+ __func__, open.mode_flags, ac->session);
+
+ 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) {
@@ -5727,6 +5770,57 @@
}
EXPORT_SYMBOL(q6asm_media_format_block_dsd);
+int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac,
+ uint32_t srate, int stream_id)
+{
+ struct asm_aptx_dec_fmt_blk_v2 aptx_fmt;
+ int rc = 0;
+
+ if (!ac->session) {
+ pr_err("%s: ac session invalid\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ pr_debug("%s :session[%d] rate[%d] stream_id[%d]\n",
+ __func__, ac->session, srate, stream_id);
+
+ q6asm_stream_add_hdr(ac, &aptx_fmt.hdr, sizeof(aptx_fmt), TRUE,
+ stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ aptx_fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ aptx_fmt.fmtblk.fmt_blk_size = sizeof(aptx_fmt) - sizeof(aptx_fmt.hdr) -
+ sizeof(aptx_fmt.fmtblk);
+
+ aptx_fmt.sample_rate = srate;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &aptx_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;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id,
int param_value, int stream_id)
{
@@ -6746,6 +6840,69 @@
return __q6asm_set_volume(ac, volume, instance);
}
+int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac,
+ struct aptx_dec_bt_addr_cfg *cfg)
+{
+ struct aptx_dec_bt_dev_addr paylod;
+ int sz = 0;
+ int rc = 0;
+
+ pr_debug("%s: BT addr nap %d, uap %d, lap %d\n", __func__, cfg->nap,
+ cfg->uap, cfg->lap);
+
+ if (ac == NULL) {
+ pr_err("%s: AC 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 aptx_dec_bt_dev_addr);
+ q6asm_add_hdr_async(ac, &paylod.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ paylod.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ paylod.encdec.param_id = APTX_DECODER_BT_ADDRESS;
+ paylod.encdec.param_size = sz - sizeof(paylod.hdr)
+ - sizeof(paylod.encdec);
+ paylod.bt_addr_cfg.lap = cfg->lap;
+ paylod.bt_addr_cfg.uap = cfg->uap;
+ paylod.bt_addr_cfg.nap = cfg->nap;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &paylod);
+ if (rc < 0) {
+ pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+ __func__, paylod.encdec.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__,
+ paylod.encdec.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)),
+ paylod.encdec.param_id);
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ pr_debug("%s: set BT addr is success\n", __func__);
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
int q6asm_set_softpause(struct audio_client *ac,
struct asm_softpause_params *pause_param)
{
@@ -7187,7 +7344,7 @@
}
q6asm_stream_add_hdr_async(
- ac, &write.hdr, sizeof(write), FALSE, ac->stream_id);
+ ac, &write.hdr, sizeof(write), TRUE, ac->stream_id);
port = &ac->port[IN];
ab = &port->buf[port->dsp_buf];
@@ -7348,7 +7505,7 @@
0, /* Stream ID is NA */
port->dsp_buf,
0, /* Direction flag is NA */
- WAIT_CMD);
+ NO_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);
@@ -7427,7 +7584,7 @@
0, /* Stream ID is NA */
port->dsp_buf,
0, /* Direction flag is NA */
- WAIT_CMD);
+ NO_WAIT_CMD);
write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
write.buf_addr_lsw = lower_32_bits(ab->phys);
@@ -7875,7 +8032,7 @@
stream_id,
0, /* Buffer index is NA */
0, /* Direction flag is NA */
- WAIT_CMD);
+ NO_WAIT_CMD);
pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
__func__, hdr.token, stream_id, ac->session);
@@ -7939,7 +8096,7 @@
return -EINVAL;
}
pr_debug("%s: session[%d]\n", __func__, ac->session);
- q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), FALSE,
+ q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), TRUE,
stream_id);
/*
@@ -7953,7 +8110,7 @@
stream_id,
0, /* Buffer index is NA */
0, /* Direction flag is NA */
- WAIT_CMD);
+ NO_WAIT_CMD);
pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
__func__, silence.hdr.token, stream_id, ac->session);
@@ -8169,14 +8326,17 @@
int q6asm_get_asm_topology(int session_id)
{
- int topology;
+ int topology = -EINVAL;
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;
}
-
+ if (session[session_id] == NULL) {
+ pr_err("%s: session not created for session id = %d\n",
+ __func__, session_id);
+ goto done;
+ }
topology = session[session_id]->topology;
done:
return topology;
@@ -8184,14 +8344,17 @@
int q6asm_get_asm_app_type(int session_id)
{
- int app_type;
+ int app_type = -EINVAL;
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;
}
-
+ if (session[session_id] == NULL) {
+ pr_err("%s: session not created for session id = %d\n",
+ __func__, session_id);
+ goto done;
+ }
app_type = session[session_id]->app_type;
done:
return app_type;
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 847a815..d6ad97d 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -220,7 +220,6 @@
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;
@@ -275,9 +274,9 @@
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",
+ pr_info("%s: Set license opcode=0x%x, id =0x%x, size = %d\n",
__func__, cmd_setl->hdr.opcode,
- metainfo->nKey, cmd_setl->id, cmd_setl->size);
+ 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",
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index d761cf5..08ddde4 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -38,6 +38,8 @@
#define LSM_ALIGN_BOUNDARY 512
#define LSM_SAMPLE_RATE 16000
#define QLSM_PARAM_ID_MINOR_VERSION 1
+#define QLSM_PARAM_ID_MINOR_VERSION_2 2
+
static int lsm_afe_port;
enum {
@@ -706,29 +708,28 @@
return rc;
}
-static int q6lsm_send_params(struct lsm_client *client,
+static int q6lsm_send_param_opmode(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 lsm_cmd_set_params_opmode opmode_params;
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;
+ msg_hdr = &opmode_params.msg_hdr;
q6lsm_add_hdr(client, msg_hdr,
- sizeof(opmode_connectport), true);
+ sizeof(opmode_params), true);
msg_hdr->opcode = set_param_opcode;
- data_payload_size = sizeof(opmode_connectport) -
+ data_payload_size = sizeof(opmode_params) -
sizeof(*msg_hdr) -
- sizeof(opmode_connectport.params_hdr);
- q6lsm_set_param_hdr_info(&opmode_connectport.params_hdr,
+ sizeof(opmode_params.params_hdr);
+ q6lsm_set_param_hdr_info(&opmode_params.params_hdr,
data_payload_size, 0, 0, 0);
- connect_to_port = &opmode_connectport.connect_to_port;
- op_mode = &opmode_connectport.op_mode;
+ op_mode = &opmode_params.op_mode;
+
param_size = sizeof(struct lsm_param_op_mode) -
sizeof(op_mode->common);
@@ -740,18 +741,8 @@
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);
+ &opmode_params, true, NULL);
if (rc)
pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
__func__, msg_hdr->opcode, rc);
@@ -770,12 +761,241 @@
return lsm_afe_port;
}
+int q6lsm_set_port_connected(struct lsm_client *client)
+{
+ int rc;
+ struct lsm_cmd_set_connectport connectport;
+ struct lsm_module_param_ids connectport_ids;
+ struct apr_hdr *msg_hdr;
+ struct lsm_param_connect_to_port *connect_to_port;
+ u32 data_payload_size, param_size, set_param_opcode;
+
+ if (client->use_topology) {
+ set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+ connectport_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
+ connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+ } else {
+ set_param_opcode = LSM_SESSION_CMD_SET_PARAMS;
+ connectport_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+ }
+ client->connect_to_port = get_lsm_port();
+
+ msg_hdr = &connectport.msg_hdr;
+ q6lsm_add_hdr(client, msg_hdr,
+ sizeof(connectport), true);
+ msg_hdr->opcode = set_param_opcode;
+ data_payload_size = sizeof(connectport) -
+ sizeof(*msg_hdr) -
+ sizeof(connectport.params_hdr);
+ q6lsm_set_param_hdr_info(&connectport.params_hdr,
+ data_payload_size, 0, 0, 0);
+ connect_to_port = &connectport.connect_to_port;
+
+ 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,
+ &connectport, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, msg_hdr->opcode, rc);
+
+ return rc;
+}
+static int q6lsm_send_param_polling_enable(struct lsm_client *client,
+ bool poll_en,
+ struct lsm_module_param_ids *poll_enable_ids,
+ u32 set_param_opcode)
+{
+ int rc = 0;
+ struct lsm_cmd_poll_enable cmd;
+ struct apr_hdr *msg_hdr;
+ struct lsm_param_poll_enable *poll_enable;
+ u32 data_payload_size, param_size;
+
+ msg_hdr = &cmd.msg_hdr;
+ q6lsm_add_hdr(client, msg_hdr,
+ sizeof(struct lsm_cmd_poll_enable), true);
+ msg_hdr->opcode = set_param_opcode;
+ data_payload_size = sizeof(struct lsm_cmd_poll_enable) -
+ sizeof(struct apr_hdr) -
+ sizeof(struct lsm_set_params_hdr);
+ q6lsm_set_param_hdr_info(&cmd.params_hdr,
+ data_payload_size, 0, 0, 0);
+ poll_enable = &cmd.poll_enable;
+
+ param_size = (sizeof(struct lsm_param_poll_enable) -
+ sizeof(poll_enable->common));
+ q6lsm_set_param_common(&poll_enable->common,
+ poll_enable_ids, param_size,
+ set_param_opcode);
+ poll_enable->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+ poll_enable->polling_enable = (poll_en) ? 1 : 0;
+ pr_debug("%s: poll enable= %d", __func__, poll_enable->polling_enable);
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &cmd, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, msg_hdr->opcode, rc);
+
+ return rc;
+}
+
+int q6lsm_set_fwk_mode_cfg(struct lsm_client *client,
+ uint32_t event_mode)
+{
+ int rc = 0;
+ struct lsm_cmd_set_fwk_mode_cfg cmd;
+ struct lsm_module_param_ids fwk_mode_cfg_ids;
+ struct apr_hdr *msg_hdr;
+ struct lsm_param_fwk_mode_cfg *fwk_mode_cfg;
+ u32 data_payload_size, param_size, set_param_opcode;
+
+ if (client->use_topology) {
+ set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+ fwk_mode_cfg_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
+ fwk_mode_cfg_ids.param_id = LSM_PARAM_ID_FWK_MODE_CONFIG;
+ } else {
+ pr_debug("%s: Ignore sending event mode\n", __func__);
+ return rc;
+ }
+
+ msg_hdr = &cmd.msg_hdr;
+ q6lsm_add_hdr(client, msg_hdr,
+ sizeof(struct lsm_cmd_set_fwk_mode_cfg), true);
+ msg_hdr->opcode = set_param_opcode;
+ data_payload_size = sizeof(struct lsm_cmd_set_fwk_mode_cfg) -
+ sizeof(struct apr_hdr) -
+ sizeof(struct lsm_set_params_hdr);
+ q6lsm_set_param_hdr_info(&cmd.params_hdr,
+ data_payload_size, 0, 0, 0);
+ fwk_mode_cfg = &cmd.fwk_mode_cfg;
+
+ param_size = (sizeof(struct lsm_param_fwk_mode_cfg) -
+ sizeof(fwk_mode_cfg->common));
+ q6lsm_set_param_common(&fwk_mode_cfg->common,
+ &fwk_mode_cfg_ids, param_size,
+ set_param_opcode);
+
+ fwk_mode_cfg->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+ fwk_mode_cfg->mode = event_mode;
+ pr_debug("%s: mode = %d\n", __func__, fwk_mode_cfg->mode);
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &cmd, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, msg_hdr->opcode, rc);
+ return rc;
+}
+
+static int q6lsm_arrange_mch_map(struct lsm_param_media_fmt *media_fmt,
+ int channel_count)
+{
+ int rc = 0;
+
+ memset(media_fmt->channel_mapping, 0, LSM_MAX_NUM_CHANNELS);
+
+ switch (channel_count) {
+ case 1:
+ media_fmt->channel_mapping[0] = PCM_CHANNEL_FC;
+ break;
+ case 2:
+ media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
+ media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
+ break;
+ case 3:
+ media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
+ media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
+ media_fmt->channel_mapping[2] = PCM_CHANNEL_FC;
+ break;
+ case 4:
+ media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
+ media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
+ media_fmt->channel_mapping[2] = PCM_CHANNEL_LS;
+ media_fmt->channel_mapping[3] = PCM_CHANNEL_RS;
+ break;
+ default:
+ pr_err("%s: invalid num_chan %d\n", __func__, channel_count);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+int q6lsm_set_media_fmt_params(struct lsm_client *client)
+{
+ int rc = 0;
+ struct lsm_cmd_set_media_fmt cmd;
+ struct lsm_module_param_ids media_fmt_ids;
+ struct apr_hdr *msg_hdr;
+ struct lsm_param_media_fmt *media_fmt;
+ u32 data_payload_size, param_size, set_param_opcode;
+ struct lsm_hw_params param = client->hw_params;
+
+ if (client->use_topology) {
+ set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+ media_fmt_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
+ media_fmt_ids.param_id = LSM_PARAM_ID_MEDIA_FMT;
+ } else {
+ pr_debug("%s: Ignore sending media format\n", __func__);
+ goto err_ret;
+ }
+
+ msg_hdr = &cmd.msg_hdr;
+ q6lsm_add_hdr(client, msg_hdr,
+ sizeof(struct lsm_cmd_set_media_fmt), true);
+ msg_hdr->opcode = set_param_opcode;
+ data_payload_size = sizeof(struct lsm_cmd_set_media_fmt) -
+ sizeof(struct apr_hdr) -
+ sizeof(struct lsm_set_params_hdr);
+ q6lsm_set_param_hdr_info(&cmd.params_hdr,
+ data_payload_size, 0, 0, 0);
+ media_fmt = &cmd.media_fmt;
+
+ param_size = (sizeof(struct lsm_param_media_fmt) -
+ sizeof(media_fmt->common));
+ q6lsm_set_param_common(&media_fmt->common,
+ &media_fmt_ids, param_size,
+ set_param_opcode);
+
+ media_fmt->minor_version = QLSM_PARAM_ID_MINOR_VERSION_2;
+ media_fmt->sample_rate = param.sample_rate;
+ media_fmt->num_channels = param.num_chs;
+ media_fmt->bit_width = param.sample_size;
+
+ rc = q6lsm_arrange_mch_map(media_fmt, media_fmt->num_channels);
+ if (rc)
+ goto err_ret;
+
+ pr_debug("%s: sample rate= %d, channels %d bit width %d\n",
+ __func__, media_fmt->sample_rate, media_fmt->num_channels,
+ media_fmt->bit_width);
+
+ rc = q6lsm_apr_send_pkt(client, client->apr,
+ &cmd, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, msg_hdr->opcode, rc);
+err_ret:
+ return rc;
+}
+
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 opmode_ids;
struct lsm_module_param_ids conf_levels_ids;
if (!client->confidence_levels) {
@@ -799,16 +1019,12 @@
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);
+ rc = q6lsm_send_param_opmode(client, &opmode_ids,
+ LSM_SESSION_CMD_SET_PARAMS);
if (rc) {
pr_err("%s: Failed to set lsm config params %d\n",
__func__, rc);
@@ -1388,7 +1604,7 @@
int q6lsm_set_one_param(struct lsm_client *client,
struct lsm_params_info *p_info, void *data,
- enum LSM_PARAM_TYPE param_type)
+ uint32_t param_type)
{
int rc = 0, pkt_sz;
struct lsm_module_param_ids ids;
@@ -1407,7 +1623,6 @@
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;
@@ -1420,16 +1635,12 @@
}
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);
+ rc = q6lsm_send_param_opmode(client, &opmode_ids,
+ LSM_SESSION_CMD_SET_PARAMS_V2);
if (rc)
pr_err("%s: OPERATION_MODE failed, rc %d\n",
__func__, rc);
@@ -1457,6 +1668,20 @@
pr_err("%s: CONFIDENCE_LEVELS cmd failed, rc %d\n",
__func__, rc);
break;
+ case LSM_POLLING_ENABLE: {
+ struct snd_lsm_poll_enable *lsm_poll_enable =
+ (struct snd_lsm_poll_enable *) data;
+ ids.module_id = p_info->module_id;
+ ids.param_id = p_info->param_id;
+ rc = q6lsm_send_param_polling_enable(client,
+ lsm_poll_enable->poll_en, &ids,
+ LSM_SESSION_CMD_SET_PARAMS_V2);
+ if (rc)
+ pr_err("%s: POLLING ENABLE cmd failed, rc %d\n",
+ __func__, rc);
+ break;
+ }
+
case LSM_REG_SND_MODEL: {
struct lsm_cmd_set_params model_param;
u32 payload_size;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 33d2225..b829c65 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -3962,6 +3962,10 @@
{
int ret;
+ ret = voice_send_cvp_device_channels_cmd(v);
+ if (ret < 0)
+ goto done;
+
if (voice_get_cvd_int_version(common.cvd_version) >=
CVD_INT_VERSION_2_3) {
ret = voice_send_cvp_media_format_cmd(v, RX_PATH);
@@ -3974,8 +3978,6 @@
if (common.ec_ref_ext)
ret = voice_send_cvp_media_format_cmd(v, EC_REF_PATH);
- } else {
- ret = voice_send_cvp_device_channels_cmd(v);
}
done:
@@ -5820,6 +5822,48 @@
return ret;
}
+int voc_set_afe_sidetone(uint32_t session_id, bool sidetone_enable)
+{
+ struct voice_data *v = NULL;
+ int ret = -EINVAL;
+ struct voice_session_itr itr;
+ u16 rx_port, tx_port;
+
+ common.sidetone_enable = sidetone_enable;
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
+ ret = -EINVAL;
+ break;
+ }
+ mutex_lock(&v->lock);
+ if (v->voc_state != VOC_RUN) {
+ mutex_unlock(&v->lock);
+ continue;
+ }
+ rx_port = v->dev_rx.port_id;
+ tx_port = v->dev_tx.port_id;
+ ret = afe_sidetone_enable(tx_port, rx_port,
+ sidetone_enable);
+ if (!ret) {
+ mutex_unlock(&v->lock);
+ break;
+ }
+ mutex_unlock(&v->lock);
+ }
+ return ret;
+}
+
+bool voc_get_afe_sidetone(void)
+{
+ bool ret;
+
+ ret = common.sidetone_enable;
+ return ret;
+}
+
int voc_get_pp_enable(uint32_t session_id, uint32_t module_id)
{
struct voice_data *v = voice_get_session(session_id);
@@ -8530,6 +8574,9 @@
memset(&common.ec_media_fmt_info.channel_mapping, 0,
VSS_CHANNEL_MAPPING_SIZE);
+ /* Initialize AFE Sidetone Enable */
+ common.sidetone_enable = false;
+
/* Initialize MVS info. */
common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 73a78a5..74d80be 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1762,6 +1762,7 @@
struct vss_isoundfocus_rsp_get_sectors_t soundFocusResponse;
struct shared_mem_info source_tracking_sh_mem;
struct vss_isourcetrack_activity_data_t sourceTrackingResponse;
+ bool sidetone_enable;
};
struct voice_session_itr {
@@ -1894,4 +1895,6 @@
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);
+int voc_set_afe_sidetone(uint32_t session_id, bool sidetone_enable);
+bool voc_get_afe_sidetone(void);
#endif
diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/sdm660-common.c
similarity index 93%
rename from sound/soc/msm/msmfalcon-common.c
rename to sound/soc/msm/sdm660-common.c
index baf6a4f..e191683 100644
--- a/sound/soc/msm/msmfalcon-common.c
+++ b/sound/soc/msm/sdm660-common.c
@@ -16,14 +16,16 @@
#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 "sdm660-common.h"
+#include "sdm660-internal.h"
+#include "sdm660-external.h"
+#include "../codecs/sdm660_cdc/msm-analog-cdc.h"
#include "../codecs/wsa881x.h"
-#define DRV_NAME "msmfalcon-asoc-snd"
+#define DRV_NAME "sdm660-asoc-snd"
+
+#define MSM_INT_DIGITAL_CODEC "msm-dig-codec"
+#define PMIC_INT_ANALOG_CODEC "analog-codec"
#define DEV_NAME_STR_LEN 32
#define DEFAULT_MCLK_RATE 9600000
@@ -158,20 +160,18 @@
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;
+ u32 msm_is_ext_mclk;
};
-struct auxpcm_conf {
- struct mutex lock;
- u32 ref_cnt;
+static u32 mi2s_ebit_clk[MI2S_MAX] = {
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT,
+ Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT
};
struct msm_wsa881x_dev_info {
@@ -189,7 +189,7 @@
.detect_extn_cable = true,
.mono_stero_detection = false,
.swap_gnd_mic = NULL,
- .hs_ext_micbias = false,
+ .hs_ext_micbias = true,
.key_code[0] = KEY_MEDIA,
.key_code[1] = KEY_VOICECOMMAND,
.key_code[2] = KEY_VOLUMEUP,
@@ -338,9 +338,42 @@
}
};
-static struct mi2s_aux_pcm_common_conf mi2s_auxpcm_conf[PCM_I2S_SEL_MAX];
+static struct afe_clk_set mi2s_mclk[MI2S_MAX] = {
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_MCLK_3,
+ Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_MCLK_4,
+ Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_MCLK_1,
+ Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_MCLK_2,
+ Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ }
+};
+
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)
@@ -1636,6 +1669,17 @@
tdm_tx_ch_put),
};
+/**
+ * msm_common_snd_controls_size - to return controls size
+ *
+ * Return: returns size of common controls array
+ */
+int msm_common_snd_controls_size(void)
+{
+ return ARRAY_SIZE(msm_common_snd_controls);
+}
+EXPORT_SYMBOL(msm_common_snd_controls_size);
+
static inline int param_is_mask(int p)
{
return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -1887,46 +1931,14 @@
*/
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);
+ rtd->cpu_dai->name, rtd->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 (ret < 0)
- auxpcm_intf_conf[index].ref_cnt--;
-
- mutex_unlock(&auxpcm_intf_conf[index].lock);
-
-done:
- return ret;
+ return 0;
}
EXPORT_SYMBOL(msm_aux_pcm_snd_startup);
@@ -1938,36 +1950,12 @@
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);
@@ -2093,6 +2081,7 @@
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int port_id = msm_get_port_id(rtd->dai_link->be_id);
int index = cpu_dai->id;
unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
@@ -2115,6 +2104,11 @@
*/
mutex_lock(&mi2s_intf_conf[index].lock);
if (++mi2s_intf_conf[index].ref_cnt == 1) {
+ /* Check if msm needs to provide the clock to the interface */
+ if (!mi2s_intf_conf[index].msm_is_mi2s_master) {
+ mi2s_clk[index].clk_id = mi2s_ebit_clk[index];
+ fmt = SND_SOC_DAIFMT_CBM_CFM;
+ }
ret = msm_mi2s_set_sclk(substream, true);
if (ret < 0) {
dev_err(rtd->card->dev,
@@ -2122,21 +2116,6 @@
__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 (ret < 0) {
dev_err(rtd->card->dev,
@@ -2144,7 +2123,21 @@
__func__, index, ret);
goto clk_off;
}
+ if (mi2s_intf_conf[index].msm_is_ext_mclk) {
+ mi2s_mclk[index].enable = 1;
+ pr_debug("%s: Enabling mclk, clk_freq_in_hz = %u\n",
+ __func__, mi2s_mclk[index].clk_freq_in_hz);
+ ret = afe_set_lpass_clock_v2(port_id,
+ &mi2s_mclk[index]);
+ if (ret < 0) {
+ pr_err("%s: afe lpass mclk failed, err:%d\n",
+ __func__, ret);
+ goto clk_off;
+ }
+ }
}
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+ return 0;
clk_off:
if (ret < 0)
msm_mi2s_set_sclk(substream, false);
@@ -2166,6 +2159,7 @@
{
int ret;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int port_id = msm_get_port_id(rtd->dai_link->be_id);
int index = rtd->cpu_dai->id;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -2183,6 +2177,17 @@
__func__, index, ret);
mi2s_intf_conf[index].ref_cnt++;
}
+ if (mi2s_intf_conf[index].msm_is_ext_mclk) {
+ mi2s_mclk[index].enable = 0;
+ pr_debug("%s: Disabling mclk, clk_freq_in_hz = %u\n",
+ __func__, mi2s_mclk[index].clk_freq_in_hz);
+ ret = afe_set_lpass_clock_v2(port_id,
+ &mi2s_mclk[index]);
+ if (ret < 0) {
+ pr_err("%s: mclk disable failed for MCLK (%d); ret=%d\n",
+ __func__, index, ret);
+ }
+ }
}
mutex_unlock(&mi2s_intf_conf[index].lock);
}
@@ -2233,6 +2238,7 @@
}
static int msm_populate_dai_link_component_of_node(
+ struct msm_asoc_mach_data *pdata,
struct snd_soc_card *card)
{
int i, index, ret = 0;
@@ -2312,6 +2318,31 @@
dai_link[i].codec_of_node = phandle;
dai_link[i].codec_name = NULL;
}
+ if (pdata->snd_card_val == INT_SND_CARD) {
+ if ((dai_link[i].be_id ==
+ MSM_BACKEND_DAI_INT0_MI2S_RX) ||
+ (dai_link[i].be_id ==
+ MSM_BACKEND_DAI_INT1_MI2S_RX) ||
+ (dai_link[i].be_id ==
+ MSM_BACKEND_DAI_INT2_MI2S_TX) ||
+ (dai_link[i].be_id ==
+ MSM_BACKEND_DAI_INT3_MI2S_TX)) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-codec-names",
+ MSM_INT_DIGITAL_CODEC);
+ phandle = of_parse_phandle(cdev->of_node,
+ "asoc-codec",
+ index);
+ dai_link[i].codecs[DIG_CDC].of_node = phandle;
+ index = of_property_match_string(cdev->of_node,
+ "asoc-codec-names",
+ PMIC_INT_ANALOG_CODEC);
+ phandle = of_parse_phandle(cdev->of_node,
+ "asoc-codec",
+ index);
+ dai_link[i].codecs[ANA_CDC].of_node = phandle;
+ }
+ }
}
err:
return ret;
@@ -2570,44 +2601,19 @@
static void i2s_auxpcm_init(struct platform_device *pdev)
{
- struct resource *muxsel;
int count;
u32 mi2s_master_slave[MI2S_MAX];
+ u32 mi2s_ext_mclk[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);
+ "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__);
@@ -2617,25 +2623,26 @@
mi2s_master_slave[count];
}
}
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-mi2s-ext-mclk",
+ mi2s_ext_mclk, MI2S_MAX);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-ext-mclk in DT node\n",
+ __func__);
+ } else {
+ for (count = 0; count < MI2S_MAX; count++)
+ mi2s_intf_conf[count].msm_is_ext_mclk =
+ mi2s_ext_mclk[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",
+static const struct of_device_id sdm660_asoc_machine_of_match[] = {
+ { .compatible = "qcom,sdm660-asoc-snd",
.data = "internal_codec"},
- { .compatible = "qcom,msmfalcon-asoc-snd-tasha",
+ { .compatible = "qcom,sdm660-asoc-snd-tasha",
.data = "tasha_codec"},
- { .compatible = "qcom,msmfalcon-asoc-snd-tavil",
+ { .compatible = "qcom,sdm660-asoc-snd-tavil",
.data = "tavil_codec"},
{},
};
@@ -2654,7 +2661,7 @@
if (!pdata)
return -ENOMEM;
- match = of_match_node(msmfalcon_asoc_machine_of_match,
+ match = of_match_node(sdm660_asoc_machine_of_match,
pdev->dev.of_node);
if (!match)
goto err;
@@ -2691,13 +2698,14 @@
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;
- }
+ pdata->pdm_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,cdc-pdm-gpios", 0);
+ pdata->comp_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,cdc-comp-gpios", 0);
+ pdata->dmic_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,cdc-dmic-gpios", 0);
+ pdata->ext_spk_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,cdc-ext-spk-gpios", 0);
}
/*
@@ -2730,22 +2738,37 @@
if (ret)
goto err;
- ret = msm_populate_dai_link_component_of_node(card);
+ ret = msm_populate_dai_link_component_of_node(pdata, card);
if (ret) {
ret = -EPROBE_DEFER;
goto err;
}
- ret = msm_init_wsa_dev(pdev, card);
- if (ret)
- goto err;
+ if (!of_property_read_bool(pdev->dev.of_node, "qcom,wsa-disable")) {
+ ret = msm_init_wsa_dev(pdev, card);
+ if (ret)
+ goto err;
+ }
ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret) {
+ if (ret == -EPROBE_DEFER) {
+ if (codec_reg_done) {
+ /*
+ * return failure as EINVAL since other codec
+ * registered sound card successfully.
+ * This avoids any further probe calls.
+ */
+ ret = -EINVAL;
+ }
+ goto err;
+ } else 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(pdev);
+
return 0;
err:
if (pdata->us_euro_gpio > 0) {
@@ -2765,6 +2788,8 @@
gpio_free(pdata->hph_en0_gpio);
pdata->hph_en0_gpio = 0;
}
+ if (pdata->snd_card_val != INT_SND_CARD)
+ msm_ext_cdc_deinit(pdata);
devm_kfree(&pdev->dev, pdata);
return ret;
}
@@ -2776,29 +2801,30 @@
if (pdata->snd_card_val == INT_SND_CARD)
mutex_destroy(&pdata->cdc_int_mclk0_mutex);
+ else
+ msm_ext_cdc_deinit(pdata);
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 = {
+static struct platform_driver sdm660_asoc_machine_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
- .of_match_table = msmfalcon_asoc_machine_of_match,
+ .of_match_table = sdm660_asoc_machine_of_match,
},
.probe = msm_asoc_machine_probe,
.remove = msm_asoc_machine_remove,
};
-module_platform_driver(msmfalcon_asoc_machine_driver);
+module_platform_driver(sdm660_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);
+MODULE_DEVICE_TABLE(of, sdm660_asoc_machine_of_match);
diff --git a/sound/soc/msm/msmfalcon-common.h b/sound/soc/msm/sdm660-common.h
similarity index 78%
rename from sound/soc/msm/msmfalcon-common.h
rename to sound/soc/msm/sdm660-common.h
index 5f6b859..bca8cd7 100644
--- a/sound/soc/msm/msmfalcon-common.h
+++ b/sound/soc/msm/sdm660-common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -59,8 +59,15 @@
u32 channel;
};
+enum {
+ DIG_CDC,
+ ANA_CDC,
+ CODECS_MAX,
+};
+
extern const struct snd_kcontrol_new msm_common_snd_controls[];
-struct msmfalcon_codec {
+extern bool codec_reg_done;
+struct sdm660_codec {
void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
enum afe_config_type config_type);
};
@@ -71,6 +78,14 @@
EXT_SND_CARD_TAVIL,
};
+struct msm_snd_interrupt {
+ void __iomem *mpm_wakeup;
+ void __iomem *intr1_cfg_apps;
+ void __iomem *lpi_gpio_intr_cfg;
+ void __iomem *lpi_gpio_cfg;
+ void __iomem *lpi_gpio_inout;
+};
+
struct msm_asoc_mach_data {
int us_euro_gpio; /* used by gpio driver API */
int hph_en1_gpio;
@@ -78,11 +93,16 @@
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 device_node *pdm_gpio_p; /* used by pinctrl API */
+ struct device_node *comp_gpio_p; /* used by pinctrl API */
+ struct device_node *dmic_gpio_p; /* used by pinctrl API */
+ struct device_node *ext_spk_gpio_p; /* used by pinctrl API */
struct snd_soc_codec *codec;
- struct msmfalcon_codec msmfalcon_codec_fn;
+ struct sdm660_codec sdm660_codec_fn;
struct snd_info_entry *codec_root;
int spk_ext_pa_gpio;
int mclk_freq;
+ bool native_clk_set;
int lb_mode;
int snd_card_val;
u8 micbias1_cap_mode;
@@ -92,6 +112,7 @@
struct mutex cdc_int_mclk0_mutex;
struct delayed_work disable_int_mclk0_work;
struct afe_clk_set digital_cdc_core_clk;
+ struct msm_snd_interrupt msm_snd_intr_lpi;
};
int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -100,4 +121,5 @@
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);
+int msm_common_snd_controls_size(void);
#endif
diff --git a/sound/soc/msm/msmfalcon-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
similarity index 99%
rename from sound/soc/msm/msmfalcon-ext-dai-links.c
rename to sound/soc/msm/sdm660-ext-dai-links.c
index 6f066c5..dbd5ed5 100644
--- a/sound/soc/msm/msmfalcon-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,11 +19,11 @@
#include <sound/pcm_params.h>
#include "qdsp6v2/msm-pcm-routing-v2.h"
#include "../codecs/wcd9335.h"
-#include "msmfalcon-common.h"
-#include "msmfalcon-external.h"
+#include "sdm660-common.h"
+#include "sdm660-external.h"
#define DEV_NAME_STR_LEN 32
-#define __CHIPSET__ "MSMFALCON "
+#define __CHIPSET__ "SDM660 "
#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
#define WCN_CDC_SLIM_RX_CH_MAX 2
@@ -861,6 +861,7 @@
.stream_name = "Compress1",
.cpu_dai_name = "MultiMedia4",
.platform_name = "msm-compress-dsp",
+ .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_playback = 1,
@@ -1881,7 +1882,7 @@
if (strnstr(card->name, "tasha", strlen(card->name))) {
codec_ver = tasha_codec_ver();
if (codec_ver == WCD9326)
- card->name = "msmfalcon-tashalite-snd-card";
+ card->name = "sdm660-tashalite-snd-card";
len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
len2 = len1 + ARRAY_SIZE(msm_ext_tasha_fe_dai);
diff --git a/sound/soc/msm/msmfalcon-external.c b/sound/soc/msm/sdm660-external.c
similarity index 92%
rename from sound/soc/msm/msmfalcon-external.c
rename to sound/soc/msm/sdm660-external.c
index d7b002e..43f5e0c 100644
--- a/sound/soc/msm/msmfalcon-external.c
+++ b/sound/soc/msm/sdm660-external.c
@@ -21,25 +21,42 @@
#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 "sdm660-common.h"
+#include "sdm660-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 SDM660_SPK_ON 1
+#define SDM660_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 TLMM_CENTER_MPM_WAKEUP_INT_EN_0 0x03596000
+#define LPI_GPIO_22_WAKEUP_VAL 0x00000002
+
+#define TLMM_LPI_DIR_CONN_INTR1_CFG_APPS 0x0359D004
+#define LPI_GPIO_22_INTR1_CFG_VAL 0x01
+#define LPI_GPIO_22_INTR1_CFG_MASK 0x03
+
+#define TLMM_LPI_GPIO_INTR_CFG1 0x0359B004
+#define LPI_GPIO_INTR_CFG1_VAL 0x00000113
+
+#define TLMM_LPI_GPIO22_CFG 0x15078040
+#define LPI_GPIO22_CFG_VAL 0x0000009
+
+#define TLMM_LPI_GPIO22_INOUT 0x179D1318
+#define LPI_GPIO22_INOUT_VAL 0x0020000
+
#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;
+bool codec_reg_done;
struct msm_asoc_wcd93xx_codec {
void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
@@ -637,7 +654,7 @@
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) {
+ if (msm_ext_spk_control == SDM660_SPK_ON) {
snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
} else {
@@ -1193,12 +1210,37 @@
afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
}
+static void msm_snd_interrupt_config(struct msm_asoc_mach_data *pdata)
+{
+ int val;
+
+ val = ioread32(pdata->msm_snd_intr_lpi.mpm_wakeup);
+ val |= LPI_GPIO_22_WAKEUP_VAL;
+ iowrite32(val, pdata->msm_snd_intr_lpi.mpm_wakeup);
+
+ val = ioread32(pdata->msm_snd_intr_lpi.intr1_cfg_apps);
+ val &= ~(LPI_GPIO_22_INTR1_CFG_MASK);
+ val |= LPI_GPIO_22_INTR1_CFG_VAL;
+ iowrite32(val, pdata->msm_snd_intr_lpi.intr1_cfg_apps);
+
+ iowrite32(LPI_GPIO_INTR_CFG1_VAL,
+ pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg);
+ iowrite32(LPI_GPIO22_CFG_VAL,
+ pdata->msm_snd_intr_lpi.lpi_gpio_cfg);
+ val = ioread32(pdata->msm_snd_intr_lpi.lpi_gpio_inout);
+ val |= LPI_GPIO22_INOUT_VAL;
+ iowrite32(val, pdata->msm_snd_intr_lpi.lpi_gpio_inout);
+}
+
static int msm_adsp_power_up_config(struct snd_soc_codec *codec)
{
int ret = 0;
unsigned long timeout;
int adsp_ready = 0;
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata;
+ pdata = snd_soc_card_get_drvdata(card);
timeout = jiffies +
msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
@@ -1221,6 +1263,7 @@
ret = -ETIMEDOUT;
goto err_fail;
}
+ msm_snd_interrupt_config(pdata);
ret = msm_afe_set_config(codec);
if (ret)
@@ -1233,7 +1276,7 @@
return ret;
}
-static int msmfalcon_notifier_service_cb(struct notifier_block *this,
+static int sdm660_notifier_service_cb(struct notifier_block *this,
unsigned long opcode, void *ptr)
{
int ret;
@@ -1291,7 +1334,7 @@
}
static struct notifier_block service_nb = {
- .notifier_call = msmfalcon_notifier_service_cb,
+ .notifier_call = sdm660_notifier_service_cb,
.priority = -INT_MAX,
};
@@ -1469,6 +1512,17 @@
134, 135, 136, 137, 138, 139,
140, 141, 142, 143};
+ /* Tavil Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch_tavil[WCD934X_RX_MAX] = {144, 145, 146, 147, 148,
+ 149, 150, 151};
+ unsigned int tx_ch_tavil[WCD934X_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;
@@ -1481,6 +1535,14 @@
return ret;
}
+ ret = snd_soc_add_codec_controls(codec, msm_common_snd_controls,
+ msm_common_snd_controls_size());
+ if (ret < 0) {
+ pr_err("%s: add_common_snd_controls failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
ARRAY_SIZE(msm_dapm_widgets));
@@ -1521,14 +1583,11 @@
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");
@@ -1536,21 +1595,33 @@
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");
+ 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")) {
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch_tavil),
+ tx_ch_tavil, ARRAY_SIZE(rx_ch_tavil),
+ rx_ch_tavil);
+ } else {
+ 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;
@@ -1674,6 +1745,7 @@
}
}
+ codec_reg_done = true;
done:
return 0;
@@ -1687,11 +1759,13 @@
/**
* msm_ext_register_audio_notifier - register SSR notifier.
*/
-void msm_ext_register_audio_notifier(void)
+void msm_ext_register_audio_notifier(struct platform_device *pdev)
{
int ret;
- ret = audio_notifier_register("msmfalcon", AUDIO_NOTIFIER_ADSP_DOMAIN,
+ is_initial_boot = true;
+ spdev = pdev;
+ ret = audio_notifier_register("sdm660", AUDIO_NOTIFIER_ADSP_DOMAIN,
&service_nb);
if (ret < 0)
pr_err("%s: Audio notifier register failed ret = %d\n",
@@ -1729,10 +1803,8 @@
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))
@@ -1759,7 +1831,36 @@
ret);
ret = 0;
}
+ pdata->msm_snd_intr_lpi.mpm_wakeup =
+ ioremap(TLMM_CENTER_MPM_WAKEUP_INT_EN_0, 4);
+ pdata->msm_snd_intr_lpi.intr1_cfg_apps =
+ ioremap(TLMM_LPI_DIR_CONN_INTR1_CFG_APPS, 4);
+ pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg =
+ ioremap(TLMM_LPI_GPIO_INTR_CFG1, 4);
+ pdata->msm_snd_intr_lpi.lpi_gpio_cfg =
+ ioremap(TLMM_LPI_GPIO22_CFG, 4);
+ pdata->msm_snd_intr_lpi.lpi_gpio_inout =
+ ioremap(TLMM_LPI_GPIO22_INOUT, 4);
err:
return ret;
}
EXPORT_SYMBOL(msm_ext_cdc_init);
+
+/**
+ * msm_ext_cdc_deinit - external codec machine specific deinit.
+ */
+void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata)
+{
+ if (pdata->msm_snd_intr_lpi.mpm_wakeup)
+ iounmap(pdata->msm_snd_intr_lpi.mpm_wakeup);
+ if (pdata->msm_snd_intr_lpi.intr1_cfg_apps)
+ iounmap(pdata->msm_snd_intr_lpi.intr1_cfg_apps);
+ if (pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg)
+ iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg);
+ if (pdata->msm_snd_intr_lpi.lpi_gpio_cfg)
+ iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_cfg);
+ if (pdata->msm_snd_intr_lpi.lpi_gpio_inout)
+ iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_inout);
+
+}
+EXPORT_SYMBOL(msm_ext_cdc_deinit);
diff --git a/sound/soc/msm/msmfalcon-external.h b/sound/soc/msm/sdm660-external.h
similarity index 83%
rename from sound/soc/msm/msmfalcon-external.h
rename to sound/soc/msm/sdm660-external.h
index 654cb70..acf5735 100644
--- a/sound/soc/msm/msmfalcon-external.h
+++ b/sound/soc/msm/sdm660-external.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef __MSMFALCON_EXTERNAL
-#define __MSMFALCON_EXTERNAL
+#ifndef __SDM660_EXTERNAL
+#define __SDM660_EXTERNAL
int msm_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
@@ -33,7 +33,8 @@
#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);
+void msm_ext_register_audio_notifier(struct platform_device *pdev);
+void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata);
#else
inline int msm_ext_cdc_init(struct platform_device *pdev,
struct msm_asoc_mach_data *pdata,
@@ -43,7 +44,10 @@
return 0;
}
-inline void msm_ext_register_audio_notifier(void)
+inline void msm_ext_register_audio_notifier(struct platform_device *pdev)
+{
+}
+inline void msm_ext_cdc_deinit(void)
{
}
#endif
diff --git a/sound/soc/msm/msmfalcon-internal.c b/sound/soc/msm/sdm660-internal.c
similarity index 91%
rename from sound/soc/msm/msmfalcon-internal.c
rename to sound/soc/msm/sdm660-internal.c
index 50efd69..abf4007 100644
--- a/sound/soc/msm/msmfalcon-internal.c
+++ b/sound/soc/msm/sdm660-internal.c
@@ -13,13 +13,15 @@
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/mfd/msm-cdc-pinctrl.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"
+#include "sdm660-common.h"
+#include "../codecs/sdm660_cdc/msm-digital-cdc.h"
+#include "../codecs/sdm660_cdc/msm-analog-cdc.h"
+#include "../codecs/msm_sdw/msm_sdw.h"
-#define __CHIPSET__ "MSMFALCON "
+#define __CHIPSET__ "SDM660 "
#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
#define DEFAULT_MCLK_RATE 9600000
@@ -30,6 +32,9 @@
#define WCN_CDC_SLIM_RX_CH_MAX 2
#define WCN_CDC_SLIM_TX_CH_MAX 3
+#define WSA8810_NAME_1 "wsa881x.20170211"
+#define WSA8810_NAME_2 "wsa881x.20170212"
+
enum {
INT0_MI2S = 0,
INT1_MI2S,
@@ -176,6 +181,7 @@
static void msm_int_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
static struct wcd_mbhc_config *mbhc_cfg_ptr;
+static struct snd_info_entry *codec_root;
static int int_mi2s_get_bit_format_val(int bit_format)
{
@@ -443,22 +449,25 @@
SND_SOC_DAPM_MIC("Digital Mic4", msm_dmic_event),
};
-static int msm_config_hph_compander_gpio(bool enable)
+static int msm_config_hph_compander_gpio(bool enable,
+ 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 ret = 0;
pr_debug("%s: %s HPH Compander\n", __func__,
enable ? "Enable" : "Disable");
if (enable) {
- ret = msm_gpioset_activate(CLIENT_WCD, "comp_gpio");
+ ret = msm_cdc_pinctrl_select_active_state(pdata->comp_gpio_p);
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");
+ ret = msm_cdc_pinctrl_select_sleep_state(pdata->comp_gpio_p);
if (ret) {
pr_err("%s: gpio set cannot be de-activated %s\n",
__func__, "comp_gpio");
@@ -509,7 +518,8 @@
enable ? "Enable" : "Disable");
if (enable) {
- ret = msm_gpioset_activate(CLIENT_WCD, "ext_spk_gpio");
+ ret = msm_cdc_pinctrl_select_active_state(
+ pdata->ext_spk_gpio_p);
if (ret) {
pr_err("%s: gpio set cannot be de-activated %s\n",
__func__, "ext_spk_gpio");
@@ -518,7 +528,8 @@
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");
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ pdata->ext_spk_gpio_p);
if (ret) {
pr_err("%s: gpio set cannot be de-activated %s\n",
__func__, "ext_spk_gpio");
@@ -672,10 +683,13 @@
atomic_read(&pdata->int_mclk0_rsc_ref));
if (enable) {
if (int_mi2s_cfg[INT0_MI2S].sample_rate ==
- SAMPLING_RATE_44P1KHZ)
+ SAMPLING_RATE_44P1KHZ) {
clk_freq_in_hz = NATIVE_MCLK_RATE;
- else
+ pdata->native_clk_set = true;
+ } else {
clk_freq_in_hz = pdata->mclk_freq;
+ pdata->native_clk_set = false;
+ }
if (pdata->digital_cdc_core_clk.clk_freq_in_hz
!= clk_freq_in_hz)
@@ -687,6 +701,12 @@
mutex_lock(&pdata->cdc_int_mclk0_mutex);
if (atomic_read(&pdata->int_mclk0_enabled) == false ||
int_mclk0_freq_chg) {
+ if (atomic_read(&pdata->int_mclk0_enabled)) {
+ pdata->digital_cdc_core_clk.enable = 0;
+ afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ }
pdata->digital_cdc_core_clk.clk_freq_in_hz =
clk_freq_in_hz;
pdata->digital_cdc_core_clk.enable = 1;
@@ -744,7 +764,7 @@
ucontrol->value.integer.value[0]);
switch (ucontrol->value.integer.value[0]) {
case 1:
- ret = msm_gpioset_activate(CLIENT_WCD, "int_pdm");
+ ret = msm_cdc_pinctrl_select_active_state(pdata->pdm_gpio_p);
if (ret) {
pr_err("%s: failed to enable the pri gpios: %d\n",
__func__, ret);
@@ -761,8 +781,8 @@
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");
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ pdata->pdm_gpio_p);
if (ret)
pr_err("%s: failed to disable the pri gpios: %d\n",
__func__, ret);
@@ -772,12 +792,12 @@
}
mutex_unlock(&pdata->cdc_int_mclk0_mutex);
atomic_inc(&pdata->int_mclk0_rsc_ref);
- msm8x16_wcd_mclk_enable(codec, 1, true);
+ msm_anlg_cdc_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);
+ msm_anlg_cdc_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))) {
@@ -794,7 +814,7 @@
atomic_set(&pdata->int_mclk0_enabled, false);
}
mutex_unlock(&pdata->cdc_int_mclk0_mutex);
- ret = msm_gpioset_suspend(CLIENT_WCD, "int_pdm");
+ ret = msm_cdc_pinctrl_select_sleep_state(pdata->pdm_gpio_p);
if (ret)
pr_err("%s: failed to disable the pri gpios: %d\n",
__func__, ret);
@@ -871,15 +891,6 @@
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,
@@ -893,7 +904,7 @@
msm_bt_sample_rate_put),
};
-static const struct snd_kcontrol_new msm_swr_controls[] = {
+static const struct snd_kcontrol_new msm_sdw_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,
@@ -919,7 +930,7 @@
pr_debug("%s: event = %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- ret = msm_gpioset_activate(CLIENT_WCD, "dmic_gpio");
+ ret = msm_cdc_pinctrl_select_active_state(pdata->dmic_gpio_p);
if (ret < 0) {
pr_err("%s: gpio set cannot be activated %sd",
__func__, "dmic_gpio");
@@ -927,7 +938,7 @@
}
break;
case SND_SOC_DAPM_POST_PMD:
- ret = msm_gpioset_suspend(CLIENT_WCD, "dmic_gpio");
+ ret = msm_cdc_pinctrl_select_sleep_state(pdata->dmic_gpio_p);
if (ret < 0) {
pr_err("%s: gpio set cannot be de-activated %sd",
__func__, "dmic_gpio");
@@ -954,7 +965,7 @@
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");
+ ret = msm_cdc_pinctrl_select_sleep_state(pdata->pdm_gpio_p);
if (ret < 0) {
pr_err("%s: gpio set cannot be de-activated %sd",
__func__, "int_pdm");
@@ -963,7 +974,7 @@
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_anlg_cdc_mclk_enable(codec, 0, true);
msm_int_enable_dig_cdc_clk(codec, 0, true);
}
break;
@@ -1055,8 +1066,7 @@
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);
+ (int_mi2s_cfg[idx].sample_rate * 2 * bit_per_sample);
}
static int int_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
@@ -1098,7 +1108,7 @@
return ret;
}
-static int msm_swr_mi2s_snd_startup(struct snd_pcm_substream *substream)
+static int msm_sdw_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;
@@ -1113,13 +1123,6 @@
__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);
@@ -1127,7 +1130,7 @@
return ret;
}
-static void msm_swr_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+static void msm_sdw_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
{
int ret;
@@ -1144,9 +1147,11 @@
{
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;
+ struct snd_soc_codec *codec = rtd->codec_dais[ANA_CDC]->codec;
int ret = 0;
+ struct msm_asoc_mach_data *pdata = NULL;
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
@@ -1162,13 +1167,13 @@
return ret;
}
/* Enable the codec mclk config */
- ret = msm_gpioset_activate(CLIENT_WCD, "int_pdm");
+ ret = msm_cdc_pinctrl_select_active_state(pdata->pdm_gpio_p);
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);
+ msm_anlg_cdc_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);
@@ -1249,22 +1254,34 @@
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_codec *dig_cdc = rtd->codec_dais[DIG_CDC]->codec;
+ struct snd_soc_codec *ana_cdc = rtd->codec_dais[ANA_CDC]->codec;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(ana_cdc);
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_card *card;
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));
+ ret = snd_soc_add_codec_controls(ana_cdc, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (ret < 0) {
+ pr_err("%s: add_codec_controls failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = snd_soc_add_codec_controls(ana_cdc, msm_common_snd_controls,
+ msm_common_snd_controls_size());
+ if (ret < 0) {
+ pr_err("%s: add common snd controls failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets,
- ARRAY_SIZE(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");
@@ -1285,39 +1302,76 @@
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);
+ /*
+ * 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)) {
+ msm_sdw_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+ msm_sdw_set_spkr_gain_offset(rtd->codec,
+ RX_GAIN_OFFSET_M1P5_DB);
+ }
+ msm_anlg_cdc_spk_ext_pa_cb(enable_spk_ext_pa, ana_cdc);
+ msm_dig_cdc_hph_comp_cb(msm_config_hph_compander_gpio, dig_cdc);
mbhc_cfg_ptr->calibration = def_msm_int_wcd_mbhc_cal();
if (mbhc_cfg_ptr->calibration) {
- ret = msm8x16_wcd_hs_detect(codec, mbhc_cfg_ptr);
+ ret = msm_anlg_cdc_hs_detect(ana_cdc, mbhc_cfg_ptr);
if (ret) {
- pr_err("%s: msm8x16_wcd_hs_detect failed\n", __func__);
+ pr_err("%s: msm_anlg_cdc_hs_detect failed\n", __func__);
kfree(mbhc_cfg_ptr->calibration);
return ret;
}
}
+ card = rtd->card->snd_card;
+ if (!codec_root)
+ codec_root = snd_register_module_info(card->module, "codecs",
+ card->proc_root);
+ if (!codec_root) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ goto done;
+ }
+ pdata->codec_root = codec_root;
+ msm_dig_codec_info_create_codec_entry(codec_root, dig_cdc);
+ msm_anlg_codec_info_create_codec_entry(codec_root, ana_cdc);
+done:
return 0;
}
-static int msm_swr_audrx_init(struct snd_soc_pcm_runtime *rtd)
+static int msm_sdw_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 msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_card *card;
- snd_soc_add_codec_controls(codec, msm_swr_controls,
- ARRAY_SIZE(msm_swr_controls));
+ snd_soc_add_codec_controls(codec, msm_sdw_controls,
+ ARRAY_SIZE(msm_sdw_controls));
- snd_soc_dapm_ignore_suspend(dapm, "AIF1_SWR Playback");
- snd_soc_dapm_ignore_suspend(dapm, "VIfeed_SWR");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF1_SDW Playback");
+ snd_soc_dapm_ignore_suspend(dapm, "VIfeed_SDW");
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_ignore_suspend(dapm, "AIF1_SDW VI");
+ snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_SDW");
snd_soc_dapm_sync(dapm);
-
+ card = rtd->card->snd_card;
+ if (!codec_root)
+ codec_root = snd_register_module_info(card->module, "codecs",
+ card->proc_root);
+ if (!codec_root) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ goto done;
+ }
+ pdata->codec_root = codec_root;
+ msm_sdw_codec_info_create_codec_entry(codec_root, codec);
+done:
return 0;
}
@@ -1540,9 +1594,42 @@
.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,
+static struct snd_soc_ops msm_sdw_mi2s_be_ops = {
+ .startup = msm_sdw_mi2s_snd_startup,
+ .shutdown = msm_sdw_mi2s_snd_shutdown,
+};
+
+struct snd_soc_dai_link_component dlc_rx1[] = {
+ {
+ .of_node = NULL,
+ .dai_name = "msm_dig_cdc_dai_rx1",
+ },
+ {
+ .of_node = NULL,
+ .dai_name = "msm_anlg_cdc_i2s_rx1",
+ },
+};
+
+struct snd_soc_dai_link_component dlc_tx1[] = {
+ {
+ .of_node = NULL,
+ .dai_name = "msm_dig_cdc_dai_tx1",
+ },
+ {
+ .of_node = NULL,
+ .dai_name = "msm_anlg_cdc_i2s_tx1",
+ },
+};
+
+struct snd_soc_dai_link_component dlc_tx2[] = {
+ {
+ .of_node = NULL,
+ .dai_name = "msm_dig_cdc_dai_tx2",
+ },
+ {
+ .of_node = NULL,
+ .dai_name = "msm_anlg_cdc_i2s_tx2",
+ },
};
/* Digital audio interface glue - connects codec <---> CPU */
@@ -1675,6 +1762,7 @@
.stream_name = "Compress1",
.cpu_dai_name = "MultiMedia4",
.platform_name = "msm-compress-dsp",
+ .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_playback = 1,
@@ -1721,25 +1809,24 @@
.codec_name = "snd-soc-dummy",
},
{/* hw:x,11 */
- .name = "SLIMBUS_3 Hostless",
- .stream_name = "SLIMBUS_3 Hostless",
- .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .name = "INT3 MI2S_TX Hostless",
+ .stream_name = "INT3 MI2S_TX Hostless",
+ .cpu_dai_name = "INT3_MI2S_TX_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 */
+ .ignore_pmdown_time = 1,
.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",
+ .name = "SLIMBUS_7 Hostless",
+ .stream_name = "SLIMBUS_7 Hostless",
+ .cpu_dai_name = "SLIMBUS7_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.dpcm_capture = 1,
@@ -2114,21 +2201,6 @@
.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",
@@ -2145,7 +2217,7 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
- {/* hw:x,37 */
+ {/* hw:x,36 */
.name = "Secondary MI2S_RX Hostless",
.stream_name = "Secondary MI2S_RX Hostless",
.cpu_dai_name = "SEC_MI2S_RX_HOSTLESS",
@@ -2162,7 +2234,7 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
- {/* hw:x,38 */
+ {/* hw:x,37 */
.name = "Tertiary MI2S_RX Hostless",
.stream_name = "Tertiary MI2S_RX Hostless",
.cpu_dai_name = "TERT_MI2S_RX_HOSTLESS",
@@ -2179,7 +2251,7 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
- {/* hw:x,39 */
+ {/* hw:x,38 */
.name = "INT0 MI2S_RX Hostless",
.stream_name = "INT0 MI2S_RX Hostless",
.cpu_dai_name = "INT0_MI2S_RX_HOSTLESS",
@@ -2196,14 +2268,36 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+};
+
+
+static struct snd_soc_dai_link msm_int_wsa_dai[] = {
+ {/* hw:x,39 */
+ .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_sdw_codec",
+ .codec_dai_name = "msm_sdw_vifeedback",
+ .be_id = MSM_BACKEND_DAI_INT5_MI2S_TX,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_sdw_mi2s_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .ignore_pmdown_time = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_int_be_dai[] = {
/* 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",
+ .codecs = dlc_rx1,
+ .num_codecs = CODECS_MAX,
.no_pcm = 1,
.dpcm_playback = 1,
.async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
@@ -2215,18 +2309,19 @@
.ignore_suspend = 1,
},
{
- .name = LPASS_BE_INT4_MI2S_RX,
- .stream_name = "INT4 MI2S Playback",
- .cpu_dai_name = "msm-dai-q6-mi2s.11",
+ .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 = "msm_swr_codec",
- .codec_dai_name = "msm_swr_i2s_rx1",
+ .codecs = dlc_tx1,
+ .num_codecs = CODECS_MAX,
.no_pcm = 1,
- .dpcm_playback = 1,
- .be_id = MSM_BACKEND_DAI_INT4_MI2S_RX,
- .init = &msm_swr_audrx_init,
+ .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_swr_mi2s_be_ops,
+ .ops = &msm_int_mi2s_be_ops,
.ignore_suspend = 1,
},
{
@@ -2234,8 +2329,8 @@
.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",
+ .codecs = dlc_tx2,
+ .num_codecs = CODECS_MAX,
.no_pcm = 1,
.dpcm_capture = 1,
.async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
@@ -2246,22 +2341,6 @@
.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",
@@ -2785,15 +2864,36 @@
},
};
+static struct snd_soc_dai_link msm_wsa_be_dai_links[] = {
+ {
+ .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_sdw_codec",
+ .codec_dai_name = "msm_sdw_i2s_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_INT4_MI2S_RX,
+ .init = &msm_sdw_audrx_init,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_sdw_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
static struct snd_soc_dai_link msm_int_dai_links[
ARRAY_SIZE(msm_int_dai) +
+ARRAY_SIZE(msm_int_wsa_dai) +
+ARRAY_SIZE(msm_int_be_dai) +
ARRAY_SIZE(msm_mi2s_be_dai_links) +
ARRAY_SIZE(msm_auxpcm_be_dai_links)+
-ARRAY_SIZE(msm_wcn_be_dai_links)];
+ARRAY_SIZE(msm_wcn_be_dai_links) +
+ARRAY_SIZE(msm_wsa_be_dai_links)];
-static struct snd_soc_card msmfalcon_card = {
- /* snd_soc_card_msmfalcon */
- .name = "msmfalcon-snd-card",
+static struct snd_soc_card sdm660_card = {
+ /* snd_soc_card_sdm660 */
+ .name = "sdm660-snd-card",
.dai_link = msm_int_dai,
.num_links = ARRAY_SIZE(msm_int_dai),
};
@@ -2844,7 +2944,7 @@
static struct snd_soc_card *msm_int_populate_sndcard_dailinks(
struct device *dev)
{
- struct snd_soc_card *card = &msmfalcon_card;
+ struct snd_soc_card *card = &sdm660_card;
struct snd_soc_dai_link *dailink;
int len1;
@@ -2852,6 +2952,16 @@
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,wsa-disable")) {
+ memcpy(dailink + len1,
+ msm_int_wsa_dai,
+ sizeof(msm_int_wsa_dai));
+ len1 += ARRAY_SIZE(msm_int_wsa_dai);
+ }
+ memcpy(dailink + len1, msm_int_be_dai, sizeof(msm_int_be_dai));
+ len1 += ARRAY_SIZE(msm_int_be_dai);
+
if (of_property_read_bool(dev->of_node,
"qcom,mi2s-audio-intf")) {
memcpy(dailink + len1,
@@ -2874,6 +2984,12 @@
sizeof(msm_wcn_be_dai_links));
len1 += ARRAY_SIZE(msm_wcn_be_dai_links);
}
+ if (!of_property_read_bool(dev->of_node, "qcom,wsa-disable")) {
+ memcpy(dailink + len1,
+ msm_wsa_be_dai_links,
+ sizeof(msm_wsa_be_dai_links));
+ len1 += ARRAY_SIZE(msm_wsa_be_dai_links);
+ }
card->dai_link = dailink;
card->num_links = len1;
return card;
@@ -2913,8 +3029,7 @@
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_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 =
diff --git a/sound/soc/msm/msmfalcon-internal.h b/sound/soc/msm/sdm660-internal.h
similarity index 94%
rename from sound/soc/msm/msmfalcon-internal.h
rename to sound/soc/msm/sdm660-internal.h
index e5e3e7c..ccc62b8 100644
--- a/sound/soc/msm/msmfalcon-internal.h
+++ b/sound/soc/msm/sdm660-internal.h
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef __MSMFALCON_INTERNAL
-#define __MSMFALCON_INTERNAL
+#ifndef __SDM660_INTERNAL
+#define __SDM660_INTERNAL
#include <sound/soc.h>